mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +00:00 
			
		
		
		
	Replace; #define __STDC_LIMIT_MACROS #define __STDC_FORMAT_MACROS With #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif This fixes a compile warning if you are defining these macros in your CXXFLAGS (as some distros do).
		
			
				
	
	
		
			1072 lines
		
	
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1072 lines
		
	
	
	
		
			34 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef __STDC_FORMAT_MACROS
 | |
| #define __STDC_FORMAT_MACROS
 | |
| #endif
 | |
| #ifndef __STDC_LIMIT_MACROS
 | |
| #define __STDC_LIMIT_MACROS
 | |
| #endif
 | |
| /***************************************************************************************[Solver.cc]
 | |
| Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
 | |
| Copyright (c) 2007-2010, 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 <math.h>
 | |
| 
 | |
| #include "Alg.h"
 | |
| #include "Sort.h"
 | |
| #include "System.h"
 | |
| #include "Solver.h"
 | |
| 
 | |
| using namespace Minisat;
 | |
| 
 | |
| //=================================================================================================
 | |
| // Options:
 | |
| 
 | |
| 
 | |
| static const char* _cat = "CORE";
 | |
| 
 | |
| static DoubleOption  opt_var_decay         (_cat, "var-decay",   "The variable activity decay factor",            0.95,     DoubleRange(0, false, 1, false));
 | |
| static DoubleOption  opt_clause_decay      (_cat, "cla-decay",   "The clause activity decay factor",              0.999,    DoubleRange(0, false, 1, false));
 | |
| static DoubleOption  opt_random_var_freq   (_cat, "rnd-freq",    "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
 | |
| static DoubleOption  opt_random_seed       (_cat, "rnd-seed",    "Used by the random variable selection",         91648253, DoubleRange(0, false, HUGE_VAL, false));
 | |
| static IntOption     opt_ccmin_mode        (_cat, "ccmin-mode",  "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2));
 | |
| static IntOption     opt_phase_saving      (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
 | |
| static BoolOption    opt_rnd_init_act      (_cat, "rnd-init",    "Randomize the initial activity", false);
 | |
| static BoolOption    opt_luby_restart      (_cat, "luby",        "Use the Luby restart sequence", true);
 | |
| static IntOption     opt_restart_first     (_cat, "rfirst",      "The base restart interval", 100, IntRange(1, INT32_MAX));
 | |
| static DoubleOption  opt_restart_inc       (_cat, "rinc",        "Restart interval increase factor", 2, DoubleRange(1, false, HUGE_VAL, false));
 | |
| static DoubleOption  opt_garbage_frac      (_cat, "gc-frac",     "The fraction of wasted memory allowed before a garbage collection is triggered",  0.20, DoubleRange(0, false, HUGE_VAL, false));
 | |
| static IntOption     opt_min_learnts_lim   (_cat, "min-learnts", "Minimum learnt clause limit",  0, IntRange(0, INT32_MAX));
 | |
| 
 | |
| 
 | |
| //=================================================================================================
 | |
| // Constructor/Destructor:
 | |
| 
 | |
| 
 | |
| Solver::Solver() :
 | |
| 
 | |
|     // Parameters (user settable):
 | |
|     //
 | |
|     verbosity        (0)
 | |
|   , var_decay        (opt_var_decay)
 | |
|   , clause_decay     (opt_clause_decay)
 | |
|   , random_var_freq  (opt_random_var_freq)
 | |
|   , random_seed      (opt_random_seed)
 | |
|   , luby_restart     (opt_luby_restart)
 | |
|   , ccmin_mode       (opt_ccmin_mode)
 | |
|   , phase_saving     (opt_phase_saving)
 | |
|   , rnd_pol          (false)
 | |
|   , rnd_init_act     (opt_rnd_init_act)
 | |
|   , garbage_frac     (opt_garbage_frac)
 | |
|   , min_learnts_lim  (opt_min_learnts_lim)
 | |
|   , restart_first    (opt_restart_first)
 | |
|   , restart_inc      (opt_restart_inc)
 | |
| 
 | |
|     // Parameters (the rest):
 | |
|     //
 | |
|   , learntsize_factor((double)1/(double)3), learntsize_inc(1.1)
 | |
| 
 | |
|     // Parameters (experimental):
 | |
|     //
 | |
|   , learntsize_adjust_start_confl (100)
 | |
|   , learntsize_adjust_inc         (1.5)
 | |
| 
 | |
|     // Statistics: (formerly in 'SolverStats')
 | |
|     //
 | |
|   , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
 | |
|   , dec_vars(0), num_clauses(0), num_learnts(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
 | |
| 
 | |
|   , watches            (WatcherDeleted(ca))
 | |
|   , order_heap         (VarOrderLt(activity))
 | |
|   , ok                 (true)
 | |
|   , cla_inc            (1)
 | |
|   , var_inc            (1)
 | |
|   , qhead              (0)
 | |
|   , simpDB_assigns     (-1)
 | |
|   , simpDB_props       (0)
 | |
|   , progress_estimate  (0)
 | |
|   , remove_satisfied   (true)
 | |
|   , next_var           (0)
 | |
| 
 | |
|     // Resource constraints:
 | |
|     //
 | |
|   , conflict_budget    (-1)
 | |
|   , propagation_budget (-1)
 | |
|   , asynch_interrupt   (false)
 | |
| {}
 | |
| 
 | |
| 
 | |
| Solver::~Solver()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| //=================================================================================================
 | |
| // Minor methods:
 | |
| 
 | |
| 
 | |
| // Creates a new SAT variable in the solver. If 'decision' 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(lbool upol, bool dvar)
 | |
| {
 | |
|     Var v;
 | |
|     if (free_vars.size() > 0){
 | |
|         v = free_vars.last();
 | |
|         free_vars.pop();
 | |
|     }else
 | |
|         v = next_var++;
 | |
| 
 | |
|     watches  .init(mkLit(v, false));
 | |
|     watches  .init(mkLit(v, true ));
 | |
|     assigns  .insert(v, l_Undef);
 | |
|     vardata  .insert(v, mkVarData(CRef_Undef, 0));
 | |
|     activity .insert(v, rnd_init_act ? drand(random_seed) * 0.00001 : 0);
 | |
|     seen     .insert(v, 0);
 | |
|     polarity .insert(v, true);
 | |
|     user_pol .insert(v, upol);
 | |
|     decision .reserve(v);
 | |
|     trail    .capacity(v+1);
 | |
|     setDecisionVar(v, dvar);
 | |
|     return v;
 | |
| }
 | |
| 
 | |
| 
 | |
| // Note: at the moment, only unassigned variable will be released (this is to avoid duplicate
 | |
| // releases of the same variable).
 | |
| void Solver::releaseVar(Lit l)
 | |
| {
 | |
|     if (value(l) == l_Undef){
 | |
|         addClause(l);
 | |
|         released_vars.push(var(l));
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool Solver::addClause_(vec<Lit>& ps)
 | |
| {
 | |
|     assert(decisionLevel() == 0);
 | |
|     if (!ok) return false;
 | |
| 
 | |
|     // 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){
 | |
|         uncheckedEnqueue(ps[0]);
 | |
|         return ok = (propagate() == CRef_Undef);
 | |
|     }else{
 | |
|         CRef cr = ca.alloc(ps, false);
 | |
|         clauses.push(cr);
 | |
|         attachClause(cr);
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::attachClause(CRef cr){
 | |
|     const Clause& c = ca[cr];
 | |
|     assert(c.size() > 1);
 | |
|     watches[~c[0]].push(Watcher(cr, c[1]));
 | |
|     watches[~c[1]].push(Watcher(cr, c[0]));
 | |
|     if (c.learnt()) num_learnts++, learnts_literals += c.size();
 | |
|     else            num_clauses++, clauses_literals += c.size();
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::detachClause(CRef cr, bool strict){
 | |
|     const Clause& c = ca[cr];
 | |
|     assert(c.size() > 1);
 | |
|     
 | |
|     // Strict or lazy detaching:
 | |
|     if (strict){
 | |
|         remove(watches[~c[0]], Watcher(cr, c[1]));
 | |
|         remove(watches[~c[1]], Watcher(cr, c[0]));
 | |
|     }else{
 | |
|         watches.smudge(~c[0]);
 | |
|         watches.smudge(~c[1]);
 | |
|     }
 | |
| 
 | |
|     if (c.learnt()) num_learnts--, learnts_literals -= c.size();
 | |
|     else            num_clauses--, clauses_literals -= c.size();
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::removeClause(CRef cr) {
 | |
|     Clause& c = ca[cr];
 | |
|     detachClause(cr);
 | |
|     // Don't leave pointers to free'd memory!
 | |
|     if (locked(c)) vardata[var(c[0])].reason = CRef_Undef;
 | |
|     c.mark(1); 
 | |
|     ca.free(cr);
 | |
| }
 | |
| 
 | |
| 
 | |
| 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] = l_Undef;
 | |
|             if (phase_saving > 1 || (phase_saving == 1 && c > trail_lim.last()))
 | |
|                 polarity[x] = sign(trail[c]);
 | |
|             insertVarOrder(x); }
 | |
|         qhead = trail_lim[level];
 | |
|         trail.shrink(trail.size() - trail_lim[level]);
 | |
|         trail_lim.shrink(trail_lim.size() - level);
 | |
|     } }
 | |
| 
 | |
| 
 | |
| //=================================================================================================
 | |
| // Major methods:
 | |
| 
 | |
| 
 | |
| Lit Solver::pickBranchLit()
 | |
| {
 | |
|     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 (value(next) == l_Undef && decision[next])
 | |
|             rnd_decisions++; }
 | |
| 
 | |
|     // Activity based decision:
 | |
|     while (next == var_Undef || value(next) != l_Undef || !decision[next])
 | |
|         if (order_heap.empty()){
 | |
|             next = var_Undef;
 | |
|             break;
 | |
|         }else
 | |
|             next = order_heap.removeMin();
 | |
| 
 | |
|     // Choose polarity based on different polarity modes (global or per-variable):
 | |
|     if (next == var_Undef)
 | |
|         return lit_Undef;
 | |
|     else if (user_pol[next] != l_Undef)
 | |
|         return mkLit(next, user_pol[next] == l_True);
 | |
|     else if (rnd_pol)
 | |
|         return mkLit(next, drand(random_seed) < 0.5);
 | |
|     else
 | |
|         return mkLit(next, polarity[next]);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*_________________________________________________________________________________________________
 | |
| |
 | |
| |  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'.
 | |
| |      * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the 
 | |
| |        rest of literals. There may be others from the same level though.
 | |
| |  
 | |
| |________________________________________________________________________________________________@*/
 | |
