#include "internal.hpp"
namespace CaDiCaL {
static Clause external_reason_clause;
Internal::Internal ()
: mode (SEARCH), unsat (false), iterating (false),
localsearching (false), lookingahead (false), preprocessing (false),
protected_reasons (false), force_saved_phase (false),
searching_lucky_phases (false), stable (false), reported (false),
external_prop (false), did_external_prop (false),
external_prop_is_lazy (true), forced_backt_allowed (false),
private_steps (false), rephased (0), vsize (0), max_var (0),
clause_id (0), original_id (0), reserved_ids (0), conflict_id (0),
saved_decisions (0), concluded (false), lrat (false), frat (false),
level (0), vals (0), score_inc (1.0), scores (this), conflict (0),
ignore (0), external_reason (&external_reason_clause),
newest_clause (0), force_no_backtrack (false),
from_propagator (false), ext_clause_forgettable (false),
changed_val (0), notified (0), probe_reason (0), propagated (0),
propagated2 (0), propergated (0), best_assigned (0),
target_assigned (0), no_conflict_until (0), unsat_constraint (false),
marked_failed (true), sweep_incomplete (false),
randomized_deciding (false), citten (0), num_assigned (0), proof (0),
opts (this),
#ifndef QUIET
profiles (this), force_phase_messages (false),
#endif
arena (this), prefix ("c "), internal (this), external (0),
termination_forced (false), vars (this->max_var),
lits (this->max_var) {
control.push_back (Level (0, 0));
size_t bytes = Clause::bytes (2);
dummy_binary = (Clause *) new char[bytes];
memset (dummy_binary, 0, bytes);
dummy_binary->size = 2;
assert (max_used == (1 << USED_SIZE) - 1);
}
Internal::~Internal () {
#ifndef QUIET
#define PROFILE(NAME, LEVEL) \
if (PROFILE_ACTIVE (NAME)) \
STOP (NAME);
PROFILES
#undef PROFILE
#endif
delete[] (char *) dummy_binary;
for (const auto &c : clauses)
delete_clause (c);
if (proof)
delete proof;
for (auto &tracer : tracers)
delete tracer;
for (auto &filetracer : file_tracers)
delete filetracer;
for (auto &stattracer : stat_tracers)
delete stattracer;
if (vals) {
vals -= vsize;
delete[] vals;
}
}
static signed char *ignore_clang_analyze_memory_leak_warning;
void Internal::enlarge_vals (size_t new_vsize) {
signed char *new_vals;
const size_t bytes = 2u * new_vsize;
new_vals = new signed char[bytes]; memset (new_vals, 0, bytes);
ignore_clang_analyze_memory_leak_warning = new_vals;
new_vals += new_vsize;
if (vals) {
memcpy (new_vals - max_var, vals - max_var, 2u * max_var + 1u);
vals -= vsize;
delete[] vals;
} else
assert (!vsize);
vals = new_vals;
}
void Internal::enlarge (int new_max_var) {
size_t new_vsize = vsize ? 2 * vsize : 1 + (size_t) new_max_var;
while (new_vsize <= (size_t) new_max_var)
new_vsize *= 2;
LOG ("enlarge internal size from %zd to new size %zd", vsize, new_vsize);
if (lrat || frat)
enlarge_zero (unit_clauses_idx, 2 * new_vsize);
enlarge_only (wtab, 2 * new_vsize);
enlarge_only (vtab, new_vsize);
enlarge_zero (parents, new_vsize);
enlarge_only (links, new_vsize);
enlarge_zero (btab, new_vsize);
enlarge_zero (gtab, new_vsize);
enlarge_zero (stab, new_vsize);
enlarge_init (ptab, 2 * new_vsize, -1);
enlarge_only (ftab, new_vsize);
enlarge_vals (new_vsize);
vsize = new_vsize;
if (external)
enlarge_zero (relevanttab, new_vsize);
const signed char val = opts.phase ? 1 : -1;
enlarge_init (phases.saved, new_vsize, val);
enlarge_zero (phases.forced, new_vsize);
enlarge_zero (phases.target, new_vsize);
enlarge_zero (phases.best, new_vsize);
enlarge_zero (phases.prev, new_vsize);
enlarge_zero (marks, new_vsize);
}
void Internal::init_vars (int new_max_var) {
if (new_max_var <= max_var)
return;
LOG ("initializing %d internal variables from %d to %d",
new_max_var - max_var, max_var + 1, new_max_var);
if ((size_t) new_max_var >= vsize)
enlarge (new_max_var);
#ifndef NDEBUG
for (int64_t i = -new_max_var; i < -max_var; i++)
assert (!vals[i]);
for (unsigned i = max_var + 1; i <= (unsigned) new_max_var; i++)
assert (!vals[i]), assert (!btab[i]), assert (!gtab[i]);
for (uint64_t i = 2 * ((uint64_t) max_var + 1);
i <= 2 * (uint64_t) new_max_var + 1; i++)
assert (ptab[i] == -1);
#endif
assert (!btab[0]);
int old_max_var = max_var;
max_var = new_max_var;
init_queue (old_max_var, new_max_var);
init_scores (old_max_var, new_max_var);
int initialized = new_max_var - old_max_var;
stats.vars += initialized;
stats.unused += initialized;
stats.inactive += initialized;
LOG ("finished initializing %d internal variables", initialized);
}
void Internal::add_original_lit (int lit) {
assert (abs (lit) <= max_var);
if (lit) {
original.push_back (lit);
} else {
const int64_t id =
original_id < reserved_ids ? ++original_id : ++clause_id;
if (proof) {
assert (!original.size () || !external->eclause.empty ());
proof->add_external_original_clause (id, false, external->eclause);
}
if (internal->opts.check &&
(internal->opts.checkwitness || internal->opts.checkfailed)) {
bool forgettable = from_propagator && ext_clause_forgettable;
if (forgettable && opts.check) {
assert (!original.size () || !external->eclause.empty ());
external->forgettable_original[id] = {1};
for (auto const &elit : external->eclause)
external->forgettable_original[id].push_back (elit);
LOG (external->eclause,
"clause added to external forgettable map:");
}
}
add_new_original_clause (id);
original.clear ();
}
}
void Internal::finish_added_clause_with_id (int64_t id, bool restore) {
if (proof) {
assert (!original.size () || !external->eclause.empty ());
proof->add_external_original_clause (id, false, external->eclause,
restore);
}
add_new_original_clause (id);
original.clear ();
}
void Internal::reserve_ids (int number) {
LOG ("reserving %d ids", number);
assert (number >= 0);
assert (!clause_id && !reserved_ids && !original_id);
clause_id = reserved_ids = number;
if (proof)
proof->begin_proof (reserved_ids);
}
#ifdef PROFILE_MODE
bool Internal::propagate_wrapper () {
if (stable)
return propagate_stable ();
else
return propagate_unstable ();
}
void Internal::analyze_wrapper () {
if (stable)
analyze_stable ();
else
analyze_unstable ();
}
int Internal::decide_wrapper () {
if (stable)
return decide_stable ();
else
return decide_unstable ();
}
#endif
int Internal::cdcl_loop_with_inprocessing () {
int res = 0;
START (search);
if (stable) {
START (stable);
report ('[');
} else {
START (unstable);
report ('{');
}
while (!res) {
if (unsat)
res = 20;
else if (unsat_constraint)
res = 20;
else if (!propagate_wrapper ())
analyze_wrapper (); else if (iterating)
iterate (); else if (!external_propagate () || unsat) { if (unsat)
continue;
else
analyze ();
} else if (satisfied ()) { if (!external_check_solution () || unsat) {
if (unsat)
continue;
else
analyze ();
} else if (satisfied ())
res = 10;
} else if (search_limits_hit ())
break; else if (terminated_asynchronously ()) break;
else if (restarting ())
restart (); else if (rephasing ())
rephase (); else if (reducing ())
reduce (); else if (inprobing ())
inprobe (); else if (ineliminating ())
elim (); else if (compacting ())
compact (); else if (conditioning ())
condition (); else
res = decide (); }
if (stable) {
STOP (stable);
report (']');
} else {
STOP (unstable);
report ('}');
}
STOP (search);
return res;
}
int Internal::propagate_assumptions () {
if (proof)
proof->solve_query ();
if (opts.ilb) {
sort_and_reuse_assumptions ();
assert (opts.ilb == 2 || (size_t) level <= assumptions.size ());
stats.ilbtriggers++;
stats.ilbsuccess += (level > 0);
stats.levelsreused += level;
if (level) {
assert (control.size () > 1);
stats.literalsreused += num_assigned - control[1].trail;
}
}
init_search_limits ();
init_report_limits ();
int res = already_solved ();
int last_assumption_level = assumptions.size ();
if (constraint.size ())
last_assumption_level++;
if (!res) {
restore_clauses ();
while (!res) {
if (unsat)
res = 20;
else if (unsat_constraint)
res = 20;
else if (!propagate ()) {
analyze ();
} else if (!external_propagate () || unsat) { if (unsat)
continue;
else
analyze ();
} else if (satisfied ()) { if (!external_check_solution () || unsat) {
if (unsat)
continue;
else
analyze ();
} else if (satisfied ())
res = 10;
} else if (search_limits_hit ())
break; else if (terminated_asynchronously ()) break;
else {
if (level >= last_assumption_level)
break;
res = decide ();
}
}
}
if (unsat || unsat_constraint)
res = 20;
if (!res && satisfied ())
res = 10;
finalize (res);
reset_solving ();
report_solving (res);
return res;
}
void Internal::implied (std::vector<int> &entrailed) {
int last_assumption_level = assumptions.size ();
if (constraint.size ())
last_assumption_level++;
size_t trail_limit = trail.size ();
if (level > last_assumption_level)
trail_limit = control[last_assumption_level + 1].trail;
for (size_t i = 0; i < trail_limit; i++)
entrailed.push_back (trail[i]);
}
void Internal::init_report_limits () {
reported = false;
lim.report = 0;
lim.recompute_tier = 5000;
}
void Internal::init_preprocessing_limits () {
const bool incremental = lim.initialized;
if (incremental)
LOG ("reinitializing preprocessing limits incrementally");
else
LOG ("initializing preprocessing limits and increments");
const char *mode = 0;
if (incremental)
mode = "keeping";
else {
last.elim.marked = -1;
lim.elim = stats.conflicts + scale (opts.elimint);
mode = "initial";
}
(void) mode;
LOG ("%s elim limit %" PRId64 " after %" PRId64 " conflicts", mode,
lim.elim, lim.elim - stats.conflicts);
lim.elimbound = opts.elimboundmin;
LOG ("elimination bound %" PRId64 "", lim.elimbound);
if (!incremental) {
last.ternary.marked = -1;
lim.compact = stats.conflicts + opts.compactint;
LOG ("initial compact limit %" PRId64 " increment %" PRId64 "",
lim.compact, lim.compact - stats.conflicts);
}
if (incremental)
mode = "keeping";
else {
double delta = log10 (stats.added.irredundant + 10);
delta = delta * delta;
lim.inprobe = stats.conflicts + opts.inprobeint * delta;
mode = "initial";
}
(void) mode;
LOG ("%s probe limit %" PRId64 " after %" PRId64 " conflicts", mode,
lim.inprobe, lim.inprobe - stats.conflicts);
if (incremental)
mode = "keeping";
else {
lim.condition = stats.conflicts + opts.conditionint;
mode = "initial";
}
LOG ("%s condition limit %" PRId64 " increment %" PRId64, mode,
lim.condition, lim.condition - stats.conflicts);
if (inc.preprocessing <= 0) {
lim.preprocessing = 0;
LOG ("no preprocessing");
} else {
lim.preprocessing = inc.preprocessing;
LOG ("limiting to %" PRId64 " preprocessing rounds", lim.preprocessing);
}
}
void Internal::init_search_limits () {
const bool incremental = lim.initialized;
if (incremental)
LOG ("reinitializing search limits incrementally");
else
LOG ("initializing search limits and increments");
const char *mode = 0;
if (incremental)
mode = "keeping";
else {
last.reduce.conflicts = -1;
lim.reduce = stats.conflicts + opts.reduceinit;
mode = "initial";
}
(void) mode;
LOG ("%s reduce limit %" PRId64 " after %" PRId64 " conflicts", mode,
lim.reduce, lim.reduce - stats.conflicts);
if (incremental)
mode = "keeping";
else {
lim.flush = opts.flushint;
inc.flush = opts.flushint;
mode = "initial";
}
(void) mode;
LOG ("%s flush limit %" PRId64 " interval %" PRId64 "", mode, lim.flush,
inc.flush);
lim.rephase = stats.conflicts + opts.rephaseint;
lim.rephased[0] = lim.rephased[1] = 0;
last.stabilize.rephased = 0;
LOG ("new rephase limit %" PRId64 " after %" PRId64 " conflicts",
lim.rephase, lim.rephase - stats.conflicts);
lim.restart = stats.conflicts + opts.restartint;
LOG ("new restart limit %" PRId64 " increment %" PRId64 "", lim.restart,
lim.restart - stats.conflicts);
if (!incremental) {
stable = opts.stabilize && opts.stabilizeonly;
if (stable)
LOG ("starting in always forced stable phase");
else
LOG ("starting in default non-stable phase");
init_averages ();
} else if (opts.stabilize && opts.stabilizeonly) {
LOG ("keeping always forced stable phase");
assert (stable);
} else if (stable) {
LOG ("switching back to default non-stable phase");
stable = false;
swap_averages ();
} else
LOG ("keeping non-stable phase");
inc.stabilize = 0;
last.stabilize.conflicts = stats.conflicts;
lim.stabilize = stats.conflicts + opts.stabilizeinit;
last.stabilize.ticks = stats.ticks.search[0];
stats.stabphases = 0;
LOG ("new ticks-based stabilize limit %" PRId64 " after %d conflicts",
lim.stabilize, (int) opts.stabilizeinit);
if (opts.stabilize && opts.reluctant && opts.reluctantint) {
LOG ("new restart reluctant doubling sequence period %d",
opts.reluctant);
reluctant.enable (opts.reluctantint, opts.reluctantmax);
} else
reluctant.disable ();
if (inc.conflicts < 0) {
lim.conflicts = -1;
LOG ("no limit on conflicts");
} else {
lim.conflicts = stats.conflicts + inc.conflicts;
LOG ("conflict limit after %" PRId64 " conflicts at %" PRId64
" conflicts",
inc.conflicts, lim.conflicts);
}
if (inc.decisions < 0) {
lim.decisions = -1;
LOG ("no limit on decisions");
} else {
lim.decisions = stats.decisions + inc.decisions;
LOG ("decision limit after %" PRId64 " decisions at %" PRId64
" decisions",
inc.decisions, lim.decisions);
}
if (inc.ticks < 0) {
lim.ticks = -1;
LOG ("no limit on ticks");
} else {
lim.ticks = stats.ticks.search[0] + stats.ticks.search[1] + inc.ticks;
LOG ("ticks limit after %" PRId64 " ticks at %" PRId64 " ticks",
inc.ticks, lim.ticks);
}
if (inc.localsearch <= 0) {
lim.localsearch = 0;
LOG ("no local search");
} else {
lim.localsearch = inc.localsearch;
LOG ("limiting to %" PRId64 " local search rounds", lim.localsearch);
}
if (incremental && opts.recomputetier) {
for (auto m : {true, false})
for (auto &u : stats.used[m])
u = 0;
stats.bump_used = {0, 0};
for (auto u : {true, false}) {
tier1[u] = max (tier1[u], opts.tier1minglue ? opts.tier1minglue : 2);
tier2[u] = max (tier2[u], opts.tier2minglue ? opts.tier2minglue : 6);
}
stats.tierecomputed = 0;
}
if (incremental)
last.incremental_decay.last_id = 0;
else {
lim.incremental_decay = opts.incdecayint;
}
if (incremental)
mode = "keeping";
else {
lim.random_decision = stats.conflicts + opts.randecinit;
mode = "initial";
}
(void) mode;
LOG ("%s randomize decision limit %" PRId64 " after %" PRId64
" conflicts",
mode, lim.random_decision, lim.random_decision - stats.conflicts);
lim.initialized = true;
}
bool Internal::preprocess_round (int round) {
(void) round;
if (unsat)
return false;
if (!max_var)
return false;
START (preprocess);
struct {
int64_t vars, clauses;
} before, after;
before.vars = active ();
before.clauses = stats.current.irredundant;
stats.preprocessings++;
assert (!preprocessing);
preprocessing = true;
PHASE ("preprocessing", stats.preprocessings,
"starting round %d with %" PRId64 " variables and %" PRId64
" clauses",
round, before.vars, before.clauses);
int old_elimbound = lim.elimbound;
if (opts.inprobing)
inprobe (false);
if (opts.elim)
elim (false);
if (opts.condition)
condition (false);
after.vars = active ();
after.clauses = stats.current.irredundant;
assert (preprocessing);
preprocessing = false;
PHASE ("preprocessing", stats.preprocessings,
"finished round %d with %" PRId64 " variables and %" PRId64
" clauses",
round, after.vars, after.clauses);
STOP (preprocess);
report ('P');
if (unsat)
return false;
if (after.vars < before.vars)
return true;
if (old_elimbound < lim.elimbound)
return true;
return false;
}
void Internal::preprocess_quickly (bool always) {
if (unsat)
return;
if (!max_var)
return;
if (!opts.preprocesslight)
return;
if (!always && stats.searches > 1)
return;
START (preprocess);
#ifndef QUIET
struct {
int64_t vars, clauses;
} before, after;
before.vars = active ();
before.clauses = stats.current.irredundant;
#endif
assert (!preprocessing);
preprocessing = true;
report ('(');
PHASE ("preprocessing", stats.preprocessings,
"starting with %" PRId64 " variables and %" PRId64 " clauses",
before.vars, before.clauses);
if (extract_gates (true))
decompose ();
binary_clauses_backbone ();
if (sweep ())
decompose ();
if (opts.factor)
factor ();
if (opts.fastelim)
elimfast ();
#ifndef QUIET
after.vars = active ();
after.clauses = stats.current.irredundant;
#endif
assert (preprocessing);
preprocessing = false;
PHASE ("preprocessing", stats.preprocessings,
"finished with %" PRId64 " variables and %" PRId64 " clauses",
after.vars, after.clauses);
STOP (preprocess);
report ('P');
}
int Internal::preprocess (bool always) {
int res = 0;
if (!level && !unsat && opts.luckyearly)
res = lucky_phases ();
if (res)
return res;
if (opts.deduplicateallinit && !stats.deduplicatedinitrounds)
deduplicate_all_clauses ();
preprocess_quickly (always);
for (int i = 0; i < lim.preprocessing; i++)
if (!preprocess_round (i))
break;
report (')');
if (unsat)
return 20;
return 0;
}
int Internal::try_to_satisfy_formula_by_saved_phases () {
LOG ("satisfying formula by saved phases");
assert (!level);
assert (!force_saved_phase);
assert (propagated == trail.size ());
force_saved_phase = true;
if (external_prop) {
assert (!level);
LOG ("external notifications are turned off during preprocessing.");
private_steps = true;
}
int res = 0;
while (!res) {
if (satisfied ()) {
LOG ("formula indeed satisfied by saved phases");
res = 10;
} else if (decide ()) {
LOG ("inconsistent assumptions with redundant clauses and phases");
res = 20;
} else if (!propagate ()) {
LOG ("saved phases do not satisfy redundant clauses");
assert (level > 0);
backtrack ();
conflict = 0; assert (!res);
break;
}
}
assert (force_saved_phase);
force_saved_phase = false;
if (external_prop) {
private_steps = false;
LOG ("external notifications are turned back on.");
if (!level)
notify_assignments (); else {
renotify_trail_after_local_search ();
}
}
return res;
}
void Internal::produce_failed_assumptions () {
LOG ("producing failed assumptions");
assert (!level);
assert (!assumptions.empty ());
while (!unsat) {
assert (!satisfied ());
notify_assignments ();
if (decide ())
break;
while (!unsat && !propagate ())
analyze ();
}
notify_assignments ();
if (unsat)
LOG ("formula is actually unsatisfiable unconditionally");
else
LOG ("assumptions indeed failing");
}
int Internal::local_search_round (int round) {
assert (round > 0);
if (unsat)
return false;
if (!max_var)
return false;
START_OUTER_WALK ();
assert (!localsearching);
localsearching = true;
int64_t limit = opts.walkmineff;
limit *= round;
if (LONG_MAX / round > limit)
limit *= round;
else
limit = LONG_MAX;
int res;
if (opts.walkfullocc)
res = walk_full_occs_round (limit, true);
else
res = walk_round (limit, true);
assert (localsearching);
localsearching = false;
STOP_OUTER_WALK ();
report ('L');
return res;
}
int Internal::local_search () {
if (unsat)
return 0;
if (!max_var)
return 0;
if (!opts.walk)
return 0;
if (constraint.size ())
return 0;
int res = 0;
for (int i = 1; !res && i <= lim.localsearch; i++)
res = local_search_round (i);
if (res == 10) {
LOG ("local search determined formula to be satisfiable");
assert (!stats.walk.minimum);
res = try_to_satisfy_formula_by_saved_phases ();
} else if (res == 20) {
LOG ("local search determined assumptions to be inconsistent");
assert (!assumptions.empty ());
produce_failed_assumptions ();
}
return res;
}
int Internal::solve (bool preprocess_only) {
assert (clause.empty ());
stats.searches++;
START (solve);
if (proof)
proof->solve_query ();
if (opts.ilb) {
sort_and_reuse_assumptions ();
assert (opts.ilb || (size_t) level <= assumptions.size ());
stats.ilbtriggers++;
stats.ilbsuccess += (level > 0);
stats.levelsreused += level;
if (level) {
assert (control.size () > 1);
stats.literalsreused += num_assigned - control[1].trail;
}
if (external->propagator)
renotify_trail_after_ilb ();
}
if (preprocess_only)
LOG ("internal solving in preprocessing only mode");
else
LOG ("internal solving in full mode");
init_report_limits ();
int res = already_solved ();
if (!res && preprocess_only && level)
backtrack ();
if (!res)
res = restore_clauses ();
if (!res || (res == 10 && external_prop)) {
init_preprocessing_limits ();
if (!preprocess_only)
init_search_limits ();
}
if (!preprocess_only) {
if (!res && !level)
res = local_search ();
}
if (!res && !level)
res = preprocess (preprocess_only);
if (!preprocess_only) {
if (!res && !level && opts.luckylate)
res = lucky_phases ();
if (!res && !level)
res = local_search ();
if (!res)
decay_clauses_upon_incremental_clauses ();
if (!res || (res == 10 && external_prop)) {
if (res == 10 && external_prop && level)
backtrack ();
res = cdcl_loop_with_inprocessing ();
}
}
finalize (res);
reset_solving ();
report_solving (res);
STOP (solve);
return res;
}
int Internal::already_solved () {
int res = 0;
if (unsat || unsat_constraint) {
LOG ("already inconsistent");
res = 20;
} else {
if (level && !opts.ilb)
backtrack ();
if (!level && !propagate ()) {
LOG ("root level propagation produces conflict");
learn_empty_clause ();
res = 20;
}
if (max_var == 0 && res == 0)
res = 10;
}
return res;
}
void Internal::report_solving (int res) {
if (res == 10)
report ('1');
else if (res == 20)
report ('0');
else
report ('?');
}
void Internal::reset_solving () {
if (termination_forced) {
termination_forced = false;
LOG ("reset forced termination");
}
}
int Internal::restore_clauses () {
int res = 0;
if (opts.restoreall <= 1 && external->tainted.empty ()) {
LOG ("no tainted literals and nothing to restore");
report ('*');
} else {
report ('+');
external->restore_clauses ();
internal->report ('r');
if (!unsat && !level && !propagate ()) {
LOG ("root level propagation after restore produces conflict");
learn_empty_clause ();
res = 20;
}
}
return res;
}
int Internal::lookahead () {
assert (clause.empty ());
START (lookahead);
assert (!lookingahead);
lookingahead = true;
if (external_prop) {
if (level) {
backtrack ();
}
LOG ("external notifications are turned off during preprocessing.");
private_steps = true;
}
int tmp = already_solved ();
if (!tmp)
tmp = restore_clauses ();
int res = 0;
if (!tmp)
res = lookahead_probing ();
if (res == INT_MIN)
res = 0;
reset_solving ();
report_solving (tmp);
assert (lookingahead);
lookingahead = false;
STOP (lookahead);
if (external_prop) {
private_steps = false;
LOG ("external notifications are turned back on.");
notify_assignments (); }
return res;
}
void Internal::finalize (int res) {
if (!proof)
return;
LOG ("finalizing");
if (frat) {
for (const auto &evar : external->vars) {
assert (evar > 0);
const auto eidx = 2 * evar;
int sign = 1;
int64_t id = external->ext_units[eidx];
if (!id) {
sign = -1;
id = external->ext_units[eidx + 1];
}
if (id) {
proof->finalize_external_unit (id, evar * sign);
}
}
for (const auto &lit : lits) {
const auto elit = externalize (lit);
if (elit) {
const unsigned eidx = (elit < 0) + 2u * (unsigned) abs (elit);
const int64_t id = external->ext_units[eidx];
if (id) {
assert (unit_clauses (vlit (lit)) == id);
continue;
}
}
const int64_t id = unit_clauses (vlit (lit));
if (!id)
continue;
proof->finalize_unit (id, lit);
}
for (const auto &c : clauses)
if (!c->garbage || (c->size == 2 && !c->flushed))
proof->finalize_clause (c);
if (conflict_id) {
proof->finalize_clause (conflict_id, {});
}
}
proof->report_status (res, conflict_id);
if (res == 10)
external->conclude_sat ();
else if (res == 20)
conclude_unsat ();
else if (!res)
external->conclude_unknown ();
}
void Internal::print_statistics () {
stats.print (this);
for (auto &st : stat_tracers)
st->print_stats ();
}
void Internal::dump (Clause *c) {
for (const auto &lit : *c)
printf ("%d ", lit);
printf ("0\n");
}
void Internal::dump () {
int64_t m = assumptions.size ();
for (auto idx : vars)
if (fixed (idx))
m++;
for (const auto &c : clauses)
if (!c->garbage)
m++;
printf ("p cnf %d %" PRId64 "\n", max_var, m);
for (auto idx : vars) {
const int tmp = fixed (idx);
if (tmp)
printf ("%d 0\n", tmp < 0 ? -idx : idx);
}
for (const auto &c : clauses)
if (!c->garbage)
dump (c);
for (const auto &lit : assumptions)
printf ("%d 0\n", lit);
fflush (stdout);
}
bool Internal::traverse_constraint (ClauseIterator &it) {
if (constraint.empty () && !unsat_constraint)
return true;
vector<int> eclause;
if (unsat)
return it.clause (eclause);
LOG (constraint, "traversing constraint");
bool satisfied = false;
for (auto ilit : constraint) {
const int tmp = fixed (ilit);
if (tmp > 0) {
satisfied = true;
break;
}
if (tmp < 0)
continue;
const int elit = externalize (ilit);
eclause.push_back (elit);
}
if (!satisfied && !it.clause (eclause))
return false;
return true;
}
bool Internal::traverse_clauses (ClauseIterator &it) {
vector<int> eclause;
if (unsat)
return it.clause (eclause);
for (const auto &c : clauses) {
if (c->garbage)
continue;
if (c->redundant)
continue;
bool satisfied = false;
for (const auto &ilit : *c) {
const int tmp = fixed (ilit);
if (tmp > 0) {
satisfied = true;
break;
}
if (tmp < 0)
continue;
const int elit = externalize (ilit);
eclause.push_back (elit);
}
if (!satisfied && !it.clause (eclause))
return false;
eclause.clear ();
}
return true;
}
}