792 lines
24 KiB
C++
792 lines
24 KiB
C++
|
/****************************************************************************************[Solver.C]
|
||
|
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||
|
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||
|
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||
|
furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in all copies or
|
||
|
substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||
|
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
**************************************************************************************************/
|
||
|
|
||
|
#include "Solver.h"
|
||
|
#include "Sort.h"
|
||
|
#include <cmath>
|
||
|
#include <iostream>
|
||
|
|
||
|
|
||
|
//=================================================================================================
|
||
|
// Constructor/Destructor:
|
||
|
|
||
|
|
||
|
Solver::Solver() :
|
||
|
|
||
|
// Parameters: (formerly in 'SearchParams')
|
||
|
var_decay(1 / 0.95), clause_decay(1 / 0.999), random_var_freq(0.02)
|
||
|
, restart_first(100), restart_inc(1.5), learntsize_factor((double)1/(double)3), learntsize_inc(1.1)
|
||
|
|
||
|
// More parameters:
|
||
|
//
|
||
|
, expensive_ccmin (true)
|
||
|
, polarity_mode (polarity_false)
|
||
|
, verbosity (0)
|
||
|
|
||
|
// Statistics: (formerly in 'SolverStats')
|
||
|
//
|
||
|
, starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
|
||
|
, clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
|
||
|
|
||
|
//***************
|
||
|
, allMinVarsAssigned(false)
|
||
|
//***************
|
||
|
|
||
|
, ok (true)
|
||
|
, cla_inc (1)
|
||
|
, var_inc (1)
|
||
|
, qhead (0)
|
||
|
, simpDB_assigns (-1)
|
||
|
, simpDB_props (0)
|
||
|
, order_heap (VarOrderLt(activity))
|
||
|
, random_seed (91648253)
|
||
|
, progress_estimate(0)
|
||
|
, remove_satisfied (true)
|
||
|
{}
|
||
|
|
||
|
|
||
|
Solver::~Solver()
|
||
|
{
|
||
|
for (int i = 0; i < learnts.size(); i++) free(learnts[i]);
|
||
|
for (int i = 0; i < clauses.size(); i++) free(clauses[i]);
|
||
|
}
|
||
|
|
||
|
|
||
|
//=================================================================================================
|
||
|
// Minor methods:
|
||
|
|
||
|
|
||
|
// Creates a new SAT variable in the solver. If 'decision_var' is cleared, variable will not be
|
||
|
// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
|
||
|
//
|
||
|
Var Solver::newVar(bool sign, bool dvar)
|
||
|
{
|
||
|
int v = nVars();
|
||
|
watches .push(); // (list for positive literal)
|
||
|
watches .push(); // (list for negative literal)
|
||
|
reason .push(NULL);
|
||
|
assigns .push(toInt(l_Undef));
|
||
|
level .push(-1);
|
||
|
activity .push(0);
|
||
|
seen .push(0);
|
||
|
|
||
|
polarity .push((char)sign);
|
||
|
decision_var.push((char)dvar);
|
||
|
|
||
|
insertVarOrder(v);
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool Solver::addClause(vec<Lit>& ps)
|
||
|
{
|
||
|
assert(decisionLevel() == 0);
|
||
|
|
||
|
if (!ok)
|
||
|
return false;
|
||
|
else{
|
||
|
// Check if clause is satisfied and remove false/duplicate literals:
|
||
|
sort(ps);
|
||
|
Lit p; int i, j;
|
||
|
for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
|
||
|
if (value(ps[i]) == l_True || ps[i] == ~p)
|
||
|
return true;
|
||
|
else if (value(ps[i]) != l_False && ps[i] != p)
|
||
|
ps[j++] = p = ps[i];
|
||
|
ps.shrink(i - j);
|
||
|
}
|
||
|
|
||
|
if (ps.size() == 0)
|
||
|
return ok = false;
|
||
|
else if (ps.size() == 1){
|
||
|
assert(value(ps[0]) == l_Undef);
|
||
|
uncheckedEnqueue(ps[0]);
|
||
|
return ok = (propagate() == NULL);
|
||
|
}else{
|
||
|
Clause* c = Clause_new(ps, false);
|
||
|
clauses.push(c);
|
||
|
attachClause(*c);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
//****************
|
||
|
bool Solver::setminVars(vec<Lit>& ps)
|
||
|
{
|
||
|
minVars.clear();
|
||
|
for (int i=0; i < ps.size(); i++){
|
||
|
minVars.push(ps[i]);
|
||
|
}
|
||
|
allMinVarsAssigned = false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
//****************
|
||
|
|
||
|
|
||
|
void Solver::attachClause(Clause& c) {
|
||
|
assert(c.size() > 1);
|
||
|
watches[toInt(~c[0])].push(&c);
|
||
|
watches[toInt(~c[1])].push(&c);
|
||
|
if (c.learnt()) learnts_literals += c.size();
|
||
|
else clauses_literals += c.size(); }
|
||
|
|
||
|
|
||
|
void Solver::detachClause(Clause& c) {
|
||
|
assert(c.size() > 1);
|
||
|
assert(find(watches[toInt(~c[0])], &c));
|
||
|
assert(find(watches[toInt(~c[1])], &c));
|
||
|
remove(watches[toInt(~c[0])], &c);
|
||
|
remove(watches[toInt(~c[1])], &c);
|
||
|
if (c.learnt()) learnts_literals -= c.size();
|
||
|
else clauses_literals -= c.size(); }
|
||
|
|
||
|
|
||
|
void Solver::removeClause(Clause& c) {
|
||
|
detachClause(c);
|
||
|
free(&c); }
|
||
|
|
||
|
|
||
|
bool Solver::satisfied(const Clause& c) const {
|
||
|
for (int i = 0; i < c.size(); i++)
|
||
|
if (value(c[i]) == l_True)
|
||
|
return true;
|
||
|
return false; }
|
||
|
|
||
|
|
||
|
// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
|
||
|
//
|
||
|
void Solver::cancelUntil(int level) {
|
||
|
if (decisionLevel() > level){
|
||
|
for (int c = trail.size()-1; c >= trail_lim[level]; c--){
|
||
|
Var x = var(trail[c]);
|
||
|
assigns[x] = toInt(l_Undef);
|
||
|
insertVarOrder(x); }
|
||
|
qhead = trail_lim[level];
|
||
|
trail.shrink(trail.size() - trail_lim[level]);
|
||
|
trail_lim.shrink(trail_lim.size() - level);
|
||
|
}
|
||
|
|
||
|
//**************************
|
||
|
if (lastMinVarDL > level){
|
||
|
allMinVarsAssigned = false;
|
||
|
}
|
||
|
//**************************
|
||
|
}
|
||
|
|
||
|
|
||
|
//=================================================================================================
|
||
|
// Major methods:
|
||
|
|
||
|
|
||
|
Lit Solver::pickBranchLit(int polarity_mode, double random_var_freq)
|
||
|
{
|
||
|
Var next = var_Undef;
|
||
|
|
||
|
// Random decision:
|
||
|
if (drand(random_seed) < random_var_freq && !order_heap.empty()){
|
||
|
next = order_heap[irand(random_seed,order_heap.size())];
|
||
|
if (toLbool(assigns[next]) == l_Undef && decision_var[next])
|
||
|
rnd_decisions++; }
|
||
|
|
||
|
// Activity based decision:
|
||
|
while (next == var_Undef || toLbool(assigns[next]) != l_Undef || !decision_var[next])
|
||
|
if (order_heap.empty()){
|
||
|
next = var_Undef;
|
||
|
break;
|
||
|
}else
|
||
|
next = order_heap.removeMin();
|
||
|
|
||
|
bool sign = false;
|
||
|
switch (polarity_mode){
|
||
|
case polarity_true: sign = false; break;
|
||
|
case polarity_false: sign = true; break;
|
||
|
case polarity_user: sign = polarity[next]; break;
|
||
|
case polarity_rnd: sign = irand(random_seed, 2); break;
|
||
|
default: assert(false); }
|
||
|
|
||
|
return next == var_Undef ? lit_Undef : Lit(next, sign);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*_________________________________________________________________________________________________
|
||
|
|
|
||
|
| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void]
|
||
|
|
|
||
|
| Description:
|
||
|
| Analyze conflict and produce a reason clause.
|
||
|
|
|
||
|
| Pre-conditions:
|
||
|
| * 'out_learnt' is assumed to be cleared.
|
||
|
| * Current decision level must be greater than root level.
|
||
|
|
|
||
|
| Post-conditions:
|
||
|
| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
|
||
|
|
|
||
|
| Effect:
|
||
|
| Will undo part of the trail, upto but not beyond the assumption of the current decision level.
|
||
|
|________________________________________________________________________________________________@*/
|
||
|
void Solver::analyze(Clause* confl, vec<Lit>& out_learnt, int& out_btlevel)
|
||
|
{
|
||
|
int pathC = 0;
|
||
|
Lit p = lit_Undef;
|
||
|
|
||
|
// Generate conflict clause:
|
||
|
//
|
||
|
out_learnt.push(); // (leave room for the asserting literal)
|
||
|
int index = trail.size() - 1;
|
||
|
out_btlevel = 0;
|
||
|
|
||
|
do{
|
||
|
assert(confl != NULL); // (otherwise should be UIP)
|
||
|
Clause& c = *confl;
|
||
|
|
||
|
if (c.learnt())
|
||
|
claBumpActivity(c);
|
||
|
|
||
|
for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
|
||
|
Lit q = c[j];
|
||
|
|
||
|
if (!seen[var(q)] && level[var(q)] > 0){
|
||
|
varBumpActivity(var(q));
|
||
|
seen[var(q)] = 1;
|
||
|
if (level[var(q)] >= decisionLevel())
|
||
|
pathC++;
|
||
|
else{
|
||
|
out_learnt.push(q);
|
||
|
if (level[var(q)] > out_btlevel)
|
||
|
out_btlevel = level[var(q)];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Select next clause to look at:
|
||
|
while (!seen[var(trail[index--])]);
|
||
|
p = trail[index+1];
|
||
|
confl = reason[var(p)];
|
||
|
seen[var(p)] = 0;
|
||
|
pathC--;
|
||
|
|
||
|
}while (pathC > 0);
|
||
|
out_learnt[0] = ~p;
|
||
|
|
||
|
// Simplify conflict clause:
|
||
|
//
|
||
|
int i, j;
|
||
|
if (expensive_ccmin){
|
||
|
uint32_t abstract_level = 0;
|
||
|
for (i = 1; i < out_learnt.size(); i++)
|
||
|
abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)
|
||
|
|
||
|
out_learnt.copyTo(analyze_toclear);
|
||
|
for (i = j = 1; i < out_learnt.size(); i++)
|
||
|
if (reason[var(out_learnt[i])] == NULL || !litRedundant(out_learnt[i], abstract_level))
|
||
|
out_learnt[j++] = out_learnt[i];
|
||
|
}else{
|
||
|
out_learnt.copyTo(analyze_toclear);
|
||
|
for (i = j = 1; i < out_learnt.size(); i++){
|
||
|
Clause& c = *reason[var(out_learnt[i])];
|
||
|
for (int k = 1; k < c.size(); k++)
|
||
|
if (!seen[var(c[k])] && level[var(c[k])] > 0){
|
||
|
out_learnt[j++] = out_learnt[i];
|
||
|
break; }
|
||
|
}
|
||
|
}
|
||
|
max_literals += out_learnt.size();
|
||
|
out_learnt.shrink(i - j);
|
||
|
tot_literals += out_learnt.size();
|
||
|
|
||
|
// Find correct backtrack level:
|
||
|
//
|
||
|
if (out_learnt.size() == 1)
|
||
|
out_btlevel = 0;
|
||
|
else{
|
||
|
int max_i = 1;
|
||
|
for (int i = 2; i < out_learnt.size(); i++)
|
||
|
if (level[var(out_learnt[i])] > level[var(out_learnt[max_i])])
|
||
|
max_i = i;
|
||
|
Lit p = out_learnt[max_i];
|
||
|
out_learnt[max_i] = out_learnt[1];
|
||
|
out_learnt[1] = p;
|
||
|
out_btlevel = level[var(p)];
|
||
|
}
|
||
|
|
||
|
|
||
|
for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared)
|
||
|
}
|
||
|
|
||
|
|
||
|
// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is
|
||
|
// visiting literals at levels that cannot be removed later.
|
||
|
bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
|
||
|
{
|
||
|
analyze_stack.clear(); analyze_stack.push(p);
|
||
|
int top = analyze_toclear.size();
|
||
|
while (analyze_stack.size() > 0){
|
||
|
assert(reason[var(analyze_stack.last())] != NULL);
|
||
|
Clause& c = *reason[var(analyze_stack.last())]; analyze_stack.pop();
|
||
|
|
||
|
for (int i = 1; i < c.size(); i++){
|
||
|
Lit p = c[i];
|
||
|
if (!seen[var(p)] && level[var(p)] > 0){
|
||
|
if (reason[var(p)] != NULL && (abstractLevel(var(p)) & abstract_levels) != 0){
|
||
|
seen[var(p)] = 1;
|
||
|
analyze_stack.push(p);
|
||
|
analyze_toclear.push(p);
|
||
|
}else{
|
||
|
for (int j = top; j < analyze_toclear.size(); j++)
|
||
|
seen[var(analyze_toclear[j])] = 0;
|
||
|
analyze_toclear.shrink(analyze_toclear.size() - top);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*_________________________________________________________________________________________________
|
||
|
|
|
||
|
| analyzeFinal : (p : Lit) -> [void]
|
||
|
|
|
||
|
| Description:
|
||
|
| Specialized analysis procedure to express the final conflict in terms of assumptions.
|
||
|
| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
|
||
|
| stores the result in 'out_conflict'.
|
||
|
|________________________________________________________________________________________________@*/
|
||
|
void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
|
||
|
{
|
||
|
out_conflict.clear();
|
||
|
out_conflict.push(p);
|
||
|
|
||
|
if (decisionLevel() == 0)
|
||
|
return;
|
||
|
|
||
|
seen[var(p)] = 1;
|
||
|
|
||
|
for (int i = trail.size()-1; i >= trail_lim[0]; i--){
|
||
|
Var x = var(trail[i]);
|
||
|
if (seen[x]){
|
||
|
if (reason[x] == NULL){
|
||
|
assert(level[x] > 0);
|
||
|
out_conflict.push(~trail[i]);
|
||
|
}else{
|
||
|
Clause& c = *reason[x];
|
||
|
for (int j = 1; j < c.size(); j++)
|
||
|
if (level[var(c[j])] > 0)
|
||
|
seen[var(c[j])] = 1;
|
||
|
}
|
||
|
seen[x] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
seen[var(p)] = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Solver::uncheckedEnqueue(Lit p, Clause* from)
|
||
|
{
|
||
|
assert(value(p) == l_Undef);
|
||
|
assigns [var(p)] = toInt(lbool(!sign(p))); // <<== abstract but not uttermost effecient
|
||
|
level [var(p)] = decisionLevel();
|
||
|
reason [var(p)] = from;
|
||
|
trail.push(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*_________________________________________________________________________________________________
|
||
|
|
|
||
|
| propagate : [void] -> [Clause*]
|
||
|
|
|
||
|
| Description:
|
||
|
| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
|
||
|
| otherwise NULL.
|
||
|
|
|
||
|
| Post-conditions:
|
||
|
| * the propagation queue is empty, even if there was a conflict.
|
||
|
|________________________________________________________________________________________________@*/
|
||
|
Clause* Solver::propagate()
|
||
|
{
|
||
|
Clause* confl = NULL;
|
||
|
int num_props = 0;
|
||
|
|
||
|
while (qhead < trail.size()){
|
||
|
Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
|
||
|
vec<Clause*>& ws = watches[toInt(p)];
|
||
|
Clause **i, **j, **end;
|
||
|
num_props++;
|
||
|
|
||
|
for (i = j = (Clause**)ws, end = i + ws.size(); i != end;){
|
||
|
Clause& c = **i++;
|
||
|
|
||
|
// Make sure the false literal is data[1]:
|
||
|
Lit false_lit = ~p;
|
||
|
if (c[0] == false_lit)
|
||
|
c[0] = c[1], c[1] = false_lit;
|
||
|
|
||
|
assert(c[1] == false_lit);
|
||
|
|
||
|
// If 0th watch is true, then clause is already satisfied.
|
||
|
Lit first = c[0];
|
||
|
if (value(first) == l_True){
|
||
|
*j++ = &c;
|
||
|
}else{
|
||
|
// Look for new watch:
|
||
|
for (int k = 2; k < c.size(); k++)
|
||
|
if (value(c[k]) != l_False){
|
||
|
c[1] = c[k]; c[k] = false_lit;
|
||
|
watches[toInt(~c[1])].push(&c);
|
||
|
goto FoundWatch; }
|
||
|
|
||
|
// Did not find watch -- clause is unit under assignment:
|
||
|
*j++ = &c;
|
||
|
if (value(first) == l_False){
|
||
|
confl = &c;
|
||
|
qhead = trail.size();
|
||
|
// Copy the remaining watches:
|
||
|
while (i < end)
|
||
|
*j++ = *i++;
|
||
|
}else
|
||
|
uncheckedEnqueue(first, &c);
|
||
|
}
|
||
|
FoundWatch:;
|
||
|
}
|
||
|
ws.shrink(i - j);
|
||
|
}
|
||
|
propagations += num_props;
|
||
|
simpDB_props -= num_props;
|
||
|
|
||
|
return confl;
|
||
|
}
|
||
|
|
||
|
/*_________________________________________________________________________________________________
|
||
|
|
|
||
|
| reduceDB : () -> [void]
|
||
|
|
|
||
|
| Description:
|
||
|
| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
|
||
|
| clauses are clauses that are reason to some assignment. Binary clauses are never removed.
|
||
|
|________________________________________________________________________________________________@*/
|
||
|
struct reduceDB_lt { bool operator () (Clause* x, Clause* y) { return x->size() > 2 && (y->size() == 2 || x->activity() < y->activity()); } };
|
||
|
void Solver::reduceDB()
|
||
|
{
|
||
|
int i, j;
|
||
|
double extra_lim = cla_inc / learnts.size(); // Remove any clause below this activity
|
||
|
|
||
|
sort(learnts, reduceDB_lt());
|
||
|
for (i = j = 0; i < learnts.size() / 2; i++){
|
||
|
if (learnts[i]->size() > 2 && !locked(*learnts[i]))
|
||
|
removeClause(*learnts[i]);
|
||
|
else
|
||
|
learnts[j++] = learnts[i];
|
||
|
}
|
||
|
for (; i < learnts.size(); i++){
|
||
|
if (learnts[i]->size() > 2 && !locked(*learnts[i]) && learnts[i]->activity() < extra_lim)
|
||
|
removeClause(*learnts[i]);
|
||
|
else
|
||
|
learnts[j++] = learnts[i];
|
||
|
}
|
||
|
learnts.shrink(i - j);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Solver::removeSatisfied(vec<Clause*>& cs)
|
||
|
{
|
||
|
int i,j;
|
||
|
for (i = j = 0; i < cs.size(); i++){
|
||
|
if (satisfied(*cs[i]))
|
||
|
removeClause(*cs[i]);
|
||
|
else
|
||
|
cs[j++] = cs[i];
|
||
|
}
|
||
|
cs.shrink(i - j);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*_________________________________________________________________________________________________
|
||
|
|
|
||
|
| simplify : [void] -> [bool]
|
||
|
|
|
||
|
| Description:
|
||
|
| Simplify the clause database according to the current top-level assigment. Currently, the only
|
||
|
| thing done here is the removal of satisfied clauses, but more things can be put here.
|
||
|
|________________________________________________________________________________________________@*/
|
||
|
bool Solver::simplify()
|
||
|
{
|
||
|
assert(decisionLevel() == 0);
|
||
|
|
||
|
if (!ok || propagate() != NULL)
|
||
|
return ok = false;
|
||
|
|
||
|
if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
|
||
|
return true;
|
||
|
|
||
|
// Remove satisfied clauses:
|
||
|
removeSatisfied(learnts);
|
||
|
if (remove_satisfied) // Can be turned off.
|
||
|
removeSatisfied(clauses);
|
||
|
|
||
|
// Remove fixed variables from the variable heap:
|
||
|
order_heap.filter(VarFilter(*this));
|
||
|
|
||
|
simpDB_assigns = nAssigns();
|
||
|
simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now)
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*_________________________________________________________________________________________________
|
||
|
|
|
||
|
| search : (nof_conflicts : int) (nof_learnts : int) (params : const SearchParams&) -> [lbool]
|
||
|
|
|
||
|
| Description:
|
||
|
| Search for a model the specified number of conflicts, keeping the number of learnt clauses
|
||
|
| below the provided limit. NOTE! Use negative value for 'nof_conflicts' or 'nof_learnts' to
|
||
|
| indicate infinity.
|
||
|
|
|
||
|
| Output:
|
||
|
| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
|
||
|
| all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
|
||
|
| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
|
||
|
|________________________________________________________________________________________________@*/
|
||
|
lbool Solver::search(int nof_conflicts, int nof_learnts)
|
||
|
{
|
||
|
assert(ok);
|
||
|
int backtrack_level;
|
||
|
int conflictC = 0;
|
||
|
vec<Lit> learnt_clause;
|
||
|
|
||
|
starts++;
|
||
|
|
||
|
bool first = true;
|
||
|
|
||
|
for (;;){
|
||
|
Clause* confl = propagate();
|
||
|
if (confl != NULL){
|
||
|
// CONFLICT
|
||
|
conflicts++; conflictC++;
|
||
|
if (decisionLevel() == 0) return l_False;
|
||
|
|
||
|
first = false;
|
||
|
|
||
|
learnt_clause.clear();
|
||
|
analyze(confl, learnt_clause, backtrack_level);
|
||
|
cancelUntil(backtrack_level);
|
||
|
assert(value(learnt_clause[0]) == l_Undef);
|
||
|
|
||
|
if (learnt_clause.size() == 1){
|
||
|
uncheckedEnqueue(learnt_clause[0]);
|
||
|
}else{
|
||
|
Clause* c = Clause_new(learnt_clause, true);
|
||
|
learnts.push(c);
|
||
|
attachClause(*c);
|
||
|
claBumpActivity(*c);
|
||
|
uncheckedEnqueue(learnt_clause[0], c);
|
||
|
}
|
||
|
|
||
|
varDecayActivity();
|
||
|
claDecayActivity();
|
||
|
|
||
|
}else{
|
||
|
// NO CONFLICT
|
||
|
|
||
|
if (nof_conflicts >= 0 && conflictC >= nof_conflicts){
|
||
|
// Reached bound on number of conflicts:
|
||
|
progress_estimate = progressEstimate();
|
||
|
cancelUntil(0);
|
||
|
return l_Undef; }
|
||
|
|
||
|
// Simplify the set of problem clauses:
|
||
|
if (decisionLevel() == 0 && !simplify())
|
||
|
return l_False;
|
||
|
|
||
|
if (nof_learnts >= 0 && learnts.size()-nAssigns() >= nof_learnts)
|
||
|
// Reduce the set of learnt clauses:
|
||
|
reduceDB();
|
||
|
|
||
|
Lit next = lit_Undef;
|
||
|
while (decisionLevel() < assumptions.size()){
|
||
|
// Perform user provided assumption:
|
||
|
Lit p = assumptions[decisionLevel()];
|
||
|
if (value(p) == l_True){
|
||
|
// Dummy decision level:
|
||
|
newDecisionLevel();
|
||
|
}else if (value(p) == l_False){
|
||
|
analyzeFinal(~p, conflict);
|
||
|
return l_False;
|
||
|
}else{
|
||
|
next = p;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//**************************
|
||
|
if (next == lit_Undef){
|
||
|
// New variable decision:
|
||
|
decisions++;
|
||
|
|
||
|
if (!allMinVarsAssigned){
|
||
|
for (int i=0; i<minVars.size(); i++){
|
||
|
if (value(minVars[i])==l_Undef){
|
||
|
next = minVars[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (next == lit_Undef){
|
||
|
allMinVarsAssigned = true;
|
||
|
lastMinVarDL = decisionLevel();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//***************************
|
||
|
|
||
|
|
||
|
if (next == lit_Undef){
|
||
|
// New variable decision:
|
||
|
decisions++;
|
||
|
next = pickBranchLit(polarity_mode, random_var_freq);
|
||
|
|
||
|
if (next == lit_Undef)
|
||
|
// Model found:
|
||
|
return l_True;
|
||
|
}
|
||
|
|
||
|
// Increase decision level and enqueue 'next'
|
||
|
assert(value(next) == l_Undef);
|
||
|
newDecisionLevel();
|
||
|
uncheckedEnqueue(next);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
double Solver::progressEstimate() const
|
||
|
{
|
||
|
double progress = 0;
|
||
|
double F = 1.0 / nVars();
|
||
|
|
||
|
for (int i = 0; i <= decisionLevel(); i++){
|
||
|
int beg = i == 0 ? 0 : trail_lim[i - 1];
|
||
|
int end = i == decisionLevel() ? trail.size() : trail_lim[i];
|
||
|
progress += pow(F, i) * (end - beg);
|
||
|
}
|
||
|
|
||
|
return progress / nVars();
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Solver::solve(const vec<Lit>& assumps)
|
||
|
{
|
||
|
model.clear();
|
||
|
conflict.clear();
|
||
|
|
||
|
allMinVarsAssigned = false;
|
||
|
|
||
|
if (!ok) return false;
|
||
|
|
||
|
assumps.copyTo(assumptions);
|
||
|
|
||
|
double nof_conflicts = restart_first;
|
||
|
double nof_learnts = nClauses() * learntsize_factor;
|
||
|
lbool status = l_Undef;
|
||
|
|
||
|
if (verbosity >= 1){
|
||
|
reportf("============================[ Search Statistics ]==============================\n");
|
||
|
reportf("| Conflicts | ORIGINAL | LEARNT | Progress |\n");
|
||
|
reportf("| | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n");
|
||
|
reportf("===============================================================================\n");
|
||
|
}
|
||
|
|
||
|
// Search:
|
||
|
while (status == l_Undef){
|
||
|
if (verbosity >= 1)
|
||
|
reportf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", (int)conflicts, order_heap.size(), nClauses(), (int)clauses_literals, (int)nof_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progress_estimate*100), fflush(stdout);
|
||
|
status = search((int)nof_conflicts, (int)nof_learnts);
|
||
|
nof_conflicts *= restart_inc;
|
||
|
nof_learnts *= learntsize_inc;
|
||
|
}
|
||
|
|
||
|
if (verbosity >= 1)
|
||
|
reportf("===============================================================================\n");
|
||
|
|
||
|
|
||
|
if (status == l_True){
|
||
|
// Extend & copy model:
|
||
|
model.growTo(nVars());
|
||
|
for (int i = 0; i < nVars(); i++) model[i] = value(i);
|
||
|
#ifndef NDEBUG
|
||
|
verifyModel();
|
||
|
#endif
|
||
|
}else{
|
||
|
assert(status == l_False);
|
||
|
if (conflict.size() == 0)
|
||
|
ok = false;
|
||
|
}
|
||
|
|
||
|
cancelUntil(0);
|
||
|
return status == l_True;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void Solver::verifyModel()
|
||
|
{
|
||
|
bool failed = false;
|
||
|
for (int i = 0; i < clauses.size(); i++){
|
||
|
assert(clauses[i]->mark() == 0);
|
||
|
Clause& c = *clauses[i];
|
||
|
for (int j = 0; j < c.size(); j++)
|
||
|
if (modelValue(c[j]) == l_True)
|
||
|
goto next;
|
||
|
|
||
|
reportf("unsatisfied clause: ");
|
||
|
printClause(*clauses[i]);
|
||
|
reportf("\n");
|
||
|
failed = true;
|
||
|
next:;
|
||
|
}
|
||
|
|
||
|
assert(!failed);
|
||
|
|
||
|
// reportf("Verified %d original clauses.\n", clauses.size());
|
||
|
}
|
||
|
|
||
|
|
||
|
void Solver::checkLiteralCount()
|
||
|
{
|
||
|
// Check that sizes are calculated correctly:
|
||
|
int cnt = 0;
|
||
|
for (int i = 0; i < clauses.size(); i++)
|
||
|
if (clauses[i]->mark() == 0)
|
||
|
cnt += clauses[i]->size();
|
||
|
|
||
|
if ((int)clauses_literals != cnt){
|
||
|
fprintf(stderr, "literal count: %d, real value = %d\n", (int)clauses_literals, cnt);
|
||
|
assert((int)clauses_literals == cnt);
|
||
|
}
|
||
|
}
|