| void Solver::analyze(CRef 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;
 | |
| 
 | |
|     do{
 | |
|         assert(confl != CRef_Undef); // (otherwise should be UIP)
 | |
|         Clause& c = ca[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);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         // 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;
 | |
|     out_learnt.copyTo(analyze_toclear);
 | |
|     if (ccmin_mode == 2){
 | |
|         for (i = j = 1; i < out_learnt.size(); i++)
 | |
|             if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i]))
 | |
|                 out_learnt[j++] = out_learnt[i];
 | |
|         
 | |
|     }else if (ccmin_mode == 1){
 | |
|         for (i = j = 1; i < out_learnt.size(); i++){
 | |
|             Var x = var(out_learnt[i]);
 | |
| 
 | |
|             if (reason(x) == CRef_Undef)
 | |
|                 out_learnt[j++] = out_learnt[i];
 | |
|             else{
 | |
|                 Clause& c = ca[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; }
 | |
|             }
 | |
|         }
 | |
|     }else
 | |
|         i = j = out_learnt.size();
 | |
| 
 | |
|     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;
 | |
|         // Find the first literal assigned at the next-highest level:
 | |
|         for (int i = 2; i < out_learnt.size(); i++)
 | |
|             if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
 | |
|                 max_i = i;
 | |
|         // Swap-in this literal at index 1:
 | |
