#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; }