mirror of https://github.com/YosysHQ/abc.git
409 lines
9.9 KiB
C++
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
|