A branching heuristic for SAT solvers based on complete implication graphs
Xiao, F., Li, C., Luo, M. et al. A branching heuristic for SAT solvers based on complete implication graphs. Sci. China Inf. Sci. 62, 72103 (2019). https://doi.org/10.1007/s11432-017-9467-7
除了VSIDS和LRB之外,新的决策变元选择(活跃度)策略——基于activity_distance[v]
Abstract
The performance of modern conflict-driven clause learning (CDCL) SAT solvers strongly depends on branching heuristics. State-of-the-art branching heuristics, such as variable state independent decaying sum (VSIDS) and learning rate branching (LRB), are computed and maintained by aggregating the occurrences of the variables in conflicts. However, these heuristics are not sufficiently accurate at the beginning of the search because they are based on very few conflicts.
We propose the distance branching heuristic, which, given a conflict, constructs a complete implication graph and increments the score of a variable considering the longest distance between the variable and the conflict rather than the simple presence of the variable in the graph. 译文:给定一个冲突,构造一个完整的隐含图,并考虑变量与冲突之间的最长距离,而不是简单地考虑变量在图中的存在,增加变量的得分。
We implemented the proposed distance branching heuristic in Maple_LCM and Glucose-3.0, two of the best CDCL SAT solvers, and used the resulting solvers to solve instances from the application and crafted tracks of the 2014 and 2016 SAT competitions and the main track of the 2017 SAT competition. The empirical results demonstrate that using the proposed distance branching heuristic in the initialization phase of Maple_LCM and Glucose-3.0 solvers improves performance. The Maple_LCM solver with the proposed distance branching heuristic in the initialization phase won the main track of the 2017 SAT competition. |
notes
1.新的思考和改进
2017, Fan Xiao, Chu-Min LI, Mao Luo: using a new branching heuristic called Distance at the beginning of search |
2.代码实现
1.Maple_LCM_Dist, Based on Maple_LCM 新增的数据和函数
在Solver.h文件中新定义的数据成员 |
vec<double> activity_CHB, // A heuristic measurement of the activity of a variable. Heap<VarOrderLt> order_heap_CHB, // A priority queue of variables ordered with respect to the variable activity. public:
bool collectFirstUIP(CRef confl); //计算蕴含图中文字变元距离冲突点路径长度的函数
|
1 inline void Solver::insertVarOrder(Var x) { 2 // Heap<VarOrderLt>& order_heap = VSIDS ? order_heap_VSIDS : order_heap_CHB; 3 Heap<VarOrderLt>& order_heap = DISTANCE ? order_heap_distance : ((!VSIDS)? order_heap_CHB:order_heap_VSIDS); 4 if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); 5 } 三类活跃度对应三类堆,通过两个策略模式DISTANCE和VSIDS进行切换 |
1 inline void Solver::setDecisionVar(Var v, bool b) 2 { 3 if ( b && !decision[v]) dec_vars++; 4 else if (!b && decision[v]) dec_vars--; 5 6 decision[v] = b; 7 if (b && !order_heap_CHB.inHeap(v)){ 8 order_heap_CHB.insert(v); 9 order_heap_VSIDS.insert(v); 10 order_heap_distance.insert(v);} 11 }
|
Solver.cc中新增(或改进)的代码 |
构造函数中
, my_var_decay (0.6) |
在Var Solver::newVar(bool sign, bool dvar)函数中,新增与变元对应的向量初值 activity_distance.push(0); |
在pickBranchLit函数中改动了一行代码,增加了第三类活跃度供作为变元活跃度的选择依据。 1 Lit Solver::pickBranchLit() 2 { 3 Var next = var_Undef; 4 // Heap<VarOrderLt>& order_heap = VSIDS ? order_heap_VSIDS : order_heap_CHB; 5 Heap<VarOrderLt>& order_heap = DISTANCE ? order_heap_distance : ((!VSIDS)? order_heap_CHB:order_heap_VSIDS); 6 7 // Random decision: 8 /*if (drand(random_seed) < random_var_freq && !order_heap.empty()){ 9 next = order_heap[irand(random_seed,order_heap.size())]; 10 if (value(next) == l_Undef && decision[next]) 11 rnd_decisions++; }*/ 12 13 // Activity based decision: 14 while (next == var_Undef || value(next) != l_Undef || !decision[next]) 15 if (order_heap.empty()) 16 return lit_Undef; 17 else{ 18 #ifdef ANTI_EXPLORATION 19 if (!VSIDS){ 20 Var v = order_heap_CHB[0]; 21 uint32_t age = conflicts - canceled[v]; 22 while (age > 0){ 23 double decay = pow(0.95, age); 24 activity_CHB[v] *= decay; 25 if (order_heap_CHB.inHeap(v)) 26 order_heap_CHB.increase(v); 27 canceled[v] = conflicts; 28 v = order_heap_CHB[0]; 29 age = conflicts - canceled[v]; 30 } 31 } 32 #endif 33 next = order_heap.removeMin(); 34 } 35 36 return mkLit(next, polarity[next]); 37 }
|
重建堆(决策变元陆续被从堆中选出就不在堆中了,重启之后需要重建堆) 1 void Solver::rebuildOrderHeap() 2 { 3 vec<Var> vs; 4 for (Var v = 0; v < nVars(); v++) 5 if (decision[v] && value(v) == l_Undef) 6 vs.push(v); 7 8 order_heap_CHB .build(vs); 9 order_heap_VSIDS.build(vs); 10 order_heap_distance.build(vs); 11 }
|
新增以下三段代码(两个函数、一个结构体定义) 1 // pathCs[k] is the number of variables assigned at level k, 2 // it is initialized to 0 at the begining and reset to 0 after the function execution 3 bool Solver::collectFirstUIP(CRef confl){ 4 involved_lits.clear(); 5 int max_level=1; 6 Clause& c=ca[confl]; int minLevel=decisionLevel(); 7 for(int i=0; i<c.size(); i++) { 8 Var v=var(c[i]); 9 // assert(!seen[v]); 10 if (level(v)>0) { 11 seen[v]=1; 12 var_iLevel_tmp[v]=1; 13 pathCs[level(v)]++; 14 if (minLevel>level(v)) { 15 minLevel=level(v); 16 assert(minLevel>0); 17 } 18 // varBumpActivity(v); 19 } 20 } 21 int limit=trail_lim[minLevel-1]; 22 for(int i=trail.size()-1; i>=limit; i--) { 23 Lit p=trail[i]; Var v=var(p); 24 if (seen[v]) { 25 int currentDecLevel=level(v); 26 // if (currentDecLevel==decisionLevel()) 27 // varBumpActivity(v); 28 seen[v]=0; 29 if (--pathCs[currentDecLevel]!=0) { 30 Clause& rc=ca[reason(v)]; 31 int reasonVarLevel=var_iLevel_tmp[v]+1; 32 if(reasonVarLevel>max_level) max_level=reasonVarLevel; 33 if (rc.size()==2 && value(rc[0])==l_False) { 34 // Special case for binary clauses 35 // The first one has to be SAT 36 assert(value(rc[1]) != l_False); 37 Lit tmp = rc[0]; 38 rc[0] = rc[1], rc[1] = tmp; 39 } 40 for (int j = 1; j < rc.size(); j++){ 41 Lit q = rc[j]; Var v1=var(q); 42 if (level(v1) > 0) { 43 if (minLevel>level(v1)) { 44 minLevel=level(v1); limit=trail_lim[minLevel-1]; assert(minLevel>0); 45 } 46 if (seen[v1]) { 47 if (var_iLevel_tmp[v1]<reasonVarLevel) 48 var_iLevel_tmp[v1]=reasonVarLevel; 49 } 50 else { 51 var_iLevel_tmp[v1]=reasonVarLevel; 52 // varBumpActivity(v1); 53 seen[v1] = 1; 54 pathCs[level(v1)]++; 55 } 56 } 57 } 58 } 59 involved_lits.push(p); 60 } 61 } 62 double inc=var_iLevel_inc; 63 vec<int> level_incs; level_incs.clear(); 64 for(int i=0;i<max_level;i++){ 65 level_incs.push(inc); 66 inc = inc/my_var_decay; 67 } 68 69 for(int i=0;i<involved_lits.size();i++){ 70 Var v =var(involved_lits[i]); 71 // double old_act=activity_distance[v]; 72 // activity_distance[v] +=var_iLevel_inc * var_iLevel_tmp[v]; 73 activity_distance[v]+=var_iLevel_tmp[v]*level_incs[var_iLevel_tmp[v]-1]; 74 75 if(activity_distance[v]>1e100){ 76 for(int vv=0;vv<nVars();vv++) 77 activity_distance[vv] *= 1e-100; 78 var_iLevel_inc*=1e-100; 79 for(int j=0; j<max_level; j++) level_incs[j]*=1e-100; 80 } 81 if (order_heap_distance.inHeap(v)) 82 order_heap_distance.decrease(v); 83 84 // var_iLevel_inc *= (1 / my_var_decay); 85 } 86 var_iLevel_inc=level_incs[level_incs.size()-1]; 87 return true; 88 } 89 90 struct UIPOrderByILevel_Lt { 91 Solver& solver; 92 const vec<double>& var_iLevel; 93 bool operator () (Lit x, Lit y) const 94 { 95 return var_iLevel[var(x)] < var_iLevel[var(y)] || 96 (var_iLevel[var(x)]==var_iLevel[var(y)]&& solver.level(var(x))>solver.level(var(y))); 97 } 98 UIPOrderByILevel_Lt(const vec<double>& iLevel, Solver& para_solver) : solver(para_solver), var_iLevel(iLevel) { } 99 }; 100 101 CRef Solver::propagateLits(vec<Lit>& lits) { 102 Lit lit; 103 int i; 104 105 for(i=lits.size()-1; i>=0; i--) { 106 lit=lits[i]; 107 if (value(lit) == l_Undef) { 108 newDecisionLevel(); 109 uncheckedEnqueue(lit); 110 CRef confl = propagate(); 111 if (confl != CRef_Undef) { 112 return confl; 113 } 114 } 115 } 116 return CRef_Undef; 117 }
|
search函数中增加一段代码——line41~43, 1 lbool Solver::search(int& nof_conflicts) 2 { 3 assert(ok); 4 int backtrack_level; 5 int lbd; 6 vec<Lit> learnt_clause; 7 bool cached = false; 8 starts++; 9 10 // simplify 11 // 12 if (conflicts >= curSimplify * nbconfbeforesimplify){ 13 // printf("c ### simplifyAll on conflict : %lld\n", conflicts); 14 //printf("nbClauses: %d, nbLearnts_core: %d, nbLearnts_tier2: %d, nbLearnts_local: %d, nbLearnts: %d\n", 15 // clauses.size(), learnts_core.size(), learnts_tier2.size(), learnts_local.size(), 16 // learnts_core.size() + learnts_tier2.size() + learnts_local.size()); 17 nbSimplifyAll++; 18 if (!simplifyAll()){ 19 return l_False; 20 } 21 curSimplify = (conflicts / nbconfbeforesimplify) + 1; 22 nbconfbeforesimplify += incSimplify; 23 } 24 25 for (;;){ 26 CRef confl = propagate(); 27 28 if (confl != CRef_Undef){ 29 // CONFLICT 30 if (VSIDS){ 31 if (--timer == 0 && var_decay < 0.95) timer = 5000, var_decay += 0.01; 32 }else 33 if (step_size > min_step_size) step_size -= step_size_dec; 34 35 conflicts++; nof_conflicts--; 36 if (conflicts == 100000 && learnts_core.size() < 100) core_lbd_cut = 5; 37 if (decisionLevel() == 0) return l_False; 38 39 learnt_clause.clear(); 40 if(conflicts>50000) DISTANCE=0; 41 else DISTANCE=1; 42 if(VSIDS && DISTANCE) 43 collectFirstUIP(confl); 44 45 analyze(confl, learnt_clause, backtrack_level, lbd); 46 cancelUntil(backtrack_level); 47 48 lbd--; 49 if (VSIDS){ 50 cached = false; 51 conflicts_VSIDS++; 52 lbd_queue.push(lbd); 53 global_lbd_sum += (lbd > 50 ? 50 : lbd); } 54 55 if (learnt_clause.size() == 1){ 56 uncheckedEnqueue(learnt_clause[0]); 57 }else{ 58 CRef cr = ca.alloc(learnt_clause, true); 59 ca[cr].set_lbd(lbd); 60 if (lbd <= core_lbd_cut){ 61 learnts_core.push(cr); 62 ca[cr].mark(CORE); 63 }else if (lbd <= 6){ 64 learnts_tier2.push(cr); 65 ca[cr].mark(TIER2); 66 ca[cr].touched() = conflicts; 67 }else{ 68 learnts_local.push(cr); 69 claBumpActivity(ca[cr]); } 70 attachClause(cr); 71 uncheckedEnqueue(learnt_clause[0], cr); 72 } 73 if (drup_file){ 74 #ifdef BIN_DRUP 75 binDRUP('a', learnt_clause, drup_file); 76 #else 77 for (int i = 0; i < learnt_clause.size(); i++) 78 fprintf(drup_file, "%i ", (var(learnt_clause[i]) + 1) * (-2 * sign(learnt_clause[i]) + 1)); 79 fprintf(drup_file, "0\n"); 80 #endif 81 } 82 83 if (VSIDS) varDecayActivity(); 84 claDecayActivity(); 85 86 /*if (--learntsize_adjust_cnt == 0){ 87 learntsize_adjust_confl *= learntsize_adjust_inc; 88 learntsize_adjust_cnt = (int)learntsize_adjust_confl; 89 max_learnts *= learntsize_inc; 90 91 if (verbosity >= 1) 92 printf("c | %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", 93 (int)conflicts, 94 (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals, 95 (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100); 96 }*/ 97 98 }else{ 99 // NO CONFLICT 100 bool restart = false; 101 if (!VSIDS) 102 restart = nof_conflicts <= 0; 103 else if (!cached){ 104 restart = lbd_queue.full() && (lbd_queue.avg() * 0.8 > global_lbd_sum / conflicts_VSIDS); 105 cached = true; 106 } 107 if (restart /*|| !withinBudget()*/){ 108 lbd_queue.clear(); 109 cached = false; 110 // Reached bound on number of conflicts: 111 progress_estimate = progressEstimate(); 112 cancelUntil(0); 113 return l_Undef; } 114 115 // Simplify the set of problem clauses: 116 if (decisionLevel() == 0 && !simplify()) 117 return l_False; 118 119 if (conflicts >= next_T2_reduce){ 120 next_T2_reduce = conflicts + 10000; 121 reduceDB_Tier2(); } 122 if (conflicts >= next_L_reduce){ 123 next_L_reduce = conflicts + 15000; 124 reduceDB(); } 125 126 Lit next = lit_Undef; 127 /*while (decisionLevel() < assumptions.size()){ 128 // Perform user provided assumption: 129 Lit p = assumptions[decisionLevel()]; 130 if (value(p) == l_True){ 131 // Dummy decision level: 132 newDecisionLevel(); 133 }else if (value(p) == l_False){ 134 analyzeFinal(~p, conflict); 135 return l_False; 136 }else{ 137 next = p; 138 break; 139 } 140 } 141 142 if (next == lit_Undef)*/{ 143 // New variable decision: 144 decisions++; 145 next = pickBranchLit(); 146 147 if (next == lit_Undef) 148 // Model found: 149 return l_True; 150 } 151 152 // Increase decision level and enqueue 'next' 153 newDecisionLevel(); 154 uncheckedEnqueue(next); 155 } 156 } 157 }
|
注意:在solve_函数中没有任何选择使用Distance策略的信息。 |
References
- 1
Audemard G, Simon L. Glucose 2.3 in the SAT 2013 competition. In: Proceedings of SAT Competition, 2013. 42–43
- 2
Biere A. Lingeling, Plingeling, Picosat and Precosat at SAT Race 2010. FMV Report Series, Technical Report 10/1, 2010
- 3
Eén N, Sorensson N. An extensible SAT solver. In: Proceedings of SAT, 2003. 502–518
- 4
Marques-Silva J, Sakallah K A. GRASP — a new search algorithm for satisfiability. In: Proceedings of the International Conference on Computer-Aided Design, 1996. 220–227
- 5
Moskewicz M, Madigan C, Zhao Y, et al. Chaff: engineering an efficient SAT solver. In: Proceedings of the Design Automation Conference, 2001. 530–535
- 6
Soos M. CryptoMiniSat v4. In: Proceedings of SAT Competition, 2014. 23
- 7
Marques-Silva J, Lynce I, Malik S. Conflict-driven clause learning SAT solvers. In: Handbook of Satisfiability. Washington: IOS Press, 2009. 131–153
- 8
Liang J H, Ganesh V, Poupart P, et al. Exponential recency weighted average branching heuristic for SAT solvers. In: Proceedings of AAAI, 2016. 3434–3440
- 9
Audemard G, Simon L. Predicting learnt clauses quality in modern SAT solvers. In: Proceedings of IJCAI, 2009. 399–404
- 10
Luo M, Li C M, Xiao F, et al. An effective learnt clause minimization approach for CDCL SAT solvers. In: Proceedings of IJCAI, 2017. 703–711
- 11
Xiao F, Luo M, Li C M, et al. MapleLRB LCM, Maple_LCM, Maple_LCM_Dist, MapleLRB_LCMoccRestart and Glucose-3.0+width in SAT Competition 2017. In: Proceedings of SAT Competition, 2017. 22–23
- 12
Audemard G, Simon L. Refining restarts strategies for SAT and UNSAT. In: Proceedings of International Conference on Principles and Practice of Constraint Programming, 2012. 118–126
- 13
Biere A, Förhlich A. Evaluating CDCL variable scoring schemes. In: Proceedings of SAT, 2015. 405–422
- 14
Goldberg E, Novikov Y. BerkMin: a fast and robust Sat-solver. Discrete Appl Math, 2007, 155: 1549–1561
- 15
Jeroslow R G, Wang J. Solving propositional satisfiability problems. Ann Math Artif Intell, 1990, 1: 167–187
- 16
Marques-Silva J. The impact of branching heuristics in propositional satisfiability algorithms. In: Proceedings of EPIA, 1999. 850
- 17
Audemard G, Simon L. GLUCOSE: a solver that predicts learnt clauses quality. In: Proceedings of SAT Competition, 2009. 7–8
- 18
Audemard G, Simon L. Glucose in the SAT 2014 competition. In: Proceedings of SAT Competition, 2014. 31–32
- 19
Liang J H, Ganesh V, Poupart P, et al. Learning rate based branching heuristic for SAT solvers. In: Proceedings of SAT, 2016. 123–140
- 20
Liang J H, Oh C, Ganesh V, et al. MapleCOMSPS, MapleCOMSPS LRB, MapleCOMSPS CHB. In: Proceedings of SAT Competition, 2016. 52–53
- 21
Li C M, Manyá F, Mohamedou N O, et al. Resolution-based lower bounds in MaxSAT. Constraints, 2010, 15: 456–484