#include "internal.hpp"
namespace CaDiCaL {
int Internal::next_decision_variable_on_queue () {
int64_t searched = 0;
int res = queue.unassigned;
while (val (res))
res = link (res).prev, searched++;
if (searched) {
stats.searched += searched;
update_queue_unassigned (res);
}
LOG ("next queue decision variable %d bumped %" PRId64 "", res,
bumped (res));
return res;
}
int Internal::next_decision_variable_with_best_score () {
int res = 0;
for (;;) {
res = scores.front ();
if (!val (res))
break;
(void) scores.pop_front ();
}
LOG ("next decision variable %d with score %g", res, score (res));
return res;
}
void Internal::start_random_sequence () {
if (!opts.randec)
return;
assert (!stable || opts.randecstable);
assert (stable || opts.randecfocused);
assert (!randomized_deciding);
const uint64_t count = ++stats.randec.random_decision_phases;
const unsigned length = opts.randeclength * log (count + 10);
VERBOSE (3,
"starting random decision sequence "
"at %" PRId64 " conflicts for %u conflicts",
stats.conflicts, length);
randomized_deciding = length;
const double delta = stats.randec.random_decision_phases *
log (stats.randec.random_decision_phases);
lim.random_decision = stats.conflicts + delta * opts.randecint;
VERBOSE (3,
"next random decision sequence "
"at %" PRId64 " conflicts current conflict: %" PRId64
" conflicts",
lim.random_decision, stats.conflicts);
}
int Internal::next_random_decision () {
assert (max_var);
if (!opts.randec)
return 0;
if (stable && !opts.randecstable)
return 0;
if (!stable && !opts.randecfocused)
return 0;
if (stats.conflicts < lim.random_decision)
return 0;
if (satisfied ())
return 0;
if (!randomized_deciding) {
if (level > (int) assumptions.size () + !!constraint.size ()) {
LOG ("random decision delayed because too deep");
return 0;
}
start_random_sequence ();
}
LOG ("searching for random decision");
Random random (internal->opts.seed);
random += stats.decisions;
++stats.randec.random_decisions;
for (;;) {
int idx = 1 + (random.next () % max_var);
LOG ("trying lit %s", LOGLIT (idx));
if (val (idx))
continue;
return idx;
}
assert (false);
__builtin_unreachable ();
}
int Internal::next_decision_variable () {
int res = next_random_decision ();
if (res) {
LOG ("randomized decision %s", LOGLIT (res));
return res;
}
if (use_scores ())
return next_decision_variable_with_best_score ();
else
return next_decision_variable_on_queue ();
}
int Internal::decide_phase (int idx, bool target) {
const int initial_phase = opts.phase ? 1 : -1;
int phase = 0;
if (force_saved_phase) {
phase = phases.saved[idx];
LOG ("trying force_saved_phase, i.e., %d", phase);
}
assert (force_saved_phase || !phase);
if (!phase) {
phase = phases.forced[idx]; LOG ("trying forced phase, i.e., %d", phase);
}
if (!phase && opts.forcephase) {
phase = initial_phase;
LOG ("trying initial phase, i.e., %d", phase);
}
if (!phase && target) {
phase = phases.target[idx];
}
if (!phase) {
if (opts.stubbornIOfocused && opts.rephase == 2)
switch ((stats.rephased.total >> 1) & 7) {
case 1:
phase = initial_phase;
break;
case 5: phase = -initial_phase;
break;
default:
phase = phases.saved[idx];
break;
}
else
phase = phases.saved[idx];
}
if (!phase)
phase = initial_phase;
return phase * idx;
}
int Internal::likely_phase (int idx) { return decide_phase (idx, false); }
void Internal::new_trail_level (int lit) {
level++;
control.push_back (Level (lit, trail.size ()));
}
bool Internal::satisfied () {
if ((size_t) level < assumptions.size () + (!!constraint.size ()))
return false;
if (num_assigned < (size_t) max_var)
return false;
assert (num_assigned == (size_t) max_var);
if (propagated < trail.size ())
return false;
size_t assigned = num_assigned;
return (assigned == (size_t) max_var);
}
bool Internal::better_decision (int lit, int other) {
int lit_idx = abs (lit);
int other_idx = abs (other);
if (stable)
return stab[lit_idx] > stab[other_idx];
else
return btab[lit_idx] > btab[other_idx];
}
int Internal::decide () {
assert (!satisfied ());
START (decide);
int res = 0;
if ((size_t) level < assumptions.size ()) {
const int lit = assumptions[level];
assert (assumed (lit));
const signed char tmp = val (lit);
if (tmp < 0) {
LOG ("assumption %d falsified", lit);
res = 20;
} else if (tmp > 0) {
LOG ("assumption %d already satisfied", lit);
new_trail_level (0);
LOG ("added pseudo decision level");
notify_decision ();
} else {
LOG ("deciding assumption %d", lit);
search_assume_decision (lit);
}
} else if ((size_t) level == assumptions.size () && constraint.size ()) {
int satisfied_lit = 0; int unassigned_lit = 0; int previous_lit = 0;
const size_t size_constraint = constraint.size ();
#ifndef NDEBUG
unsigned sum = 0;
for (auto lit : constraint)
sum += lit;
#endif
for (size_t i = 0; i != size_constraint; i++) {
int lit = constraint[i];
constraint[i] = previous_lit;
previous_lit = lit;
const signed char tmp = val (lit);
if (tmp < 0) {
LOG ("constraint literal %d falsified", lit);
continue;
}
if (tmp > 0) {
LOG ("constraint literal %d satisfied", lit);
satisfied_lit = lit;
break;
}
assert (!tmp);
LOG ("constraint literal %d unassigned", lit);
if (!unassigned_lit || better_decision (lit, unassigned_lit))
unassigned_lit = lit;
}
if (satisfied_lit) {
constraint[0] = satisfied_lit;
LOG ("literal %d satisfies constraint and "
"is implied by assumptions",
satisfied_lit);
new_trail_level (0);
LOG ("added pseudo decision level for constraint");
notify_decision ();
} else {
if (size_constraint) {
for (size_t i = 0; i + 1 != size_constraint; i++)
constraint[i] = constraint[i + 1];
constraint[size_constraint - 1] = previous_lit;
}
if (unassigned_lit) {
LOG ("deciding %d to satisfy constraint", unassigned_lit);
search_assume_decision (unassigned_lit);
} else {
LOG ("failing constraint");
unsat_constraint = true;
res = 20;
}
}
#ifndef NDEBUG
for (auto lit : constraint)
sum -= lit;
assert (!sum); #endif
} else {
int decision = ask_decision ();
if ((size_t) level < assumptions.size () ||
((size_t) level == assumptions.size () && constraint.size ())) {
STOP (decide);
res = decide (); START (decide);
} else {
stats.decisions++;
if (!decision) {
int idx = next_decision_variable ();
const bool target = (opts.target > 1 || (stable && opts.target));
decision = decide_phase (idx, target);
}
search_assume_decision (decision);
}
}
if (res)
marked_failed = false;
STOP (decide);
return res;
}
}