321 lines
7.8 KiB
C
Raw Normal View History

2022-08-30 15:42:35 +08:00
#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;
}