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);
 | |
|     }
 | |
| }
 |