Exponential Recency Weighted Average Branching Heuristic for SAT Solvers
Jia Hui Liang, Vijay Ganesh, Pascal Poupart,等. Exponential Recency Weighted Average Branching Heuristic for SAT Solvers[C]// Thirtieth Aaai Conference on Artificial Intelligence. AAAI Press, 2016.
conflict history-based branching heuristic (CHB)
Abstract
Modern conflict-driven clause-learning SAT solvers routinely solve large real-world instances with millions of clauses and variables in them. Their success crucially depends on effective branching heuristics. In this paper, we propose a new branching heuristic inspired by the exponential recency weighted average algorithm used to solve the bandit problem. The branching heuristic, we call CHB, learns online which variables to branch on by leveraging the feedback received from conflict analysis.译文:通过利用从冲突分析中得到的反馈,在线学习哪些变量可以进行分支。
We evaluated CHB on 1200 instances from the SAT Competition 2013 and 2014 instances, and showed that CHB solves significantly more instances than VSIDS, currently the most effective branching heuristic in widespread use.More precisely, we implemented CHB as part of the MiniSat and Glucose solvers, and performed an apple-to-apple comparison with their VSIDS-based variants. CHB-based MiniSat (resp. CHB-based Glucose) solved approximately 16.1% (resp. 5.6%) more instances than their VSIDS-based variants. Additionally, CHB-based solvers are much more efficient at constructing first preimage attacks on step-reduced SHA-1 and MD5 cryptographic hash functions, than their VSIDS-based counterparts.译文:此外,基于chb的求解器在构造针对阶减SHA-1和MD5加密哈希函数的第一次原像攻击时,比基于vsid的求解器要高效得多。
To the best of our knowledge, CHB is the first branching heuristic to solve significantly more instances than VSIDS on a large, diverse benchmark of real-world instances. |
Modern conflict-driven clause-learning SAT solvers routinely solve large real-world instances with millions of clauses and variables in them. Their success crucially depends on effective branching heuristics. |
my study notes
remain as the most effective ones in widespread use today. Lagoudakis and Littman took 7 well-known SAT 译文: |
Second, until very recently, little was understood as to why the VSIDS branching heuristic and its variants are so effective.译文:其次,直到最近,人们对为什么VSIDS分支启发式及其变体如此有效还知之甚少。 |
Inspired by the bandit framework and reinforcement learning, we learn to choose good variables to branch based on past experience. Our goal is to leverage the theory and practice of a rich sub-field of reinforcement learning to plain and design an effective branching heuristic for solving real-world problems. 译文:受到bandit框架和强化学习的启发,我们学会根据过去的经验选择好的变量进行分支。我们的目标是利用理论和实践的丰富子领域的强化学习,以平原和设计一个有效的分支启发式解决实际问题。 分支决策变元的选择包含强化学习的思想 |
The branching heuristic proposed in this paper, CHB, is completely online and learns which variable to branch on
dynamically as the input instance is being solved. By online we mean that the heuristic learns only during the olving 译文:本文提出的分支启发式CHB是完全在线的,并在求解输入实例时动态地学习在哪个变量上进行分支。线上是指启发式只在存活过程中学习,而不存在线下学习。 |
Exponential Recency Weighted Average (ERWA) |
The CHB Branching Heuristic
|
Future Work
The connection between branching heuristics and reinforcement learning opens many new opportunities for future improvements to branching heuristics and SAT solving in general.译文:分支启发式和强化学习之间的联系为分支启发式和SAT解决的未来改进打开了许多新的机会。
Modern CDCL SAT solvers maintain lots of state features such as the partial assignment, trail, learnt clause database, saved phases, etc. 译文:现代CDCL SAT求解器维护了许多状态特性,如部分赋值、跟踪、学习子句数据库、保存阶段等。 The technique proposed in this paper is based on the multi-armed bandit setting, and it can be extended to a full Markov decision process by conditioning the choice of variables on some of the solvers’ state features. More research is needed to find a stateful model that works well in practice by balancing the trade-off between the gain in information due to states and the cost of increased model complexity. |
We modeled our branching heuristic on ERWA, a technique used to solve the bandit problem. However, perhaps It is evident that the branching heuristic and clause learning drive each other, so a model capturing both aspects can lead to algorithms that not only choose better branching variables, but also learn higher quality clauses.译文:很明显,分支启发式和子句学习是相互推动的,因此,一个抓住这两个方面的模型,不仅能够选择更好的分支变量,而且能够学习更高质量的子句。 It is clear that such a model is outside the bandit framework, due to the additional feedback from clause learning to the branching heuristic in the form of learnt clauses. More work is needed to construct new models that include more aspects of CDCL such as clause learning.译文:很明显,这样的模型是在bandit框架之外的,因为从子句学习到以学习子句形式的分支启发式的额外反馈。需要做更多的工作来构建包含CDCL更多方面的新模型,比如子句学习。 |
代码解读
Jia Hui Liang老师2016年参加竞赛的求解器有两个主要革新:CHB和LRB。
CHB的思路是从冲突分析中得到的反馈,每个变元从参与决策、传播和冲突分析的历史(记录相应的时间节点——用当时的冲突次数标定时刻)信息中获得reward,基于activity_CHB的大小选择下一次分支决策变量;
LRB的思路与上述思想大致类似,所不同的是反馈的是边缘生存期参与冲突分析及构造学习字句的比例。
由于是同一个作者,在实现代码中,activity_CHB在不同的策略版本中分别代表两种活跃度。实际上LRB策略代码中应当使用activity_LRB,以免引起错觉和误会。
CHB策略相关代码
solver.h中定义与CHB相关的量 double step_size; // alfa |
重点看一下第48行congflicted的赋值------记录了变元 |
1 void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, int& out_lbd) 2 { 3 int pathC = 0; 4 Lit p = lit_Undef; 5 6 // Generate conflict clause: 7 // 8 out_learnt.push(); // (leave room for the asserting literal) 9 int index = trail.size() - 1; 10 11 // Trying to reduce proof size. 12 add_oc.clear(); 13 do{ 14 assert(confl != CRef_Undef); // (otherwise should be UIP) 15 Clause& c = ca[confl]; 16 17 // For binary clauses, we don't rearrange literals in propagate(), so check and make sure the first is an implied lit. 18 if (p != lit_Undef && c.size() == 2 && value(c[0]) == l_False){ 19 assert(value(c[1]) == l_True); 20 Lit tmp = c[0]; 21 c[0] = c[1], c[1] = tmp; } 22 23 bool migrate_bin = false; 24 bool otf_simp = !drup_file || (c.size() < 10 && (!c.learnt() || c.mark() == CORE)); 25 for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){ 26 Lit q = c[j]; 27 28 if (otf_simp && j >= 2 // For now, should use only "premise_bin" if printing proof. 29 && ((!drup_file && (premise[toInt(~q)] == ~c[0] || premise[toInt(c[0])] == q 30 || premise[toInt(~q)] == ~c[1] || premise[toInt(c[1])] == q)) 31 || premise_bin[toInt(~q)] == ~c[0] || premise_bin[toInt(c[0])] == q 32 || premise_bin[toInt(~q)] == ~c[1] || premise_bin[toInt(c[1])] == q)){ 33 if (drup_file && add_oc.size() == 0) 34 for (int k = 0; k < c.size(); k++) 35 add_oc.push(c[k]); 36 37 lit_elim++; 38 c[j--] = c.last(); 39 c.shrink(1); // FIXME: fix (statistical) memory leak. 40 if (c.learnt()) learnts_literals--; 41 else clauses_literals--; 42 43 if (c.size() == 2) 44 migrate_bin = true; 45 }else if (!seen[var(q)] && level(var(q)) > 0){ 46 varBumpActivity(var(q), .5); 47 add_tmp.push(q); 48 conflicted[var(q)] = conflicts;//此次冲突分析记录下变元参与冲突分析的时刻,用于下次冲突时计算间隔 49 seen[var(q)] = 1; 50 if (level(var(q)) >= decisionLevel()){ 51 pathC++; 52 }else 53 out_learnt.push(q); 54 } 55 } 56 57 if (drup_file && add_oc.size() != 0){ 58 drup('a', c, drup_file); 59 drup('d', add_oc, drup_file); 60 add_oc.clear(); } 61 62 // Update LBD if improved. 63 if (c.learnt() && c.mark() != CORE && !migrate_bin){ 64 int lbd = computeLBD(c); 65 if (lbd < c.lbd()){ 66 if (c.lbd() <= 30) c.removable(false); // Protect once from reduction. 67 c.set_lbd(lbd); 68 if (lbd <= core_lbd_cut){ 69 learnts_core.push(confl); 70 c.mark(CORE); 71 }else if (lbd <= 6 && c.mark() == LOCAL){ 72 // Bug: 'cr' may already be in 'learnts_tier2', e.g., if 'cr' was demoted from TIER2 73 // to LOCAL previously and if that 'cr' is not cleaned from 'learnts_tier2' yet. 74 learnts_tier2.push(confl); 75 c.mark(TIER2); } 76 } 77 78 if (c.mark() == TIER2) 79 c.touched() = conflicts; 80 else if (c.mark() == LOCAL) 81 claBumpActivity(c); 82 } 83 84 if (migrate_bin){ 85 assert(c.size() == 2); assert(!c.learnt() || c.mark() == CORE); 86 assert(p == lit_Undef || value(c[0]) == l_True); 87 88 static vec<Lit> bin_tmp(2); 89 bin_tmp[0] = c[0]; bin_tmp[1] = c[1]; 90 91 bool learnt = c.learnt(); // We need a copy, as 'alloc' may invalidate the 'c' reference. 92 CRef cr = ca.alloc(bin_tmp, learnt); 93 if (p != lit_Undef) 94 vardata[var(bin_tmp[0])].reason = cr; 95 96 if (learnt){ 97 learnts_core.push(cr); 98 ca[cr].mark(CORE); 99 ca[cr].set_lbd(1); 100 }else 101 clauses.push(cr); 102 // attachClause(cr) 103 watches_bin[~bin_tmp[0]].push(Watcher(cr, bin_tmp[1])); 104 watches_bin[~bin_tmp[1]].push(Watcher(cr, bin_tmp[0])); 105 // removeClause(confl) without detachClause(confl) 106 ca[confl].mark(1); 107 ca.free(confl); 108 // detachClause(confl) 109 watches.smudge(~bin_tmp[0]); 110 watches.smudge(~bin_tmp[1]); 111 } 112 113 // Select next clause to look at: 114 while (!seen[var(trail[index--])]); 115 p = trail[index+1]; 116 confl = reason(var(p)); 117 seen[var(p)] = 0; 118 pathC--; 119 120 }while (pathC > 0); 121 out_learnt[0] = ~p; 122 123 // Simplify conflict clause: 124 // 125 int i, j; 126 out_learnt.copyTo(analyze_toclear); 127 if (ccmin_mode == 2){ 128 uint32_t abstract_level = 0; 129 for (i = 1; i < out_learnt.size(); i++) 130 abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict) 131 132 for (i = j = 1; i < out_learnt.size(); i++) 133 if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level)) 134 out_learnt[j++] = out_learnt[i]; 135 136 }else if (ccmin_mode == 1){ 137 for (i = j = 1; i < out_learnt.size(); i++){ 138 Var x = var(out_learnt[i]); 139 140 if (reason(x) == CRef_Undef) 141 out_learnt[j++] = out_learnt[i]; 142 else{ 143 Clause& c = ca[reason(var(out_learnt[i]))]; 144 for (int k = c.size() == 2 ? 0 : 1; k < c.size(); k++) 145 if (!seen[var(c[k])] && level(var(c[k])) > 0){ 146 out_learnt[j++] = out_learnt[i]; 147 break; } 148 } 149 } 150 }else 151 i = j = out_learnt.size(); 152 153 max_literals += out_learnt.size(); 154 out_learnt.shrink(i - j); 155 tot_literals += out_learnt.size(); 156 157 out_lbd = computeLBD(out_learnt); 158 if (out_lbd <= 6 && out_learnt.size() <= 30) // Try further minimization? 159 if (binResMinimize(out_learnt)) 160 out_lbd = computeLBD(out_learnt); // Recompute LBD if minimized. 161 162 // Find correct backtrack level: 163 // 164 if (out_learnt.size() == 1) 165 out_btlevel = 0; 166 else{ 167 int max_i = 1; 168 // Find the first literal assigned at the next-highest level: 169 for (int i = 2; i < out_learnt.size(); i++) 170 if (level(var(out_learnt[i])) > level(var(out_learnt[max_i]))) 171 max_i = i; 172 // Swap-in this literal at index 1: 173 Lit p = out_learnt[max_i]; 174 out_learnt[max_i] = out_learnt[1]; 175 out_learnt[1] = p; 176 out_btlevel = level(var(p)); 177 } 178 179 for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared) 180 181 for (int i = 0; i < add_tmp.size(); i++){ 182 Var v = var(add_tmp[i]); 183 if (level(v) >= out_btlevel - 1) 184 varBumpActivity(v, 1); 185 } 186 add_tmp.clear(); 187 }
|
action = trail.size();//求解器数据成员action记录的队列的长度,也是传播下一个阶段的开始位置。 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 action = trail.size(); 11 bool otf_probing = !drup_file && conflicts >= 50000 && starts % 10 == 0; 12 for (;;){ 13 CRef confl = propagate(otf_probing); 14 15 for (int a = action; a < trail.size(); a++){ 16 Var v = var(trail[a]); 17 updateQ(v, confl == CRef_Undef ? 0.9 : 1.0); } 18 //conflictAnalyze 19 。。。 20 } 搜索过程中,propagete函数一次调用结束(运行遇到冲突、或没有遇到冲突但没有可传播的子句),传播队列新传播的文字序列对应的变元获得活跃度回报值(由于冲突造成传播终止时,multi为1,非冲突造成传播终止时,multi略低,为0.9. |
1 void Solver::updateQ(Var v, double multi) { 2 uint32_t age = conflicts - conflicted[v] + 1; 3 double adjusted_reward = step_size * multi / age; 4 double old_activity = activity_CHB[v]; 5 activity_CHB[v] = adjusted_reward + ((1 - step_size) * old_activity); 6 if (order_heap_CHB.inHeap(v)) 7 if (activity_CHB[v] > old_activity) 8 order_heap_CHB.decrease(v); 9 else 10 order_heap_CHB.increase(v); 11 } conflicted[v]标定时刻——此次参与冲突分析的时刻,用于下一次冲突分析时计算时间间隔 adjusted_reward的值与age成反比,age为从conflicted[v]标定时刻至冲突分析回溯标定时刻的时间间隔。 |
LRB策略相关代码:选择下一个决策文字时,现有队列中的所有文字变元
solver.h中定义的成员变量 vec<uint32_t> picked; //记录变元传播进入trail的时刻 注意:conflicted在LRB中该量记录变元时刻而不是次数。
|
公式中,L(I)为该变元进入trail队列之后至被回溯取消期间发生的冲突次数;即,age = conflicts - canceled[v]; conflicted[v]是其中参与冲突分析作为学习子句文字的次数; almost_conflicted是参与冲突分析且作为reason一侧时的次数; 公式中,r=P(v,I)/L(I)为conflicted[v]的占比;A(v,I)/L(I)是almost_conflicted占比; |
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.选择决策变元时更新activity_CHB ——注意,此处通过line22的while循环语句,将所有传播至回退阶段参与CHB计算的变元的activity_CHB进行衰减处理。 |
1 void Solver::uncheckedEnqueue(Lit p, int level, CRef from) 2 { 3 assert(value(p) == l_Undef); 4 Var x = var(p); 5 if (!VSIDS){ 6 picked[x] = conflicts; 7 conflicted[x] = 0; 8 almost_conflicted[x] = 0; 9 #ifdef ANTI_EXPLORATION 10 uint32_t age = conflicts - canceled[var(p)]; 11 if (age > 0){ 12 double decay = pow(0.95, age);//体现:据上次使用(参与冲突分析)时间越长,对活跃度贡献越小。 13 activity_CHB[var(p)] *= decay; 14 if (order_heap_CHB.inHeap(var(p))) 15 order_heap_CHB.increase(var(p)); 16 } 17 #endif 18 } 19 20 assigns[x] = lbool(!sign(p)); 21 vardata[x] = mkVarData(from, level); 22 trail.push_(p); 23 } 2.传播阶段计算变元的activity_CHB line5-18为较minisat新增的部分,其中:
|
1 // Revert to the state at given level (keeping all assignment at 'level' but not beyond). 2 // 3 void Solver::cancelUntil(int bLevel) { 4 5 if (decisionLevel() > bLevel){ 6 #ifdef PRINT_OUT 7 std::cout << "bt " << bLevel << "\n"; 8 #endif 9 add_tmp.clear(); 10 for (int c = trail.size()-1; c >= trail_lim[bLevel]; c--) 11 { 12 Var x = var(trail[c]); 13 14 if (level(x) <= bLevel) 15 { 16 add_tmp.push(trail[c]); 17 } 18 else 19 { 20 if (!VSIDS){ 21 uint32_t age = conflicts - picked[x]; 22 if (age > 0){ 23 double adjusted_reward = ((double) (conflicted[x] + almost_conflicted[x])) / ((double) age); 24 double old_activity = activity_CHB[x]; 25 activity_CHB[x] = step_size * adjusted_reward + ((1 - step_size) * old_activity); 26 if (order_heap_CHB.inHeap(x)){ 27 if (activity_CHB[x] > old_activity) 28 order_heap_CHB.decrease(x); 29 else 30 order_heap_CHB.increase(x); 31 } 32 } 33 #ifdef ANTI_EXPLORATION 34 canceled[x] = conflicts; 35 #endif 36 } 37 38 assigns [x] = l_Undef; 39 #ifdef PRINT_OUT 40 std::cout << "undo " << x << "\n"; 41 #endif 42 if (phase_saving > 1 || (phase_saving == 1) && c > trail_lim.last()) 43 polarity[x] = sign(trail[c]); 44 insertVarOrder(x); 45 } 46 } 47 qhead = trail_lim[bLevel]; 48 trail.shrink(trail.size() - trail_lim[bLevel]); 49 trail_lim.shrink(trail_lim.size() - bLevel); 50 for (int nLitId = add_tmp.size() - 1; nLitId >= 0; --nLitId) 51 { 52 trail.push_(add_tmp[nLitId]); 53 } 54 55 add_tmp.clear(); 56 } 57 } 3.回溯阶段计算并更新变元的activity_CHB |
seach函数中冲突发生时: if (VSIDS){ if (--timer == 0 && var_decay < 0.95) timer = 5000, var_decay += 0.01; }else if (step_size > min_step_size) step_size -= step_size_dec;
4.移动平均的alfa(代码中为)的动态调整。 step_size初始值为0.4; min_step_size定位0.06; step_size_dec为0.000001 |
1 lbool Solver::solve_() 2 { 3 signal(SIGALRM, SIGALRM_switch); 4 alarm(2500); 5 6 model.clear(); 7 conflict.clear(); 8 if (!ok) return l_False; 9 10 solves++; 11 12 max_learnts = nClauses() * learntsize_factor; 13 learntsize_adjust_confl = learntsize_adjust_start_confl; 14 learntsize_adjust_cnt = (int)learntsize_adjust_confl; 15 lbool status = l_Undef; 16 17 if (verbosity >= 1){ 18 printf("c ============================[ Search Statistics ]==============================\n"); 19 printf("c | Conflicts | ORIGINAL | LEARNT | Progress |\n"); 20 printf("c | | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n"); 21 printf("c ===============================================================================\n"); 22 } 23 24 add_tmp.clear(); 25 26 VSIDS = true; 27 int init = 10000; 28 while (status == l_Undef && init > 0 /*&& withinBudget()*/) 29 status = search(init); 30 VSIDS = false; 31 32 duplicates_added_conflicts = 0; 33 duplicates_added_minimization=0; 34 duplicates_added_tier2 =0; 35 36 dupl_db_size=0; 37 size_t dupl_db_size_limit = dupl_db_init_size; 38 39 // Search: 40 int curr_restarts = 0; 41 while (status == l_Undef /*&& withinBudget()*/){ 42 if (dupl_db_size >= dupl_db_size_limit){ 43 printf("c Duplicate learnts added (Minimization) %i\n",duplicates_added_minimization); 44 printf("c Duplicate learnts added (conflicts) %i\n",duplicates_added_conflicts); 45 printf("c Duplicate learnts added (tier2) %i\n",duplicates_added_tier2); 46 printf("c Duptime: %i\n",duptime.count()); 47 printf("c Number of conflicts: %i\n",conflicts); 48 printf("c Core size: %i\n",learnts_core.size()); 49 50 uint32_t removed_duplicates = 0; 51 std::vector<std::vector<uint64_t>> tmp; 52 //std::map<int32_t,std::map<uint32_t,std::unordered_map<uint64_t,uint32_t>>> ht; 53 for (auto & outer_mp: ht){//variables 54 for (auto &inner_mp:outer_mp.second){//sizes 55 for (auto &in_in_mp: inner_mp.second){ 56 if (in_in_mp.second >= min_number_of_learnts_copies){ 57 tmp.push_back({outer_mp.first,inner_mp.first,in_in_mp.first,in_in_mp.second}); 58 } 59 } 60 } 61 } 62 removed_duplicates = dupl_db_size-tmp.size(); 63 ht.clear(); 64 for (auto i=0;i<tmp.size();i++){ 65 ht[tmp[i][0]][tmp[i][1]][tmp[i][2]]=tmp[i][3]; 66 } 67 //ht_old.clear(); 68 dupl_db_size_limit*=1.1; 69 dupl_db_size -= removed_duplicates; 70 printf("c removed duplicate db entries %i \n",removed_duplicates); 71 } 72 if (VSIDS){ 73 int weighted = INT32_MAX; 74 status = search(weighted); 75 }else{ 76 int nof_conflicts = luby(restart_inc, curr_restarts) * restart_first; 77 curr_restarts++; 78 status = search(nof_conflicts); 79 } 80 if (!VSIDS && switch_mode){ 81 VSIDS = true; 82 printf("c Switched to VSIDS.\n"); 83 fflush(stdout); 84 picked.clear(); 85 conflicted.clear(); 86 almost_conflicted.clear(); 87 #ifdef ANTI_EXPLORATION 88 canceled.clear(); 89 #endif 90 } 91 } 92 93 if (verbosity >= 1) 94 printf("c ===============================================================================\n"); 95 96 #ifdef BIN_DRUP 97 if (drup_file && status == l_False) binDRUP_flush(drup_file); 98 #endif 99 100 if (status == l_True){ 101 // Extend & copy model: 102 model.growTo(nVars()); 103 for (int i = 0; i < nVars(); i++) model[i] = value(i); 104 }else if (status == l_False && conflict.size() == 0) 105 ok = false; 106 107 cancelUntil(0); 108 return status; 109 }
5.activity_CHB与其它活跃度策略的组合使用 |
1 void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, int& out_lbd) 2 { 3 int pathC = 0; 4 Lit p = lit_Undef; 5 6 // Generate conflict clause: 7 // 8 out_learnt.push(); // (leave room for the asserting literal) 9 int index = trail.size() - 1; 10 11 do{ 12 assert(confl != CRef_Undef); // (otherwise should be UIP) 13 Clause& c = ca[confl]; 14 15 // For binary clauses, we don't rearrange literals in propagate(), so check and make sure the first is an implied lit. 16 if (p != lit_Undef && c.size() == 2 && value(c[0]) == l_False){ 17 assert(value(c[1]) == l_True); 18 Lit tmp = c[0]; 19 c[0] = c[1], c[1] = tmp; } 20 21 // Update LBD if improved. 22 if (c.learnt() && c.mark() != CORE){ 23 int lbd = computeLBD(c); 24 if (lbd < c.lbd()){ 25 if (c.lbd() <= 30) c.removable(false); // Protect once from reduction. 26 c.set_lbd(lbd); 27 if (lbd <= core_lbd_cut){ 28 learnts_core.push(confl); 29 c.mark(CORE); 30 }else if (lbd <= 6 && c.mark() == LOCAL){ 31 // Bug: 'cr' may already be in 'learnts_tier2', e.g., if 'cr' was demoted from TIER2 32 // to LOCAL previously and if that 'cr' is not cleaned from 'learnts_tier2' yet. 33 learnts_tier2.push(confl); 34 c.mark(TIER2); } 35 } 36 37 if (c.mark() == TIER2) 38 c.touched() = conflicts; 39 else if (c.mark() == LOCAL) 40 claBumpActivity(c); 41 } 42 43 for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){ 44 Lit q = c[j]; 45 46 if (!seen[var(q)] && level(var(q)) > 0){ 47 if (VSIDS){ 48 varBumpActivity(var(q), .5); 49 add_tmp.push(q); 50 }else 51 conflicted[var(q)]++; 52 seen[var(q)] = 1; 53 if (level(var(q)) >= decisionLevel()){ 54 pathC++; 55 }else 56 out_learnt.push(q); 57 } 58 } 59 60 // Select next clause to look at: 61 while (!seen[var(trail[index--])]); 62 p = trail[index+1]; 63 confl = reason(var(p)); 64 seen[var(p)] = 0; 65 pathC--; 66 67 }while (pathC > 0); 68 out_learnt[0] = ~p; 69 70 // Simplify conflict clause: 71 // 72 int i, j; 73 out_learnt.copyTo(analyze_toclear); 74 if (ccmin_mode == 2){ 75 uint32_t abstract_level = 0; 76 for (i = 1; i < out_learnt.size(); i++) 77 abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict) 78 79 for (i = j = 1; i < out_learnt.size(); i++) 80 if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level)) 81 out_learnt[j++] = out_learnt[i]; 82 83 }else if (ccmin_mode == 1){ 84 for (i = j = 1; i < out_learnt.size(); i++){ 85 Var x = var(out_learnt[i]); 86 87 if (reason(x) == CRef_Undef) 88 out_learnt[j++] = out_learnt[i]; 89 else{ 90 Clause& c = ca[reason(var(out_learnt[i]))]; 91 for (int k = c.size() == 2 ? 0 : 1; k < c.size(); k++) 92 if (!seen[var(c[k])] && level(var(c[k])) > 0){ 93 out_learnt[j++] = out_learnt[i]; 94 break; } 95 } 96 } 97 }else 98 i = j = out_learnt.size(); 99 100 max_literals += out_learnt.size(); 101 out_learnt.shrink(i - j); 102 tot_literals += out_learnt.size(); 103 104 out_lbd = computeLBD(out_learnt); 105 if (out_lbd <= 6 && out_learnt.size() <= 30) // Try further minimization? 106 if (binResMinimize(out_learnt)) 107 out_lbd = computeLBD(out_learnt); // Recompute LBD if minimized. 108 109 // Find correct backtrack level: 110 // 111 if (out_learnt.size() == 1) 112 out_btlevel = 0; 113 else{ 114 int max_i = 1; 115 // Find the first literal assigned at the next-highest level: 116 for (int i = 2; i < out_learnt.size(); i++) 117 if (level(var(out_learnt[i])) > level(var(out_learnt[max_i]))) 118 max_i = i; 119 // Swap-in this literal at index 1: 120 Lit p = out_learnt[max_i]; 121 out_learnt[max_i] = out_learnt[1]; 122 out_learnt[1] = p; 123 out_btlevel = level(var(p)); 124 } 125 126 if (VSIDS){ 127 for (int i = 0; i < add_tmp.size(); i++){ 128 Var v = var(add_tmp[i]); 129 if (level(v) >= out_btlevel - 1) 130 varBumpActivity(v, 1); 131 } 132 add_tmp.clear(); 133 }else{ 134 seen[var(p)] = true; 135 for(int i = out_learnt.size() - 1; i >= 0; i--){ 136 Var v = var(out_learnt[i]); 137 CRef rea = reason(v); 138 if (rea != CRef_Undef){ 139 const Clause& reaC = ca[rea]; 140 for (int i = 0; i < reaC.size(); i++){ 141 Lit l = reaC[i]; 142 if (!seen[var(l)]){ 143 seen[var(l)] = true; 144 almost_conflicted[var(l)]++; 145 analyze_toclear.push(l); } } } } } 146 147 for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared) 148 }
|
References