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