321 lines
7.8 KiB
C
321 lines
7.8 KiB
C
|
#include "allocate.h"
|
||
|
#include "backward.h"
|
||
|
#include "eliminate.h"
|
||
|
#include "inline.h"
|
||
|
#include "terminate.h"
|
||
|
|
||
|
static bool
|
||
|
backward_subsume_lits (kissat * solver, reference ignore,
|
||
|
unsigned size, unsigned *lits)
|
||
|
{
|
||
|
assert (size > 1);
|
||
|
|
||
|
unsigned min_lit = INVALID_LIT;
|
||
|
unsigned min_occs = UINT_MAX;
|
||
|
|
||
|
const unsigned *end_lits = lits + size;
|
||
|
|
||
|
for (const unsigned *p = lits; p != end_lits; p++)
|
||
|
{
|
||
|
const unsigned lit = *p;
|
||
|
assert (!VALUE (lit));
|
||
|
const unsigned occs = WATCHES (lit).size;
|
||
|
if (occs >= min_occs)
|
||
|
continue;
|
||
|
min_occs = occs;
|
||
|
min_lit = lit;
|
||
|
}
|
||
|
|
||
|
assert (min_lit != INVALID_LIT);
|
||
|
|
||
|
const unsigned occlim = solver->bounds.subsume.occurrences;
|
||
|
if (min_occs > occlim)
|
||
|
return true;
|
||
|
|
||
|
LOGTMP ("backward subsumption on %s with %zu occurrences in",
|
||
|
LOGLIT (min_lit), min_occs);
|
||
|
|
||
|
value *marks = solver->marks;
|
||
|
const value *values = solver->values;
|
||
|
const word *arena = BEGIN_STACK (solver->arena);
|
||
|
|
||
|
const unsigned clslim = solver->bounds.subsume.clause_size;
|
||
|
|
||
|
const unsigned match =
|
||
|
(size > 2 ? INVALID_LIT : (lits[0] ^ lits[1] ^ min_lit));
|
||
|
const unsigned not_match = (size > 2 ? INVALID_LIT : NOT (match));
|
||
|
|
||
|
watches *watches = &WATCHES (min_lit);
|
||
|
watch *begin_watches = BEGIN_WATCHES (*watches), *q = begin_watches;
|
||
|
const watch *end_watches = END_WATCHES (*watches), *p = q;
|
||
|
|
||
|
bool found = false;
|
||
|
bool marked = false;
|
||
|
bool unit = false;
|
||
|
|
||
|
assert (EMPTY_STACK (solver->delayed));
|
||
|
assert (!values[min_lit]);
|
||
|
|
||
|
bool terminated = false;
|
||
|
|
||
|
while (p != end_watches)
|
||
|
{
|
||
|
terminated = TERMINATED (4);
|
||
|
if (terminated)
|
||
|
break;
|
||
|
const watch watch = *q++ = *p++;
|
||
|
if (watch.type.binary)
|
||
|
{
|
||
|
assert (!watch.binary.redundant);
|
||
|
if (size > 2)
|
||
|
continue;
|
||
|
const unsigned other = watch.binary.lit;
|
||
|
if (other == not_match)
|
||
|
{
|
||
|
LOGBINARY (min_lit, match,
|
||
|
"backward hyper unary resolution"
|
||
|
"on %s first antecedent", LOGLIT (match));
|
||
|
LOGBINARY (min_lit, not_match,
|
||
|
"backward hyper unary resolution"
|
||
|
"on %s second antecedent", LOGLIT (not_match));
|
||
|
unit = true;
|
||
|
break;
|
||
|
}
|
||
|
if (other != match)
|
||
|
continue;
|
||
|
if (found)
|
||
|
{
|
||
|
LOGBINARY (min_lit, match, "duplicated");
|
||
|
INC (duplicated);
|
||
|
kissat_disconnect_binary (solver, other, min_lit);
|
||
|
kissat_delete_binary (solver, false, false, min_lit, other);
|
||
|
kissat_update_after_removing_variable (solver, IDX (other));
|
||
|
q--;
|
||
|
}
|
||
|
else
|
||
|
found = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const reference ref = watch.large.ref;
|
||
|
if (ref == ignore)
|
||
|
{
|
||
|
assert (size > 2);
|
||
|
found = true;
|
||
|
continue;
|
||
|
}
|
||
|
assert (ref < SIZE_STACK (solver->arena));
|
||
|
struct clause *c = (struct clause *) (arena + ref);
|
||
|
if (c->garbage)
|
||
|
continue;
|
||
|
if (c->size < size)
|
||
|
continue;
|
||
|
if (c->size > clslim)
|
||
|
continue;
|
||
|
INC (subsumption_checks);
|
||
|
if (!marked)
|
||
|
{
|
||
|
for (const unsigned *l = lits; l != end_lits; l++)
|
||
|
{
|
||
|
const unsigned lit = *l;
|
||
|
assert (!values[lit]);
|
||
|
marks[lit] |= 2;
|
||
|
}
|
||
|
marked = true;
|
||
|
}
|
||
|
unsigned limit = c->size - size;
|
||
|
unsigned needed = size;
|
||
|
unsigned remove = INVALID_LIT;
|
||
|
for (all_literals_in_clause (lit, c))
|
||
|
{
|
||
|
assert (needed);
|
||
|
const value value = values[lit];
|
||
|
if (value > 0)
|
||
|
{
|
||
|
LOGCLS (c, "satisfied by %s", LOGLIT (lit));
|
||
|
kissat_mark_clause_as_garbage (solver, c);
|
||
|
kissat_update_after_removing_clause (solver, c,
|
||
|
INVALID_LIT);
|
||
|
break;
|
||
|
}
|
||
|
if (value < 0)
|
||
|
{
|
||
|
if (!limit--)
|
||
|
break;
|
||
|
continue;
|
||
|
}
|
||
|
if (marks[lit] & 2)
|
||
|
{
|
||
|
assert (needed);
|
||
|
if (!--needed)
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const unsigned not_lit = NOT (lit);
|
||
|
if (marks[not_lit] & 2)
|
||
|
{
|
||
|
if (remove != INVALID_LIT)
|
||
|
break;
|
||
|
remove = lit;
|
||
|
if (!--needed)
|
||
|
break;
|
||
|
}
|
||
|
if (!limit--)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (c->garbage)
|
||
|
{
|
||
|
q--;
|
||
|
continue;
|
||
|
}
|
||
|
if (needed)
|
||
|
continue;
|
||
|
if (remove == INVALID_LIT)
|
||
|
{
|
||
|
LOGCLS (c, "backward subsumed");
|
||
|
INC (subsumed);
|
||
|
INC (backward_subsumed);
|
||
|
kissat_mark_clause_as_garbage (solver, c);
|
||
|
kissat_update_after_removing_clause (solver, c, INVALID_LIT);
|
||
|
q--;
|
||
|
continue;
|
||
|
}
|
||
|
bool satisfied = false;
|
||
|
unsigned old_size = 0;
|
||
|
unsigned other = INVALID_LIT;
|
||
|
for (all_literals_in_clause (lit, c))
|
||
|
{
|
||
|
const value value = values[lit];
|
||
|
if (value > 0)
|
||
|
{
|
||
|
LOGCLS (c, "satisfied by %s", LOGLIT (lit));
|
||
|
satisfied = true;
|
||
|
break;
|
||
|
}
|
||
|
else if (!value)
|
||
|
{
|
||
|
if (lit != min_lit && lit != remove)
|
||
|
other = lit;
|
||
|
old_size++;
|
||
|
}
|
||
|
}
|
||
|
if (satisfied)
|
||
|
{
|
||
|
kissat_mark_clause_as_garbage (solver, c);
|
||
|
kissat_update_after_removing_clause (solver, c, INVALID_LIT);
|
||
|
q--;
|
||
|
continue;
|
||
|
}
|
||
|
assert (old_size <= c->size);
|
||
|
|
||
|
INC (strengthened);
|
||
|
INC (backward_strengthened);
|
||
|
LOGCLS (c, "backward strengthening by removing %s in",
|
||
|
LOGLIT (remove));
|
||
|
assert (remove != min_lit);
|
||
|
if (old_size == 2)
|
||
|
{
|
||
|
LOGTMP ("backward large hyper unary resolution on %s"
|
||
|
"first antecedent", LOGLIT (NOT (remove)));
|
||
|
LOGCLS (c, "backward large hyper unary resolution on %s"
|
||
|
"second antecedent", LOGLIT (remove));
|
||
|
unit = true;
|
||
|
break;
|
||
|
}
|
||
|
SHRINK_CLAUSE_IN_PROOF (c, remove, INVALID_LIT);
|
||
|
CHECK_SHRINK_CLAUSE (c, remove, INVALID_LIT);
|
||
|
if (old_size > 3)
|
||
|
{
|
||
|
unsigned *lits = c->lits;
|
||
|
unsigned new_size = 0;
|
||
|
for (unsigned i = 0; i < c->size; i++)
|
||
|
{
|
||
|
unsigned lit = lits[i];
|
||
|
if (remove == lit)
|
||
|
continue;
|
||
|
const value value = values[lit];
|
||
|
if (value < 0)
|
||
|
continue;
|
||
|
assert (!value);
|
||
|
lits[new_size++] = lit;
|
||
|
kissat_mark_added_literal (solver, remove);
|
||
|
}
|
||
|
assert (new_size == old_size - 1);
|
||
|
assert (new_size > 2);
|
||
|
if (!c->shrunken)
|
||
|
{
|
||
|
c->shrunken = true;
|
||
|
lits[c->size - 1] = INVALID_LIT;
|
||
|
}
|
||
|
c->size = new_size;
|
||
|
c->searched = 2;
|
||
|
LOGCLS (c, "backward strengthened");
|
||
|
kissat_disconnect_reference (solver, remove, ref);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
assert (old_size == 3);
|
||
|
assert (other != INVALID_LIT);
|
||
|
assert (other != min_lit);
|
||
|
assert (other != remove);
|
||
|
PUSH_STACK (solver->delayed, other);
|
||
|
LOGCLS (c, "garbage");
|
||
|
assert (!c->garbage);
|
||
|
assert (!c->hyper);
|
||
|
const size_t bytes = kissat_actual_bytes_of_clause (c);
|
||
|
ADD (arena_garbage, bytes);
|
||
|
c->garbage = true;
|
||
|
q--;
|
||
|
}
|
||
|
kissat_mark_removed_literal (solver, remove);
|
||
|
kissat_update_after_removing_variable (solver, IDX (remove));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (p != end_watches)
|
||
|
*q++ = *p++;
|
||
|
|
||
|
SET_END_OF_WATCHES (*watches, q);
|
||
|
|
||
|
if (unit)
|
||
|
{
|
||
|
LOG ("backward strengthened unit clause %s", LOGLIT (min_lit));
|
||
|
kissat_assign_unit (solver, min_lit);
|
||
|
CHECK_AND_ADD_UNIT (min_lit);
|
||
|
ADD_UNIT_TO_PROOF (min_lit);
|
||
|
}
|
||
|
|
||
|
for (all_stack (unsigned, other, solver->delayed))
|
||
|
{
|
||
|
LOGBINARY (other, min_lit, "backward strengthened");
|
||
|
kissat_watch_other (solver, false, false, other, min_lit);
|
||
|
kissat_watch_other (solver, false, false, min_lit, other);
|
||
|
kissat_mark_added_literal (solver, other);
|
||
|
kissat_mark_added_literal (solver, min_lit);
|
||
|
}
|
||
|
CLEAR_STACK (solver->delayed);
|
||
|
|
||
|
if (marked)
|
||
|
for (const unsigned *l = lits; l != end_lits; l++)
|
||
|
marks[*l] &= ~2;
|
||
|
|
||
|
return !terminated;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
kissat_backward_subsume_temporary (kissat * solver, reference ignore)
|
||
|
{
|
||
|
assert (!solver->watching);
|
||
|
assert (GET_OPTION (backward));
|
||
|
START (backward);
|
||
|
unsigneds *clause = &solver->clause.lits;
|
||
|
const size_t size = SIZE_STACK (*clause);
|
||
|
assert (size), assert (size <= UINT_MAX);
|
||
|
unsigned *lits = BEGIN_STACK (*clause);
|
||
|
bool res = backward_subsume_lits (solver, ignore, size, lits);
|
||
|
STOP (backward);
|
||
|
return res;
|
||
|
}
|