2022-08-30 15:42:35 +08:00

172 lines
5.2 KiB
C

#include "deduce.h"
#include "inline.h"
#include "promote.h"
#include "strengthen.h"
static inline void
mark_clause_as_used (kissat * solver, clause * c)
{
if (!c->redundant)
return;
if (!c->hyper && c->keep)
return;
const unsigned used = c->used;
LOGCLS (c, "using");
c->used = 1;
if (c->hyper)
return;
const unsigned new_glue = kissat_recompute_glue (solver, c);
if (new_glue < c->glue)
kissat_promote_clause (solver, c, new_glue);
else if (used && c->glue <= (unsigned) GET_OPTION (tier2))
c->used = 2;
}
static inline bool
analyze_literal (kissat * solver,
assigned * all_assigned, frame * frames, unsigned lit)
{
assert (VALUE (lit) < 0);
const unsigned idx = IDX (lit);
assigned *a = all_assigned + idx;
const unsigned level = a->level;
if (!level)
return false;
solver->antecedent_size++;
if (a->analyzed)
return false;
LOG ("analyzing literal %s", LOGLIT (lit));
a->analyzed = ANALYZED;
PUSH_STACK (solver->analyzed, idx);
assert (level <= solver->level);
#if defined(LOGGING) || !defined(NDEBUG)
PUSH_STACK (solver->resolvent_lits, lit);
#endif
solver->resolvent_size++;
if (level == solver->level)
return true;
a->analyzed = REMOVABLE;
PUSH_STACK (solver->clause.lits, lit);
LOG ("learned literal %s", LOGLIT (lit));
frame *f = frames + level;
assert (f->used < 3);
if (f->used == 2 || f->used++)
return false;
LOG ("pulling in decision level %u", level);
PUSH_STACK (solver->levels, level);
return false;
}
clause *
kissat_deduce_first_uip_clause (kissat * solver, clause * conflict)
{
START (deduce);
assert (EMPTY_STACK (solver->analyzed));
assert (EMPTY_STACK (solver->levels));
assert (EMPTY_STACK (solver->clause.lits));
#if defined(LOGGING) || !defined(NDEBUG)
CLEAR_STACK (solver->resolvent_lits);
#endif
if (conflict->size > 2)
mark_clause_as_used (solver, conflict);
PUSH_STACK (solver->clause.lits, INVALID_LIT);
solver->antecedent_size = 0;
solver->resolvent_size = 0;
unsigned unresolved_on_current_level = 0, conflict_size = 0;
assigned *all_assigned = solver->assigned;
frame *frames = BEGIN_STACK (solver->frames);
for (all_literals_in_clause (lit, conflict))
{
assert (VALUE (lit) < 0);
if (LEVEL (lit))
conflict_size++;
if (analyze_literal (solver, all_assigned, frames, lit))
unresolved_on_current_level++;
}
assert (unresolved_on_current_level > 1);
LOG ("starting with %u unresolved literals on current decision level",
unresolved_on_current_level);
assert (solver->antecedent_size == solver->resolvent_size);
LOGRES2 ("initial");
const bool otfs = GET_OPTION (otfs);
const unsigned *t = END_STACK (solver->trail);
unsigned uip = INVALID_LIT, resolved = 0;
assigned *a = 0;
for (;;)
{
do
{
assert (t > BEGIN_STACK (solver->trail));
uip = *--t;
a = ASSIGNED (uip);
}
while (!a->analyzed || a->level != solver->level);
if (unresolved_on_current_level == 1)
break;
assert (a->reason != DECISION);
assert (a->level == solver->level);
solver->antecedent_size = 1;
resolved++;
if (a->binary)
{
const unsigned other = a->reason;
LOGBINARY (uip, other, "resolving %s reason", LOGLIT (uip));
if (analyze_literal (solver, all_assigned, frames, other))
unresolved_on_current_level++;
}
else
{
const reference ref = a->reason;
LOGREF (ref, "resolving %s reason", LOGLIT (uip));
clause *reason = kissat_dereference_clause (solver, ref);
for (all_literals_in_clause (lit, reason))
if (lit != uip &&
analyze_literal (solver, all_assigned, frames, lit))
unresolved_on_current_level++;
mark_clause_as_used (solver, reason);
}
assert (unresolved_on_current_level > 0);
unresolved_on_current_level--;
LOG ("after resolving %s there are %u literals left "
"on current decision level", LOGLIT (uip),
unresolved_on_current_level);
assert (solver->resolvent_size > 0);
solver->resolvent_size--;
#if defined(LOGGING) || !defined(NDEBUG)
LOG2 ("actual antecedent size %u", solver->antecedent_size);
REMOVE_STACK (unsigned, solver->resolvent_lits, NOT (uip));
assert (SIZE_STACK (solver->resolvent_lits) == solver->resolvent_size);
LOGRES2 ("new");
#endif
if (otfs &&
solver->antecedent_size > 2 &&
solver->resolvent_size < solver->antecedent_size)
{
assert (!a->binary);
assert (solver->antecedent_size && solver->resolvent_size + 1);
clause *reason = kissat_dereference_clause (solver, a->reason);
assert (!reason->garbage);
clause *res = kissat_on_the_fly_strengthen (solver, reason, uip);
if (resolved == 1 && solver->resolvent_size < conflict_size)
{
assert (!conflict->garbage);
assert (conflict_size > 2);
kissat_on_the_fly_subsume (solver, res, conflict);
}
STOP (deduce);
return res;
}
}
assert (uip != INVALID_LIT);
LOG ("first unique implication point %s (1st UIP)", LOGLIT (uip));
assert (PEEK_STACK (solver->clause.lits, 0) == INVALID_LIT);
POKE_STACK (solver->clause.lits, 0, NOT (uip));
assert (a);
a->analyzed = REMOVABLE;
LOGTMP ("deduced not yet minimized 1st UIP");
if (!solver->probing)
ADD (literals_deduced, SIZE_STACK (solver->clause.lits));
STOP (deduce);
return 0;
}