809 lines
21 KiB
C
809 lines
21 KiB
C
#define INLINE_SORT
|
|
|
|
#include "allocate.h"
|
|
#include "colors.h"
|
|
#include "collect.h"
|
|
#include "compact.h"
|
|
#include "inline.h"
|
|
#include "print.h"
|
|
#include "report.h"
|
|
#include "trail.h"
|
|
#include "sort.c"
|
|
|
|
#include <inttypes.h>
|
|
|
|
static void
|
|
flush_watched_clauses_by_literal (kissat * solver, litpairs * hyper,
|
|
unsigned lit, bool compact, reference start)
|
|
{
|
|
assert (start != INVALID_REF);
|
|
|
|
const value *values = solver->values;
|
|
const assigned *all_assigned = solver->assigned;
|
|
|
|
const value lit_value = values[lit];
|
|
const assigned *lit_assigned = all_assigned + IDX (lit);
|
|
const value lit_fixed = (lit_value && !lit_assigned->level) ? lit_value : 0;
|
|
|
|
const unsigned mlit = kissat_map_literal (solver, lit, true);
|
|
|
|
watches *lit_watches = &WATCHES (lit);
|
|
watch *begin = BEGIN_WATCHES (*lit_watches), *q = begin;
|
|
const watch *end_of_watches = END_WATCHES (*lit_watches), *p = q;
|
|
|
|
while (p != end_of_watches)
|
|
{
|
|
watch head = *p++;
|
|
if (head.type.binary)
|
|
{
|
|
const unsigned other = head.binary.lit;
|
|
const unsigned other_idx = IDX (other);
|
|
const value other_value = values[other];
|
|
const value other_fixed =
|
|
(other_value && !all_assigned[other_idx].level) ? other_value : 0;
|
|
const unsigned mother = kissat_map_literal (solver, other, compact);
|
|
if (lit_fixed > 0 || other_fixed > 0 || mother == INVALID_LIT)
|
|
{
|
|
if (lit < other)
|
|
kissat_delete_binary (solver,
|
|
head.binary.redundant,
|
|
head.binary.hyper, lit, other);
|
|
}
|
|
else
|
|
{
|
|
assert (!lit_fixed);
|
|
assert (!other_fixed);
|
|
|
|
if (head.binary.hyper)
|
|
{
|
|
assert (head.binary.redundant);
|
|
assert (mlit != INVALID_LIT);
|
|
assert (mother != INVALID_LIT);
|
|
if (lit < other)
|
|
{
|
|
const litpair litpair = kissat_litpair (lit, other);
|
|
PUSH_STACK (*hyper, litpair);
|
|
LOGBINARY (lit, other, "saved SRC hyper");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
head.binary.lit = mother;
|
|
*q++ = head;
|
|
#ifdef LOGGING
|
|
if (lit < other)
|
|
{
|
|
LOGBINARY (lit, other, "SRC");
|
|
LOGBINARY (mlit, mother, "DST");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert (solver->watching);
|
|
const watch tail = *p++;
|
|
if (!lit_fixed)
|
|
{
|
|
const reference ref = tail.large.ref;
|
|
if (ref < start)
|
|
{
|
|
*q++ = head;
|
|
*q++ = tail;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
assert (!lit_fixed || q == begin);
|
|
SET_END_OF_WATCHES (*lit_watches, q);
|
|
LOG ("keeping %" SECTOR_FORMAT " watches[%u]", lit_watches->size, lit);
|
|
|
|
if (!compact)
|
|
return;
|
|
|
|
if (mlit == INVALID_LIT)
|
|
return;
|
|
|
|
watches *mlit_watches = &WATCHES (mlit);
|
|
if (lit_fixed)
|
|
assert (!mlit_watches->size);
|
|
else if (mlit < lit)
|
|
{
|
|
assert (mlit != INVALID_LIT);
|
|
assert (mlit < lit);
|
|
*mlit_watches = *lit_watches;
|
|
LOG ("copied watches[%u] = watches[%u] "
|
|
"(size %" SECTOR_FORMAT ")", mlit, lit, mlit_watches->size);
|
|
memset (lit_watches, 0, sizeof *lit_watches);
|
|
}
|
|
else
|
|
assert (mlit == lit);
|
|
}
|
|
|
|
static void
|
|
flush_hyper_binary_watches (kissat * solver, litpairs * hyper, bool compact)
|
|
{
|
|
assert (!solver->probing);
|
|
const litpair *end = END_STACK (*hyper);
|
|
const value *values = solver->values;
|
|
size_t flushed = 0;
|
|
for (const litpair * p = BEGIN_STACK (*hyper); p != end; p++)
|
|
{
|
|
const unsigned lit = p->lits[0];
|
|
const unsigned other = p->lits[1];
|
|
assert (lit < other);
|
|
|
|
const value lit_value = values[lit];
|
|
const value other_value = values[other];
|
|
|
|
assert (!lit_value || LEVEL (lit));
|
|
assert (!other_value || LEVEL (other));
|
|
|
|
if (((lit_value < 0 && other_value > 0) ||
|
|
((lit_value > 0 && other_value < 0))))
|
|
{
|
|
LOGBINARY (lit, other, "keeping potential reason hyper SRC");
|
|
const unsigned mlit = kissat_map_literal (solver, lit, compact);
|
|
const unsigned mother = kissat_map_literal (solver, other, compact);
|
|
LOGBINARY (mlit, mother, "keeping potential reason hyper DST");
|
|
kissat_watch_other (solver, true, true, mlit, mother);
|
|
kissat_watch_other (solver, true, true, mother, mlit);
|
|
}
|
|
else
|
|
{
|
|
LOGBINARY (lit, other, "flushing hyper SRC");
|
|
kissat_delete_binary (solver, true, true, lit, other);
|
|
flushed++;
|
|
}
|
|
}
|
|
if (flushed)
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"flushed %zu unused hyper binary clauses %.0f%%",
|
|
flushed, kissat_percent (flushed, SIZE_STACK (*hyper)));
|
|
(void) flushed;
|
|
}
|
|
|
|
static void
|
|
flush_all_watched_clauses (kissat * solver, bool compact, reference start)
|
|
{
|
|
assert (solver->watching);
|
|
LOG ("starting to flush watches at clause[%zu]", start);
|
|
litpairs hyper;
|
|
INIT_STACK (hyper);
|
|
for (all_variables (idx))
|
|
{
|
|
const unsigned lit = LIT (idx);
|
|
flush_watched_clauses_by_literal (solver, &hyper, lit, compact, start);
|
|
const unsigned not_lit = NOT (lit);
|
|
flush_watched_clauses_by_literal (solver, &hyper,
|
|
not_lit, compact, start);
|
|
}
|
|
LOG ("saved %zu hyper binary watches", SIZE_STACK (hyper));
|
|
flush_hyper_binary_watches (solver, &hyper, compact);
|
|
RELEASE_STACK (hyper);
|
|
}
|
|
|
|
static void
|
|
update_large_reason (kissat * solver, assigned * assigned, unsigned forced,
|
|
clause * dst)
|
|
{
|
|
assert (dst->reason);
|
|
assert (forced != INVALID_LIT);
|
|
reference dst_ref = kissat_reference_clause (solver, dst);
|
|
const unsigned forced_idx = IDX (forced);
|
|
struct assigned *a = assigned + forced_idx;
|
|
assert (!a->binary);
|
|
if (a->reason != dst_ref)
|
|
{
|
|
LOG ("reason reference %u of %s updated to %u",
|
|
a->reason, LOGLIT (forced), dst_ref);
|
|
a->reason = dst_ref;
|
|
}
|
|
dst->reason = false;
|
|
}
|
|
|
|
static unsigned
|
|
get_forced (const value * values, clause * dst)
|
|
{
|
|
assert (dst->reason);
|
|
unsigned forced = INVALID_LIT;
|
|
for (all_literals_in_clause (lit, dst))
|
|
{
|
|
const value value = values[lit];
|
|
if (value <= 0)
|
|
continue;
|
|
forced = lit;
|
|
break;
|
|
}
|
|
assert (forced != INVALID_LIT);
|
|
return forced;
|
|
}
|
|
|
|
static void
|
|
get_forced_and_update_large_reason (kissat * solver, assigned * assigned,
|
|
const value * values, clause * dst)
|
|
{
|
|
const unsigned forced = get_forced (values, dst);
|
|
update_large_reason (solver, assigned, forced, dst);
|
|
}
|
|
|
|
static void
|
|
update_first_reducible (kissat * solver, const clause * end,
|
|
clause * first_reducible)
|
|
{
|
|
if (first_reducible >= end)
|
|
{
|
|
LOG ("first reducible after end of arena");
|
|
solver->first_reducible = INVALID_REF;
|
|
}
|
|
else if (first_reducible)
|
|
{
|
|
LOGCLS (first_reducible, "updating first reducible clause to");
|
|
solver->first_reducible =
|
|
kissat_reference_clause (solver, first_reducible);
|
|
}
|
|
else
|
|
{
|
|
LOG ("first reducible clause becomes invalid");
|
|
solver->first_reducible = INVALID_REF;
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_last_irredundant (kissat * solver, const clause * end,
|
|
clause * last_irredundant)
|
|
{
|
|
if (!last_irredundant)
|
|
{
|
|
LOG ("no more large irredundant clauses left");
|
|
solver->last_irredundant = INVALID_REF;
|
|
}
|
|
else if (end <= last_irredundant)
|
|
{
|
|
LOG ("last irredundant clause after end of arena");
|
|
solver->last_irredundant = INVALID_REF;
|
|
}
|
|
else
|
|
{
|
|
LOGCLS (last_irredundant, "updating last irredundant clause to");
|
|
reference ref = kissat_reference_clause (solver, last_irredundant);
|
|
solver->last_irredundant = ref;
|
|
}
|
|
}
|
|
|
|
static void
|
|
move_redundant_clauses_to_the_end (kissat * solver, reference ref)
|
|
{
|
|
INC (moved);
|
|
assert (ref != INVALID_REF);
|
|
#ifndef NDEBUG
|
|
const size_t size = SIZE_STACK (solver->arena);
|
|
assert ((size_t) ref <= size);
|
|
#endif
|
|
clause *begin = (clause *) (BEGIN_STACK (solver->arena) + ref);
|
|
clause *end = (clause *) END_STACK (solver->arena);
|
|
size_t bytes_redundant = (char *) end - (char *) begin;
|
|
kissat_phase (solver, "move",
|
|
GET (moved),
|
|
"moving redundant clauses of %s to the end",
|
|
FORMAT_BYTES (bytes_redundant));
|
|
kissat_mark_reason_clauses (solver, ref);
|
|
clause *redundant = (clause *) kissat_malloc (solver, bytes_redundant);
|
|
|
|
clause *p = begin, *q = begin, *r = redundant;
|
|
|
|
const value *values = solver->values;
|
|
assigned *assigned = solver->assigned;
|
|
|
|
clause *last_irredundant = kissat_last_irredundant_clause (solver);
|
|
while (p != end)
|
|
{
|
|
assert (!p->shrunken);
|
|
size_t bytes = kissat_bytes_of_clause (p->size);
|
|
if (p->redundant)
|
|
{
|
|
memcpy (r, p, bytes);
|
|
r = (clause *) (bytes + (char *) r);
|
|
}
|
|
else
|
|
{
|
|
LOGCLS (p, "old DST");
|
|
memmove (q, p, bytes);
|
|
LOGCLS (q, "new DST");
|
|
last_irredundant = q;
|
|
if (q->reason)
|
|
get_forced_and_update_large_reason (solver, assigned, values, q);
|
|
q = (clause *) (bytes + (char *) q);
|
|
}
|
|
p = (clause *) (bytes + (char *) p);
|
|
}
|
|
r = redundant;
|
|
clause *first_reducible = 0;
|
|
while (q != end)
|
|
{
|
|
size_t bytes = kissat_bytes_of_clause (r->size);
|
|
memcpy (q, r, bytes);
|
|
LOGCLS (q, "new DST");
|
|
if (q->reason)
|
|
get_forced_and_update_large_reason (solver, assigned, values, q);
|
|
assert (q->redundant);
|
|
if (!first_reducible && !q->keep)
|
|
first_reducible = q;
|
|
r = (clause *) (bytes + (char *) r);
|
|
q = (clause *) (bytes + (char *) q);
|
|
}
|
|
assert ((char *) r <= (char *) redundant + bytes_redundant);
|
|
kissat_free (solver, redundant, bytes_redundant);
|
|
|
|
assert (!first_reducible || first_reducible < q);
|
|
|
|
update_first_reducible (solver, q, first_reducible);
|
|
update_last_irredundant (solver, q, last_irredundant);
|
|
}
|
|
|
|
static reference
|
|
sparse_sweep_garbage_clauses (kissat * solver, bool compact, reference start)
|
|
{
|
|
assert (solver->watching);
|
|
LOG ("sparse garbage collection starting at clause[%zu]", start);
|
|
#ifdef CHECKING_OR_PROVING
|
|
const bool checking_or_proving = kissat_checking_or_proving (solver);
|
|
#endif
|
|
assert (EMPTY_STACK (solver->added));
|
|
assert (EMPTY_STACK (solver->removed));
|
|
|
|
const value *values = solver->values;
|
|
assigned *assigned = solver->assigned;
|
|
|
|
size_t flushed_garbage_clauses = 0;
|
|
size_t flushed_satisfied_clauses = 0;
|
|
size_t flushed_literals = 0;
|
|
|
|
clause *begin = (clause *) BEGIN_STACK (solver->arena);
|
|
const clause *end = (clause *) END_STACK (solver->arena);
|
|
|
|
clause *first, *src, *dst;
|
|
if (start)
|
|
first = kissat_dereference_clause (solver, start);
|
|
else
|
|
first = begin;
|
|
src = dst = first;
|
|
|
|
clause *first_redundant = 0;
|
|
clause *first_reducible = 0;
|
|
clause *last_irredundant;
|
|
|
|
if (start)
|
|
last_irredundant = kissat_last_irredundant_clause (solver);
|
|
else
|
|
last_irredundant = 0;
|
|
|
|
size_t redundant_bytes = 0;
|
|
|
|
for (clause * next; src != end; src = next)
|
|
{
|
|
if (src->garbage)
|
|
{
|
|
next = kissat_delete_clause (solver, src);
|
|
flushed_garbage_clauses++;
|
|
if (last_irredundant == src)
|
|
{
|
|
if (first == begin)
|
|
last_irredundant = 0;
|
|
else
|
|
last_irredundant = first;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
assert (src->size > 1);
|
|
LOGCLS (src, "SRC");
|
|
next = kissat_next_clause (src);
|
|
#if !defined(NDEBUG) || defined(CHECKING_OR_PROVING)
|
|
const unsigned old_size = src->size;
|
|
#endif
|
|
assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned));
|
|
*(unsigned *) dst = *(unsigned *) src;
|
|
|
|
unsigned *q = dst->lits;
|
|
|
|
unsigned mfirst = INVALID_LIT;
|
|
unsigned msecond = INVALID_LIT;
|
|
unsigned forced = INVALID_LIT;
|
|
unsigned other = INVALID_LIT;
|
|
unsigned non_false = 0;
|
|
|
|
bool satisfied = false;
|
|
|
|
for (all_literals_in_clause (lit, src))
|
|
{
|
|
#ifdef CHECKING_OR_PROVING
|
|
if (checking_or_proving)
|
|
PUSH_STACK (solver->removed, lit);
|
|
#endif
|
|
if (satisfied)
|
|
continue;
|
|
|
|
const value tmp = values[lit];
|
|
const unsigned idx = IDX (lit);
|
|
const unsigned level = tmp ? assigned[idx].level : INVALID_LEVEL;
|
|
|
|
if (tmp < 0 && !level)
|
|
flushed_literals++;
|
|
else if (tmp > 0 && !level)
|
|
{
|
|
assert (!satisfied);
|
|
assert (!dst->reason);
|
|
LOG ("SRC satisfied by %s", LOGLIT (lit));
|
|
satisfied = true;
|
|
}
|
|
else
|
|
{
|
|
const unsigned mlit = kissat_map_literal (solver, lit, compact);
|
|
|
|
if (tmp > 0)
|
|
{
|
|
assert (level);
|
|
forced = non_false++ ? INVALID_LIT : lit;
|
|
}
|
|
else if (tmp < 0)
|
|
other = lit;
|
|
|
|
if (mfirst == INVALID_LIT)
|
|
mfirst = mlit;
|
|
else if (msecond == INVALID_LIT)
|
|
msecond = mlit;
|
|
|
|
*q++ = mlit;
|
|
|
|
#ifdef CHECKING_OR_PROVING
|
|
if (checking_or_proving)
|
|
PUSH_STACK (solver->added, lit);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (satisfied)
|
|
{
|
|
if (dst->redundant)
|
|
DEC (clauses_redundant);
|
|
else
|
|
DEC (clauses_irredundant);
|
|
if (dst->hyper)
|
|
DEC (hyper_ternaries);
|
|
|
|
flushed_satisfied_clauses++;
|
|
|
|
#ifdef CHECKING_OR_PROVING
|
|
if (checking_or_proving)
|
|
{
|
|
REMOVE_CHECKER_STACK (solver->removed);
|
|
DELETE_STACK_FROM_PROOF (solver->removed);
|
|
CLEAR_STACK (solver->added);
|
|
CLEAR_STACK (solver->removed);
|
|
}
|
|
#endif
|
|
if (last_irredundant == src)
|
|
{
|
|
if (first == begin)
|
|
last_irredundant = 0;
|
|
else
|
|
last_irredundant = first;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
const unsigned new_size = q - dst->lits;
|
|
assert (new_size <= old_size);
|
|
assert (1 < new_size);
|
|
|
|
if (new_size == 2)
|
|
{
|
|
assert (mfirst != INVALID_LIT);
|
|
assert (msecond != INVALID_LIT);
|
|
|
|
const bool redundant = dst->redundant;
|
|
LOGBINARY (mfirst, msecond, "DST");
|
|
kissat_watch_binary (solver, redundant, false, mfirst, msecond);
|
|
|
|
if (dst->hyper)
|
|
DEC (hyper_ternaries);
|
|
|
|
if (dst->reason)
|
|
{
|
|
assert (non_false == 1);
|
|
assert (other != INVALID_LIT);
|
|
assert (forced != INVALID_LIT);
|
|
|
|
const unsigned forced_idx = IDX (forced);
|
|
struct assigned *a = assigned + forced_idx;
|
|
assert (!a->binary);
|
|
|
|
LOGBINARY (mfirst, msecond,
|
|
"reason clause[%u] of %s updated to binary reason",
|
|
a->reason, LOGLIT (forced));
|
|
|
|
a->binary = true;
|
|
a->reason = other;
|
|
}
|
|
|
|
if (!redundant && last_irredundant == src)
|
|
{
|
|
if (first == begin)
|
|
last_irredundant = 0;
|
|
else
|
|
last_irredundant = first;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert (2 < new_size);
|
|
|
|
dst->size = new_size;
|
|
dst->shrunken = false;
|
|
dst->searched = 2;
|
|
|
|
LOGCLS (dst, "DST");
|
|
if (dst->reason)
|
|
update_large_reason (solver, assigned, forced, dst);
|
|
|
|
clause *next_dst = kissat_next_clause (dst);
|
|
|
|
if (dst->redundant)
|
|
{
|
|
if (!first_reducible && !dst->keep)
|
|
first_reducible = dst;
|
|
|
|
redundant_bytes += (char *) next_dst - (char *) dst;
|
|
if (!first_redundant)
|
|
first_redundant = dst;
|
|
}
|
|
else
|
|
last_irredundant = dst;
|
|
|
|
dst = next_dst;
|
|
}
|
|
|
|
#ifdef CHECKING_OR_PROVING
|
|
if (!checking_or_proving)
|
|
continue;
|
|
|
|
if (new_size != old_size)
|
|
{
|
|
assert (1 < new_size);
|
|
assert (new_size < old_size);
|
|
|
|
CHECK_AND_ADD_STACK (solver->added);
|
|
ADD_STACK_TO_PROOF (solver->added);
|
|
|
|
REMOVE_CHECKER_STACK (solver->removed);
|
|
DELETE_STACK_FROM_PROOF (solver->removed);
|
|
}
|
|
CLEAR_STACK (solver->added);
|
|
CLEAR_STACK (solver->removed);
|
|
#endif
|
|
}
|
|
|
|
update_first_reducible (solver, dst, first_reducible);
|
|
update_last_irredundant (solver, dst, last_irredundant);
|
|
|
|
if (first_redundant)
|
|
LOGCLS (first_redundant, "determined first redundant clause as");
|
|
|
|
#if !defined(QUIET) || !defined(NMETRICS)
|
|
size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst;
|
|
#endif
|
|
#ifndef QUIET
|
|
if (flushed_literals)
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"flushed %zu falsified literals in large clauses",
|
|
flushed_literals);
|
|
size_t flushed_clauses =
|
|
flushed_satisfied_clauses + flushed_garbage_clauses;
|
|
if (flushed_satisfied_clauses)
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"flushed %zu satisfied large clauses %.0f%%",
|
|
flushed_satisfied_clauses,
|
|
kissat_percent (flushed_satisfied_clauses,
|
|
flushed_clauses));
|
|
if (flushed_garbage_clauses)
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"flushed %zu large garbage clauses %.0f%%",
|
|
flushed_garbage_clauses,
|
|
kissat_percent (flushed_garbage_clauses, flushed_clauses));
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"collected %s in total", FORMAT_BYTES (bytes));
|
|
#endif
|
|
ADD (literals_flushed, flushed_literals);
|
|
#ifndef NMETRICS
|
|
ADD (allocated_collected, bytes);
|
|
#endif
|
|
|
|
reference res = INVALID_REF;
|
|
|
|
if (first_redundant &&
|
|
last_irredundant && first_redundant < last_irredundant)
|
|
{
|
|
#ifdef LOGGING
|
|
size_t move_bytes = (char *) dst - (char *) first_redundant;
|
|
LOG ("redundant bytes %s (%.0f%) out of %s moving bytes",
|
|
FORMAT_BYTES (redundant_bytes),
|
|
kissat_percent (redundant_bytes, move_bytes),
|
|
FORMAT_BYTES (move_bytes));
|
|
#endif
|
|
assert (first_redundant < dst);
|
|
res = kissat_reference_clause (solver, first_redundant);
|
|
assert (res != INVALID_REF);
|
|
}
|
|
|
|
SET_END_OF_STACK (solver->arena, (word *) dst);
|
|
kissat_shrink_arena (solver);
|
|
|
|
kissat_clear_clueue (solver, &solver->clueue);
|
|
|
|
#ifndef NMETRICS
|
|
if (solver->statistics.arena_garbage)
|
|
kissat_very_verbose (solver, "still %s garbage left in arena",
|
|
FORMAT_BYTES (solver->statistics.arena_garbage));
|
|
else
|
|
kissat_very_verbose (solver, "all garbage clauses in arena collected");
|
|
#endif
|
|
|
|
return res;
|
|
}
|
|
|
|
static void
|
|
rewatch_clauses (kissat * solver, reference start)
|
|
{
|
|
LOG ("rewatching clause[%zu] and following clauses", start);
|
|
assert (solver->watching);
|
|
|
|
const value *values = solver->values;
|
|
const assigned *assigned = solver->assigned;
|
|
watches *watches = solver->watches;
|
|
const word *arena = BEGIN_STACK (solver->arena);
|
|
|
|
clause *end = (clause *) END_STACK (solver->arena);
|
|
clause *c = (clause *) (BEGIN_STACK (solver->arena) + start);
|
|
assert (c <= end);
|
|
|
|
for (clause * next; c != end; c = next)
|
|
{
|
|
next = kissat_next_clause (c);
|
|
|
|
unsigned *lits = c->lits;
|
|
kissat_sort_literals (solver, values, assigned, c->size, lits);
|
|
c->searched = 2;
|
|
|
|
const reference ref = (word *) c - arena;
|
|
const unsigned l0 = lits[0];
|
|
const unsigned l1 = lits[1];
|
|
|
|
kissat_push_blocking_watch (solver, watches + l0, l1, ref);
|
|
kissat_push_blocking_watch (solver, watches + l1, l0, ref);
|
|
}
|
|
}
|
|
|
|
void
|
|
kissat_sparse_collect (kissat * solver, bool compact, reference start)
|
|
{
|
|
assert (solver->watching);
|
|
START (collect);
|
|
INC (garbage_collections);
|
|
INC (sparse_garbage_collections);
|
|
REPORT (1, 'G');
|
|
unsigned vars, mfixed;
|
|
if (compact)
|
|
vars = kissat_compact_literals (solver, &mfixed);
|
|
else
|
|
{
|
|
vars = solver->vars;
|
|
mfixed = INVALID_LIT;
|
|
}
|
|
flush_all_watched_clauses (solver, compact, start);
|
|
reference move = sparse_sweep_garbage_clauses (solver, compact, start);
|
|
if (compact)
|
|
kissat_finalize_compacting (solver, vars, mfixed);
|
|
if (move != INVALID_REF)
|
|
move_redundant_clauses_to_the_end (solver, move);
|
|
|
|
rewatch_clauses (solver, start);
|
|
REPORT (1, 'C');
|
|
kissat_check_statistics (solver);
|
|
STOP (collect);
|
|
}
|
|
|
|
static void
|
|
dense_sweep_garbage_clauses (kissat * solver)
|
|
{
|
|
assert (!solver->level);
|
|
assert (!solver->watching);
|
|
|
|
LOG ("dense garbage collection");
|
|
|
|
size_t flushed_garbage_clauses = 0;
|
|
|
|
clause *first_reducible = 0;
|
|
clause *last_irredundant = 0;
|
|
|
|
clause *begin = (clause *) BEGIN_STACK (solver->arena);
|
|
const clause *end = (clause *) END_STACK (solver->arena);
|
|
|
|
clause *src = begin;
|
|
clause *dst = src;
|
|
|
|
for (clause * next; src != end; src = next)
|
|
{
|
|
if (src->garbage)
|
|
{
|
|
next = kissat_delete_clause (solver, src);
|
|
flushed_garbage_clauses++;
|
|
continue;
|
|
}
|
|
assert (src->size > 1);
|
|
LOGCLS (src, "SRC");
|
|
next = kissat_next_clause (src);
|
|
assert (SIZE_OF_CLAUSE_HEADER == sizeof (unsigned));
|
|
*(unsigned *) dst = *(unsigned *) src;
|
|
dst->searched = src->searched;
|
|
dst->size = src->size;
|
|
dst->shrunken = false;
|
|
memmove (dst->lits, src->lits, src->size * sizeof (unsigned));
|
|
LOGCLS (dst, "DST");
|
|
if (!dst->redundant)
|
|
last_irredundant = dst;
|
|
else if (!first_reducible && !dst->keep)
|
|
first_reducible = dst;
|
|
dst = kissat_next_clause (dst);
|
|
}
|
|
|
|
update_first_reducible (solver, dst, first_reducible);
|
|
update_last_irredundant (solver, dst, last_irredundant);
|
|
|
|
#if !defined(QUIET) || !defined(NMETRICS)
|
|
size_t bytes = (char *) END_STACK (solver->arena) - (char *) dst;
|
|
#endif
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"flushed %zu large garbage clauses", flushed_garbage_clauses);
|
|
kissat_phase (solver, "collect",
|
|
GET (garbage_collections),
|
|
"collected %s in total", FORMAT_BYTES (bytes));
|
|
#ifndef NMETRICS
|
|
ADD (allocated_collected, bytes);
|
|
#endif
|
|
|
|
SET_END_OF_STACK (solver->arena, (word *) dst);
|
|
kissat_shrink_arena (solver);
|
|
|
|
kissat_clear_clueue (solver, &solver->clueue);
|
|
#ifndef NMETRICS
|
|
if (solver->statistics.arena_garbage)
|
|
kissat_very_verbose (solver, "still %s garbage left in arena",
|
|
FORMAT_BYTES (solver->statistics.arena_garbage));
|
|
else
|
|
kissat_very_verbose (solver, "all garbage clauses in arena collected");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
kissat_dense_collect (kissat * solver)
|
|
{
|
|
assert (!solver->watching);
|
|
assert (!solver->level);
|
|
START (collect);
|
|
INC (garbage_collections);
|
|
INC (dense_garbage_collections);
|
|
REPORT (1, 'G');
|
|
dense_sweep_garbage_clauses (solver);
|
|
REPORT (1, 'C');
|
|
STOP (collect);
|
|
}
|