2019年求解器Maple LCM OnlineDel给出了在线管理学习子句规模的方法
(1)将新增的学习子句与学习子句集中指定的子句进行替换,保证学习子句集的规模一定。
(2)每个学习子句的Q值初始为0;当参与冲突分析时,会按照一定规则增加其值;
(3)最新的学习子句生成后,原学习子句集中指定被替换的学习子句是如何选出来的?
(3-1)依次加入l冲突分析得到的学习子句进入earnt_local学习子句集,维持一定数量规模(如80000个);
(3-2)学习子句集中的子句表示为learnts_local[CDelTag] 。CDelTag为循环增加的位置序号。按照一个方向排查每一个学习子句:对于.usedRecDel() >= 2的子句,设置其值为0,SETusedRecDel(0)。排查一遍后,CDelTag停驻的地方(没有.usedRecDel() >= 2的子句在学习子句集中时刻)即为需要被替换的学习子句位置。
在search函数中,实现代码如下:
1 。。。 2 if (learnts_local.size() < Learnts_Size_threshold){ 3 learnts_local.push(cr); 4 }else{ 5 CRef DelClauseCandidate ; 6 DelClauseCandidate = learnts_local[CDelTag] ; 7 while (!ca[DelClauseCandidate].removable() || locked(ca[DelClauseCandidate]) || ca[DelClauseCandidate].usedRecDel() >= 2 ) { 8 if(!ca[DelClauseCandidate].removable()) ca[DelClauseCandidate].removable(true); 9 ca[DelClauseCandidate].SETusedRecDel(0) ; 10 CDelTag = (CDelTag+1) % learnts_local.size() ; 11 DelClauseCandidate = learnts_local[CDelTag] ; 12 } 13 ca[DelClauseCandidate].SETusedRecDel(0) ; 14 DeletionCnt++ ; 15 if (ca[DelClauseCandidate].mark() == LOCAL) removeClause(DelClauseCandidate) ; 16 learnts_local[CDelTag] = cr ; 17 CDelTag = (CDelTag+1) % learnts_local.size() ; 18 } 19 }
在analyze函数中,参与冲突分析的学习子句的值 c.usedRecDel() + inc_val 做增加,具体代码如下:
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 int nDecisionLevel = level(var(ca[confl][0])); 11 assert(nDecisionLevel == level(var(ca[confl][0]))); 12 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 // Update LBD if improved. 24 if (c.learnt() && c.mark() != CORE){ 25 int lbd = computeLBD(c); 26 if (lbd < c.lbd()){ 27 if (c.lbd() <= 30) c.removable(false); // Protect once from reduction. 28 c.set_lbd(lbd); 29 if (lbd <= 3){ 30 learnts_core.push(confl); 31 c.mark(CORE); 32 } 33 } 34 } 35 36 double inc_val = 12 / double(c.lbd()) ; 37 double used_so_far = c.usedRecDel() + inc_val ; //Sima 38 c.SETusedRecDel(used_so_far) ; //Sima 39 40 41 for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){ 42 Lit q = c[j]; 43 44 if (!seen[var(q)] && level(var(q)) > 0){ 45 if (VSIDS){ 46 varBumpActivity(var(q), .5); 47 add_tmp.push(q); 48 }else 49 conflicted[var(q)]++; 50 seen[var(q)] = 1; 51 if (level(var(q)) >= nDecisionLevel){ 52 pathC++; 53 }else 54 out_learnt.push(q); 55 } 56 } 57 58 // Select next clause to look at: 59 do { 60 while (!seen[var(trail[index--])]); 61 p = trail[index+1]; 62 } while (level(var(p)) < nDecisionLevel); 63 64 confl = reason(var(p)); 65 seen[var(p)] = 0; 66 pathC--; 67 68 }while (pathC > 0); 69 out_learnt[0] = ~p; 70 71 // Simplify conflict clause: 72 // 73 int i, j; 74 out_learnt.copyTo(analyze_toclear); 75 if (ccmin_mode == 2){ 76 uint32_t abstract_level = 0; 77 for (i = 1; i < out_learnt.size(); i++) 78 abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict) 79 80 for (i = j = 1; i < out_learnt.size(); i++) 81 if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level)) 82 out_learnt[j++] = out_learnt[i]; 83 84 }else if (ccmin_mode == 1){ 85 for (i = j = 1; i < out_learnt.size(); i++){ 86 Var x = var(out_learnt[i]); 87 88 if (reason(x) == CRef_Undef) 89 out_learnt[j++] = out_learnt[i]; 90 else{ 91 Clause& c = ca[reason(var(out_learnt[i]))]; 92 for (int k = c.size() == 2 ? 0 : 1; k < c.size(); k++) 93 if (!seen[var(c[k])] && level(var(c[k])) > 0){ 94 out_learnt[j++] = out_learnt[i]; 95 break; } 96 } 97 } 98 }else 99 i = j = out_learnt.size(); 100 101 max_literals += out_learnt.size(); 102 out_learnt.shrink(i - j); 103 tot_literals += out_learnt.size(); 104 105 out_lbd = computeLBD(out_learnt); 106 if (out_lbd <= 6 && out_learnt.size() <= 30) // Try further minimization? 107 if (binResMinimize(out_learnt)) 108 out_lbd = computeLBD(out_learnt); // Recompute LBD if minimized. 109 110 // Find correct backtrack level: 111 // 112 if (out_learnt.size() == 1) 113 out_btlevel = 0; 114 else{ 115 int max_i = 1; 116 // Find the first literal assigned at the next-highest level: 117 for (int i = 2; i < out_learnt.size(); i++) 118 if (level(var(out_learnt[i])) > level(var(out_learnt[max_i]))) 119 max_i = i; 120 // Swap-in this literal at index 1: 121 Lit p = out_learnt[max_i]; 122 out_learnt[max_i] = out_learnt[1]; 123 out_learnt[1] = p; 124 out_btlevel = level(var(p)); 125 } 126 127 if (VSIDS){ 128 for (int i = 0; i < add_tmp.size(); i++){ 129 Var v = var(add_tmp[i]); 130 if (level(v) >= out_btlevel - 1) 131 varBumpActivity(v, 1); 132 } 133 add_tmp.clear(); 134 }else{ 135 seen[var(p)] = true; 136 for(int i = out_learnt.size() - 1; i >= 0; i--){ 137 Var v = var(out_learnt[i]); 138 CRef rea = reason(v); 139 if (rea != CRef_Undef){ 140 const Clause& reaC = ca[rea]; 141 for (int i = 0; i < reaC.size(); i++){ 142 Lit l = reaC[i]; 143 if (!seen[var(l)]){ 144 seen[var(l)] = true; 145 almost_conflicted[var(l)]++; 146 analyze_toclear.push(l); } } } } } 147 148 for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared) 149 }
具体可以参考:Sima Jamali、David Mitchell2019年SAT竞赛求解器Maple LCM OnlineDel,以及他们发表的文章:S. Jamali and D. Mitchell, ”Simplifying CDCL Clause Database Reduction,” in Proceedings of SAT, 2019。