abc/src/sat/cadical/cadical_rephase.cpp

409 lines
9.9 KiB
C++

#include "global.h"
#include "internal.hpp"
ABC_NAMESPACE_IMPL_START
namespace CaDiCaL {
/*------------------------------------------------------------------------*/
// We experimented with resetting and reinitializing the saved phase with
// many solvers. Actually RSAT had already such a scheme. Our newest
// version seems to be quite beneficial for satisfiable instances. In an
// arithmetic increasing interval in the number of conflicts we either use
// the original phase (set by the option 'phase'), its inverted value, flip
// the current phase, pick random phases, then pick the best since the last
// time a best phase was picked and finally also use local search to find
// phases which minimize the number of falsified clauses. During
// stabilization (see 'stabilizing' in 'restart.cpp' when 'stable' is true)
// we execute a different rephasing schedule. The same applies if local
// search is disabled.
/*------------------------------------------------------------------------*/
bool Internal::rephasing () {
if (!opts.rephase)
return false;
if (opts.forcephase)
return false;
if (opts.rephase == 2) {
if (stable)
return stats.stabconflicts > lim.rephase;
else
return false;
}
return stats.conflicts > lim.rephase;
}
/*------------------------------------------------------------------------*/
// Pick the original default phase.
char Internal::rephase_original () {
stats.rephased.original++;
signed char val = opts.phase ? 1 : -1; // original = initial
PHASE ("rephase", stats.rephased.total, "switching to original phase %d",
val);
for (auto idx : vars)
phases.saved[idx] = val;
return 'O';
}
// Pick the inverted original default phase.
char Internal::rephase_inverted () {
stats.rephased.inverted++;
signed char val = opts.phase ? -1 : 1; // original = -initial
PHASE ("rephase", stats.rephased.total,
"switching to inverted original phase %d", val);
for (auto idx : vars)
phases.saved[idx] = val;
return 'I';
}
// Flip the current phase.
char Internal::rephase_flipping () {
stats.rephased.flipped++;
PHASE ("rephase", stats.rephased.total,
"flipping all phases individually");
for (auto idx : vars)
phases.saved[idx] *= -1;
return 'F';
}
// Complete random picking of phases.
char Internal::rephase_random () {
stats.rephased.random++;
PHASE ("rephase", stats.rephased.total, "resetting all phases randomly");
Random random (opts.seed); // global seed
random += stats.rephased.random; // different every time
for (auto idx : vars)
phases.saved[idx] = random.generate_bool () ? -1 : 1;
return '#';
}
// Best phases are those saved at the largest trail height without conflict.
// See code and comments in 'update_target_and_best' in 'backtrack.cpp'
char Internal::rephase_best () {
stats.rephased.best++;
PHASE ("rephase", stats.rephased.total,
"overwriting saved phases by best phases");
signed char val;
for (auto idx : vars)
if ((val = phases.best[idx]))
phases.saved[idx] = val;
return 'B';
}
// Trigger local search 'walk' in 'walk.cpp'.
char Internal::rephase_walk () {
stats.rephased.walk++;
PHASE ("rephase", stats.rephased.total,
"starting local search to improve current phase");
if (opts.walkfullocc)
walk_full_occs ();
else
walk ();
return 'W';
}
/*------------------------------------------------------------------------*/
void Internal::rephase () {
stats.rephased.total++;
last.stabilize.rephased++;
CADICAL_assert (last.stabilize.rephased <= stats.rephased.total);
PHASE ("rephase", stats.rephased.total,
"reached rephase limit %" PRId64 " after %" PRId64 " conflicts",
lim.rephase,
opts.rephase == 2 ? stats.stabconflicts : stats.conflicts);
// Report current 'target' and 'best' and then set 'rephased' below, which
// will trigger reporting the new 'target' and 'best' after updating it in
// the next 'update_target_and_best' called from the next 'backtrack'.
//
report ('~', 1);
backtrack ();
size_t count = lim.rephased[stable]++;
bool single;
char type;
if (opts.stabilize && opts.stabilizeonly)
single = true;
else
single = !opts.stabilize;
if (single && !opts.walk) {
// (inverted,best,flipping,best,random,best,original,best)^\omega
switch (count % 8) {
case 0:
type = rephase_inverted ();
break;
case 1:
type = rephase_best ();
break;
case 2:
type = rephase_flipping ();
break;
case 3:
type = rephase_best ();
break;
case 4:
type = rephase_random ();
break;
case 5:
type = rephase_best ();
break;
case 6:
type = rephase_original ();
break;
case 7:
type = rephase_best ();
break;
default:
type = 0;
break;
}
} else if (single && opts.walk) {
// (inverted,best,walk,
// flipping,best,walk,
// random,best,walk,
// original,best,walk)^\omega
switch (count % 12) {
case 0:
type = rephase_inverted ();
break;
case 1:
type = rephase_best ();
break;
case 2:
type = rephase_walk ();
break;
case 3:
type = rephase_flipping ();
break;
case 4:
type = rephase_best ();
break;
case 5:
type = rephase_walk ();
break;
case 6:
type = rephase_random ();
break;
case 7:
type = rephase_best ();
break;
case 8:
type = rephase_walk ();
break;
case 9:
type = rephase_original ();
break;
case 10:
type = rephase_best ();
break;
case 11:
type = rephase_walk ();
break;
default:
type = 0;
break;
}
} else if (opts.rephase == 2 && opts.walk) {
// (inverted,best,walk,
// flipping,best,walk,
// random,best,walk,
// original,best,walk)^\omega
switch (count % 12) {
case 0:
type = rephase_inverted ();
break;
case 1:
type = rephase_best ();
break;
case 2:
type = rephase_walk ();
break;
case 3:
type = rephase_flipping ();
break;
case 4:
type = rephase_best ();
break;
case 5:
type = rephase_walk ();
break;
case 6:
type = rephase_random ();
break;
case 7:
type = rephase_best ();
break;
case 8:
type = rephase_walk ();
break;
case 9:
type = rephase_original ();
break;
case 10:
type = rephase_best ();
break;
case 11:
type = rephase_walk ();
break;
default:
type = 0;
break;
}
} else if (stable && !opts.walk) {
// original,inverted,(best,original,best,inverted)^\omega
if (!count)
type = rephase_original ();
else if (count == 1)
type = rephase_inverted ();
else
switch ((count - 2) % 4) {
case 0:
type = rephase_best ();
break;
case 1:
type = rephase_original ();
break;
case 2:
type = rephase_best ();
break;
case 3:
type = rephase_inverted ();
break;
default:
type = 0;
break;
}
} else if (stable && opts.walk) {
// original,inverted,(best,walk,original,best,walk,inverted)^\omega
if (!count)
type = rephase_original ();
else if (count == 1)
type = rephase_inverted ();
else
switch ((count - 2) % 6) {
case 0:
type = rephase_best ();
break;
case 1:
type = rephase_walk ();
break;
case 2:
type = rephase_original ();
break;
case 3:
type = rephase_best ();
break;
case 4:
type = rephase_walk ();
break;
case 5:
type = rephase_inverted ();
break;
default:
type = 0;
break;
}
} else if (!stable && (!opts.walk || !opts.walknonstable)) {
// flipping,(random,best,flipping,best)^\omega
if (!count)
type = rephase_flipping ();
else
switch ((count - 1) % 4) {
case 0:
type = rephase_random ();
break;
case 1:
type = rephase_best ();
break;
case 2:
type = rephase_flipping ();
break;
case 3:
type = rephase_best ();
break;
default:
type = 0;
break;
}
} else {
CADICAL_assert (!stable && opts.walk && opts.walknonstable);
// flipping,(random,best,walk,flipping,best,walk)^\omega
if (!count)
type = rephase_original ();
else
switch ((count - 1) % 6) {
case 0:
type = rephase_random ();
break;
case 1:
type = rephase_best ();
break;
case 2:
type = rephase_walk ();
break;
case 3:
type = rephase_flipping ();
break;
case 4:
type = rephase_best ();
break;
case 5:
type = rephase_walk ();
break;
default:
type = 0;
break;
}
}
CADICAL_assert (type);
// clear after walk such that random walk can still access the target
// by using the saved phases
copy_phases (phases.target);
target_assigned = 0;
int64_t delta = opts.rephaseint * (stats.rephased.total + 1);
lim.rephase =
(opts.rephase == 2 ? stats.stabconflicts : stats.conflicts) + delta;
PHASE ("rephase", stats.rephased.total,
"new rephase limit %" PRId64 " after %" PRId64 " conflicts",
lim.rephase, delta);
// This will trigger to report the effect of this new set of phases at the
// 'backtrack' (actually 'update_target_and_best') after the next
// conflict, as well as resetting 'best_assigned' then to allow to compute
// a new "best" assignment at that point.
//
last.rephase.conflicts = stats.conflicts;
rephased = type;
if (!marked_failed || unsat_constraint) {
CADICAL_assert (opts.warmup);
return;
}
if (stable)
shuffle_scores ();
else
shuffle_queue ();
}
} // namespace CaDiCaL
ABC_NAMESPACE_IMPL_END