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.
  activity_VSIDS,activity_distance;

  Heap<VarOrderLt> order_heap_CHB, // A priority queue of variables ordered with respect to the variable activity.
  order_heap_VSIDS,order_heap_distance;

public:
  int level (Var x) const;//提升成员level的访问属性为公有访问(原来访问属性为 protected:)

 

bool collectFirstUIP(CRef confl);                    //计算蕴含图中文字变元距离冲突点路径长度的函数
vec<double> var_iLevel,var_iLevel_tmp;
uint64_t nbcollectfirstuip, nblearntclause, nbDoubleConflicts, nbTripleConflicts;
int uip1, uip2;
vec<int> pathCs;


CRef propagateLits(vec<Lit>& lits);              //给定文字序列(赋值默认?)开始传播
uint64_t previousStarts;
double var_iLevel_inc;
vec<Lit> involved_lits;
double my_var_decay;
bool DISTANCE;

 
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)
, DISTANCE (true)
, var_iLevel_inc (1)
, order_heap_distance(VarOrderLt(activity_distance))

 在Var Solver::newVar(bool sign, bool dvar)函数中,新增与变元对应的向量初值

activity_distance.push(0);
var_iLevel.push(0);
var_iLevel_tmp.push(0);
pathCs.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. 1

    Audemard G, Simon L. Glucose 2.3 in the SAT 2013 competition. In: Proceedings of SAT Competition, 2013. 42–43

    Google Scholar 

  2. 2

    Biere A. Lingeling, Plingeling, Picosat and Precosat at SAT Race 2010. FMV Report Series, Technical Report 10/1, 2010

    Google Scholar 

  3. 3

    Eén N, Sorensson N. An extensible SAT solver. In: Proceedings of SAT, 2003. 502–518

    Google Scholar 

  4. 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

    Google Scholar 

  5. 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

    Google Scholar 

  6. 6

    Soos M. CryptoMiniSat v4. In: Proceedings of SAT Competition, 2014. 23

    Google Scholar 

  7. 7

    Marques-Silva J, Lynce I, Malik S. Conflict-driven clause learning SAT solvers. In: Handbook of Satisfiability. Washington: IOS Press, 2009. 131–153

    Google Scholar 

  8. 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

    Google Scholar 

  9. 9

    Audemard G, Simon L. Predicting learnt clauses quality in modern SAT solvers. In: Proceedings of IJCAI, 2009. 399–404

    Google Scholar 

  10. 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

    Google Scholar 

  11. 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

    Google Scholar 

  12. 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

    Google Scholar 

  13. 13

    Biere A, Förhlich A. Evaluating CDCL variable scoring schemes. In: Proceedings of SAT, 2015. 405–422

    Google Scholar 

  14. 14

    Goldberg E, Novikov Y. BerkMin: a fast and robust Sat-solver. Discrete Appl Math, 2007, 155: 1549–1561

    MathSciNet Article MATH Google Scholar 

  15. 15

    Jeroslow R G, Wang J. Solving propositional satisfiability problems. Ann Math Artif Intell, 1990, 1: 167–187

    Article MATH Google Scholar 

  16. 16

    Marques-Silva J. The impact of branching heuristics in propositional satisfiability algorithms. In: Proceedings of EPIA, 1999. 850

    Google Scholar 

  17. 17

    Audemard G, Simon L. GLUCOSE: a solver that predicts learnt clauses quality. In: Proceedings of SAT Competition, 2009. 7–8

    Google Scholar 

  18. 18

    Audemard G, Simon L. Glucose in the SAT 2014 competition. In: Proceedings of SAT Competition, 2014. 31–32

    Google Scholar 

  19. 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

    Google Scholar 

  20. 20

    Liang J H, Oh C, Ganesh V, et al. MapleCOMSPS, MapleCOMSPS LRB, MapleCOMSPS CHB. In: Proceedings of SAT Competition, 2016. 52–53

    Google Scholar 

  21. 21

    Li C M, Manyá F, Mohamedou N O, et al. Resolution-based lower bounds in MaxSAT. Constraints, 2010, 15: 456–484

 

posted on 2020-06-28 21:45  海阔凭鱼跃越  阅读(210)  评论(0编辑  收藏  举报