|         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 from a conflict clause.
 | |
| bool Solver::litRedundant(Lit p)
 | |
| {
 | |
|     enum { seen_undef = 0, seen_source = 1, seen_removable = 2, seen_failed = 3 };
 | |
|     assert(seen[var(p)] == seen_undef || seen[var(p)] == seen_source);
 | |
|     assert(reason(var(p)) != CRef_Undef);
 | |
| 
 | |
|     Clause*               c     = &ca[reason(var(p))];
 | |
|     vec<ShrinkStackElem>& stack = analyze_stack;
 | |
|     stack.clear();
 | |
| 
 | |
|     for (uint32_t i = 1; ; i++){
 | |
|         if (i < (uint32_t)c->size()){
 | |
|             // Checking 'p'-parents 'l':
 | |
|             Lit l = (*c)[i];
 | |
|             
 | |
|             // Variable at level 0 or previously removable:
 | |
|             if (level(var(l)) == 0 || seen[var(l)] == seen_source || seen[var(l)] == seen_removable){
 | |
|                 continue; }
 | |
|             
 | |
|             // Check variable can not be removed for some local reason:
 | |
|             if (reason(var(l)) == CRef_Undef || seen[var(l)] == seen_failed){
 | |
|                 stack.push(ShrinkStackElem(0, p));
 | |
|                 for (int i = 0; i < stack.size(); i++)
 | |
|                     if (seen[var(stack[i].l)] == seen_undef){
 | |
|                         seen[var(stack[i].l)] = seen_failed;
 | |
|                         analyze_toclear.push(stack[i].l);
 | |
|                     }
 | |
|                     
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             // Recursively check 'l':
 | |
|             stack.push(ShrinkStackElem(i, p));
 | |
|             i  = 0;
 | |
|             p  = l;
 | |
|             c  = &ca[reason(var(p))];
 | |
|         }else{
 | |
|             // Finished with current element 'p' and reason 'c':
 | |
|             if (seen[var(p)] == seen_undef){
 | |
|                 seen[var(p)] = seen_removable;
 | |
|                 analyze_toclear.push(p);
 | |
|             }
 | |
| 
 | |
|             // Terminate with success if stack is empty:
 | |
|             if (stack.size() == 0) break;
 | |
|             
 | |
|             // Continue with top element on stack:
 | |
|             i  = stack.last().i;
 | |
|             p  = stack.last().l;
 | |
|             c  = &ca[reason(var(p))];
 | |
| 
 | |
|             stack.pop();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     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, LSet& out_conflict)
 | |
| {
 | |
|     out_conflict.clear();
 | |
|     out_conflict.insert(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) == CRef_Undef){
 | |
|                 assert(level(x) > 0);
 | |
|                 out_conflict.insert(~trail[i]);
 | |
|             }else{
 | |
|                 Clause& c = ca[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, CRef from)
 | |
| {
 | |
|     assert(value(p) == l_Undef);
 | |
|     assigns[var(p)] = lbool(!sign(p));
 | |
|     vardata[var(p)] = mkVarData(from, decisionLevel());
 | |
|     trail.push_(p);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*_________________________________________________________________________________________________
 | |
| |
 | |
| |  propagate : [void]  ->  [Clause*]
 | |
| |  
 | |
| |  Description:
 | |
| |    Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
 | |
| |    otherwise CRef_Undef.
 | |
| |  
 | |
| |    Post-conditions:
 | |
| |      * the propagation queue is empty, even if there was a conflict.
 | |
| |________________________________________________________________________________________________@*/
 | |
| CRef Solver::propagate()
 | |
| {
 | |
|     CRef    confl     = CRef_Undef;
 | |
|     int     num_props = 0;
 | |
| 
 | |
|     while (qhead < trail.size()){
 | |
|         Lit            p   = trail[qhead++];     // 'p' is enqueued fact to propagate.
 | |
|         vec<Watcher>&  ws  = watches.lookup(p);
 | |
|         Watcher        *i, *j, *end;
 | |
|         num_props++;
 | |
| 
 | |
|         for (i = j = (Watcher*)ws, end = i + ws.size();  i != end;){
 | |
|             // Try to avoid inspecting the clause:
 | |
|             Lit blocker = i->blocker;
 | |
|             if (value(blocker) == l_True){
 | |
|                 *j++ = *i++; continue; }
 | |
| 
 | |
|             // Make sure the false literal is data[1]:
 | |
|             CRef     cr        = i->cref;
 | |
|             Clause&  c         = ca[cr];
 | |
|             Lit      false_lit = ~p;
 | |
|             if (c[0] == false_lit)
 | |
|                 c[0] = c[1], c[1] = false_lit;
 | |
|             assert(c[1] == false_lit);
 | |
|             i++;
 | |
| 
 | |
|             // If 0th watch is true, then clause is already satisfied.
 | |
|             Lit     first = c[0];
 | |
|             Watcher w     = Watcher(cr, first);
 | |
|             if (first != blocker && value(first) == l_True){
 | |
|                 *j++ = w; continue; }
 | |
| 
 | |
|             // 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[~c[1]].push(w);
 | |
|                     goto NextClause; }
 | |
| 
 | |
|             // Did not find watch -- clause is unit under assignment:
 | |
|             *j++ = w;
 | |
|             if (value(first) == l_False){
 | |
|                 confl = cr;
 | |
|                 qhead = trail.size();
 | |
|                 // Copy the remaining watches:
 | |
|                 while (i < end)
 | |
|                     *j++ = *i++;
 | |
|             }else
 | |
|                 uncheckedEnqueue(first, cr);
 | |
| 
 | |
|         NextClause:;
 | |
|         }
 | |
|         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 { 
 | |
|     ClauseAllocator& ca;
 | |
|     reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
 | |
|     bool operator () (CRef x, CRef y) { 
 | |
|         return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[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(ca));
 | |
|     // Don't delete binary or locked clauses. From the rest, delete clauses from the first half
 | |
|     // and clauses with activity smaller than 'extra_lim':
 | |
|     for (i = j = 0; i < learnts.size(); i++){
 | |
|         Clause& c = ca[learnts[i]];
 | |
|         if (c.size() > 2 && !locked(c) && (i < learnts.size() / 2 || c.activity() < extra_lim))
 | |
|             removeClause(learnts[i]);
 | |
|         else
 | |
|             learnts[j++] = learnts[i];
 | |
|     }
 | |
|     learnts.shrink(i - j);
 | |
|     checkGarbage();
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::removeSatisfied(vec<CRef>& cs)
 | |
| {
 | |
|     int i, j;
 | |
|     for (i = j = 0; i < cs.size(); i++){
 | |
|         Clause& c = ca[cs[i]];
 | |
|         if (satisfied(c))
 | |
|             removeClause(cs[i]);
 | |
|         else{
 | |
|             // Trim clause:
 | |
|             assert(value(c[0]) == l_Undef && value(c[1]) == l_Undef);
 | |
|             for (int k = 2; k < c.size(); k++)
 | |
|                 if (value(c[k]) == l_False){
 | |
|                     c[k--] = c[c.size()-1];
 | |
|                     c.pop();
 | |
|                 }
 | |
|             cs[j++] = cs[i];
 | |
|         }
 | |
|     }
 | |
|     cs.shrink(i - j);
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::rebuildOrderHeap()
 | |
| {
 | |
|     vec<Var> vs;
 | |
|     for (Var v = 0; v < nVars(); v++)
 | |
|         if (decision[v] && value(v) == l_Undef)
 | |
|             vs.push(v);
 | |
|     order_heap.build(vs);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*_________________________________________________________________________________________________
 | |
| |
 | |
| |  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() != CRef_Undef)
 | |
|         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);
 | |
| 
 | |
|         // TODO: what todo in if 'remove_satisfied' is false?
 | |
| 
 | |
|         // Remove all released variables from the trail:
 | |
|         for (int i = 0; i < released_vars.size(); i++){
 | |
|             assert(seen[released_vars[i]] == 0);
 | |
|             seen[released_vars[i]] = 1;
 | |
|         }
 | |
| 
 | |
|         int i, j;
 | |
|         for (i = j = 0; i < trail.size(); i++)
 | |
|             if (seen[var(trail[i])] == 0)
 | |
|                 trail[j++] = trail[i];
 | |
|         trail.shrink(i - j);
 | |
|         //printf("trail.size()= %d, qhead = %d\n", trail.size(), qhead);
 | |
|         qhead = trail.size();
 | |
| 
 | |
|         for (int i = 0; i < released_vars.size(); i++)
 | |
|             seen[released_vars[i]] = 0;
 | |
| 
 | |
|         // Released variables are now ready to be reused:
 | |
|         append(released_vars, free_vars);
 | |
|         released_vars.clear();
 | |
|     }
 | |
|     checkGarbage();
 | |
|     rebuildOrderHeap();
 | |
| 
 | |
|     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) (params : const SearchParams&)  ->  [lbool]
 | |
| |  
 | |
| |  Description:
 | |
| |    Search for a model the specified number of conflicts. 
 | |
| |    NOTE! Use negative value for 'nof_conflicts' 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)
 | |
| {
 | |
|     assert(ok);
 | |
|     int         backtrack_level;
 | |
|     int         conflictC = 0;
 | |
|     vec<Lit>    learnt_clause;
 | |
|     starts++;
 | |
| 
 | |
|     for (;;){
 | |
|         CRef confl = propagate();
 | |
|         if (confl != CRef_Undef){
 | |
|             // CONFLICT
 | |
|             conflicts++; conflictC++;
 | |
|             if (decisionLevel() == 0) return l_False;
 | |
| 
 | |
|             learnt_clause.clear();
 | |
|             analyze(confl, learnt_clause, backtrack_level);
 | |
|             cancelUntil(backtrack_level);
 | |
| 
 | |
|             if (learnt_clause.size() == 1){
 | |
|                 uncheckedEnqueue(learnt_clause[0]);
 | |
|             }else{
 | |
|                 CRef cr = ca.alloc(learnt_clause, true);
 | |
|                 learnts.push(cr);
 | |
|                 attachClause(cr);
 | |
|                 claBumpActivity(ca[cr]);
 | |
|                 uncheckedEnqueue(learnt_clause[0], cr);
 | |
|             }
 | |
| 
 | |
|             varDecayActivity();
 | |
|             claDecayActivity();
 | |
| 
 | |
|             if (--learntsize_adjust_cnt == 0){
 | |
|                 learntsize_adjust_confl *= learntsize_adjust_inc;
 | |
|                 learntsize_adjust_cnt    = (int)learntsize_adjust_confl;
 | |
|                 max_learnts             *= learntsize_inc;
 | |
| 
 | |
|                 if (verbosity >= 1)
 | |
|                     printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", 
 | |
|                            (int)conflicts, 
 | |
|                            (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals, 
 | |
|                            (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100);
 | |
|             }
 | |
| 
 | |
|         }else{
 | |
|             // NO CONFLICT
 | |
|             if ((nof_conflicts >= 0 && conflictC >= nof_conflicts) || !withinBudget()){
 | |
|                 // 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 (learnts.size()-nAssigns() >= max_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++;
 | |
|                 next = pickBranchLit();
 | |
| 
 | |
|                 if (next == lit_Undef)
 | |
|                     // Model found:
 | |
|                     return l_True;
 | |
|             }
 | |
| 
 | |
|             // Increase decision level and enqueue 'next'
 | |
|             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();
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Finite subsequences of the Luby-sequence:
 | |
| 
 | |
|   0: 1
 | |
|   1: 1 1 2
 | |
|   2: 1 1 2 1 1 2 4
 | |
|   3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8
 | |
|   ...
 | |
| 
 | |
| 
 | |
|  */
 | |
| 
 | |
| static double luby(double y, int x){
 | |
| 
 | |
|     // Find the finite subsequence that contains index 'x', and the
 | |
|     // size of that subsequence:
 | |
|     int size, seq;
 | |
|     for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1);
 | |
| 
 | |
|     while (size-1 != x){
 | |
|         size = (size-1)>>1;
 | |
|         seq--;
 | |
|         x = x % size;
 | |
|     }
 | |
| 
 | |
|     return pow(y, seq);
 | |
| }
 | |
| 
 | |
| // NOTE: assumptions passed in member-variable 'assumptions'.
 | |
| lbool Solver::solve_()
 | |
| {
 | |
|     model.clear();
 | |
|     conflict.clear();
 | |
|     if (!ok) return l_False;
 | |
| 
 | |
|     solves++;
 | |
| 
 | |
|     max_learnts = nClauses() * learntsize_factor;
 | |
|     if (max_learnts < min_learnts_lim)
 | |
|         max_learnts = min_learnts_lim;
 | |
| 
 | |
|     learntsize_adjust_confl   = learntsize_adjust_start_confl;
 | |
|     learntsize_adjust_cnt     = (int)learntsize_adjust_confl;
 | |
|     lbool   status            = l_Undef;
 | |
| 
 | |
|     if (verbosity >= 1){
 | |
|         printf("============================[ Search Statistics ]==============================\n");
 | |
|         printf("| Conflicts |          ORIGINAL         |          LEARNT          | Progress |\n");
 | |
|         printf("|           |    Vars  Clauses Literals |    Limit  Clauses Lit/Cl |          |\n");
 | |
|         printf("===============================================================================\n");
 | |
|     }
 | |
| 
 | |
|     // Search:
 | |
|     int curr_restarts = 0;
 | |
|     while (status == l_Undef){
 | |
|         double rest_base = luby_restart ? luby(restart_inc, curr_restarts) : pow(restart_inc, curr_restarts);
 | |
|         status = search(rest_base * restart_first);
 | |
|         if (!withinBudget()) break;
 | |
|         curr_restarts++;
 | |
|     }
 | |
| 
 | |
|     if (verbosity >= 1)
 | |
|         printf("===============================================================================\n");
 | |
| 
 | |
| 
 | |
|     if (status == l_True){
 | |
|         // Extend & copy model:
 | |
|         model.growTo(nVars());
 | |
|         for (int i = 0; i < nVars(); i++) model[i] = value(i);
 | |
|     }else if (status == l_False && conflict.size() == 0)
 | |
|         ok = false;
 | |
| 
 | |
|     cancelUntil(0);
 | |
|     return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool Solver::implies(const vec<Lit>& assumps, vec<Lit>& out)
 | |
| {
 | |
|     trail_lim.push(trail.size());
 | |
|     for (int i = 0; i < assumps.size(); i++){
 | |
|         Lit a = assumps[i];
 | |
| 
 | |
|         if (value(a) == l_False){
 | |
|             cancelUntil(0);
 | |
|             return false;
 | |
|         }else if (value(a) == l_Undef)
 | |
|             uncheckedEnqueue(a);
 | |
|     }
 | |
| 
 | |
|     unsigned trail_before = trail.size();
 | |
|     bool     ret          = true;
 | |
|     if (propagate() == CRef_Undef){
 | |
|         out.clear();
 | |
|         for (int j = trail_before; j < trail.size(); j++)
 | |
|             out.push(trail[j]);
 | |
|     }else
 | |
|         ret = false;
 | |
|     
 | |
|     cancelUntil(0);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| //=================================================================================================
 | |
| // Writing CNF to DIMACS:
 | |
| // 
 | |
| // FIXME: this needs to be rewritten completely.
 | |
| 
 | |
| static Var mapVar(Var x, vec<Var>& map, Var& max)
 | |
| {
 | |
|     if (map.size() <= x || map[x] == -1){
 | |
|         map.growTo(x+1, -1);
 | |
|         map[x] = max++;
 | |
|     }
 | |
|     return map[x];
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max)
 | |
| {
 | |
|     if (satisfied(c)) return;
 | |
| 
 | |
|     for (int i = 0; i < c.size(); i++)
 | |
|         if (value(c[i]) != l_False)
 | |
|             fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1);
 | |
|     fprintf(f, "0\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::toDimacs(const char *file, const vec<Lit>& assumps)
 | |
| {
 | |
|     FILE* f = fopen(file, "wr");
 | |
|     if (f == NULL)
 | |
|         fprintf(stderr, "could not open file %s\n", file), exit(1);
 | |
|     toDimacs(f, assumps);
 | |
|     fclose(f);
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::toDimacs(FILE* f, const vec<Lit>& assumps)
 | |
| {
 | |
|     // Handle case when solver is in contradictory state:
 | |
|     if (!ok){
 | |
|         fprintf(f, "p cnf 1 2\n1 0\n-1 0\n");
 | |
|         return; }
 | |
| 
 | |
|     vec<Var> map; Var max = 0;
 | |
| 
 | |
|     // Cannot use removeClauses here because it is not safe
 | |
|     // to deallocate them at this point. Could be improved.
 | |
|     int cnt = 0;
 | |
|     for (int i = 0; i < clauses.size(); i++)
 | |
|         if (!satisfied(ca[clauses[i]]))
 | |
|             cnt++;
 | |
|         
 | |
|     for (int i = 0; i < clauses.size(); i++)
 | |
|         if (!satisfied(ca[clauses[i]])){
 | |
|             Clause& c = ca[clauses[i]];
 | |
|             for (int j = 0; j < c.size(); j++)
 | |
|                 if (value(c[j]) != l_False)
 | |
|                     mapVar(var(c[j]), map, max);
 | |
|         }
 | |
| 
 | |
|     // Assumptions are added as unit clauses:
 | |
|     cnt += assumps.size();
 | |
| 
 | |
|     fprintf(f, "p cnf %d %d\n", max, cnt);
 | |
| 
 | |
|     for (int i = 0; i < assumps.size(); i++){
 | |
|         assert(value(assumps[i]) != l_False);
 | |
|         fprintf(f, "%s%d 0\n", sign(assumps[i]) ? "-" : "", mapVar(var(assumps[i]), map, max)+1);
 | |
|     }
 | |
| 
 | |
|     for (int i = 0; i < clauses.size(); i++)
 | |
|         toDimacs(f, ca[clauses[i]], map, max);
 | |
| 
 | |
|     if (verbosity > 0)
 | |
|         printf("Wrote DIMACS with %d variables and %d clauses.\n", max, cnt);
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::printStats() const
 | |
| {
 | |
|     double cpu_time = cpuTime();
 | |
|     double mem_used = memUsedPeak();
 | |
|     printf("restarts              : %" PRIu64 "\n", starts);
 | |
|     printf("conflicts             : %-12" PRIu64 "   (%.0f /sec)\n", conflicts   , conflicts   /cpu_time);
 | |
|     printf("decisions             : %-12" PRIu64 "   (%4.2f %% random) (%.0f /sec)\n", decisions, (float)rnd_decisions*100 / (float)decisions, decisions   /cpu_time);
 | |
|     printf("propagations          : %-12" PRIu64 "   (%.0f /sec)\n", propagations, propagations/cpu_time);
 | |
|     printf("conflict literals     : %-12" PRIu64 "   (%4.2f %% deleted)\n", tot_literals, (max_literals - tot_literals)*100 / (double)max_literals);
 | |
|     if (mem_used != 0) printf("Memory used           : %.2f MB\n", mem_used);
 | |
|     printf("CPU time              : %g s\n", cpu_time);
 | |
| }
 | |
| 
 | |
| 
 | |
| //=================================================================================================
 | |
| // Garbage Collection methods:
 | |
| 
 | |
| void Solver::relocAll(ClauseAllocator& to)
 | |
| {
 | |
|     // All watchers:
 | |
|     //
 | |
|     watches.cleanAll();
 | |
|     for (int v = 0; v < nVars(); v++)
 | |
|         for (int s = 0; s < 2; s++){
 | |
|             Lit p = mkLit(v, s);
 | |
|             vec<Watcher>& ws = watches[p];
 | |
|             for (int j = 0; j < ws.size(); j++)
 | |
|                 ca.reloc(ws[j].cref, to);
 | |
|         }
 | |
| 
 | |
|     // All reasons:
 | |
|     //
 | |
|     for (int i = 0; i < trail.size(); i++){
 | |
|         Var v = var(trail[i]);
 | |
| 
 | |
|         // Note: it is not safe to call 'locked()' on a relocated clause. This is why we keep
 | |
|         // 'dangling' reasons here. It is safe and does not hurt.
 | |
|         if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)]))){
 | |
|             assert(!isRemoved(reason(v)));
 | |
|             ca.reloc(vardata[v].reason, to);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // All learnt:
 | |
|     //
 | |
|     int i, j;
 | |
|     for (i = j = 0; i < learnts.size(); i++)
 | |
|         if (!isRemoved(learnts[i])){
 | |
|             ca.reloc(learnts[i], to);
 | |
|             learnts[j++] = learnts[i];
 | |
|         }
 | |
|     learnts.shrink(i - j);
 | |
| 
 | |
|     // All original:
 | |
|     //
 | |
|     for (i = j = 0; i < clauses.size(); i++)
 | |
|         if (!isRemoved(clauses[i])){
 | |
|             ca.reloc(clauses[i], to);
 | |
|             clauses[j++] = clauses[i];
 | |
|         }
 | |
|     clauses.shrink(i - j);
 | |
| }
 | |
| 
 | |
| 
 | |
| void Solver::garbageCollect()
 | |
| {
 | |
|     // Initialize the next region to a size corresponding to the estimated utilization degree. This
 | |
|     // is not precise but should avoid some unnecessary reallocations for the new region:
 | |
|     ClauseAllocator to(ca.size() - ca.wasted()); 
 | |
| 
 | |
|     relocAll(to);
 | |
|     if (verbosity >= 2)
 | |
|         printf("|  Garbage collection:   %12d bytes => %12d bytes             |\n", 
 | |
|                ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
 | |
|     to.moveTo(ca);
 | |
| }
 |