1.构造观察元并加入观察序列 在internal.hpp中有以下构造函数并声明相关函数 // Operators on watches. 1 // Watch literal 'lit' in clause with blocking literal 'blit'. 2 // Inlined here, since it occurs in the tight inner loop of 'propagate'. 3 // 4 inline void watch_literal (int lit, int blit, Clause * c) { 5 assert (lit != blit); 6 Watches & ws = watches (lit); 7 ws.push_back (Watch (blit, c)); 8 LOG (c, "watch %d blit %d in", lit, blit); 9 } 10 11 // Add two watches to a clause. This is used initially during allocation 12 // of a clause and during connecting back all watches after preprocessing. 13 // 14 inline void watch_clause (Clause * c) { 15 const int l0 = c->literals[0]; 16 const int l1 = c->literals[1]; 17 watch_literal (l0, l1, c); 18 watch_literal (l1, l0, c); 19 } 20 21 inline void unwatch_clause (Clause * c) { 22 const int l0 = c->literals[0]; 23 const int l1 = c->literals[1]; 24 remove_watch (watches (l0), c); 25 remove_watch (watches (l1), c); 26 }
|
|
观察序列中二值观察元放在前部 void Internal::sort_watches () watch.cpp文件 1 #include "internal.hpp" 2 3 namespace CaDiCaL { 4 5 void Internal::init_watches () { 6 assert (wtab.empty ()); 7 if (wtab.size () < 2*vsize) 8 wtab.resize (2*vsize, Watches ()); 9 LOG ("initialized watcher tables"); 10 } 11 12 void Internal::clear_watches () { 13 for (auto lit : lits) 14 watches (lit).clear (); 15 } 16 17 void Internal::reset_watches () { 18 assert (!wtab.empty ()); 19 erase_vector (wtab); 20 LOG ("reset watcher tables"); 21 } 22 23 // This can be quite costly since lots of memory is accessed in a rather 24 // random fashion, and thus we optionally profile it. 25 26 void Internal::connect_watches (bool irredundant_only) { 27 START (connect); 28 assert (watching ()); 29 30 LOG ("watching all %sclauses", irredundant_only ? "irredundant " : ""); 31 32 // First connect binary clauses. 33 // 34 for (const auto & c : clauses) { 35 if (irredundant_only && c->redundant) continue; 36 if (c->garbage || c->size > 2) continue; 37 watch_clause (c); 38 } 39 40 // Then connect non-binary clauses. 41 // 42 for (const auto & c : clauses) { 43 if (irredundant_only && c->redundant) continue; 44 if (c->garbage || c->size == 2) continue; 45 watch_clause (c); 46 if (!level) { 47 const int lit0 = c->literals[0]; 48 const int lit1 = c->literals[1]; 49 const signed char tmp0 = val (lit0); 50 const signed char tmp1 = val (lit1); 51 if (tmp0 > 0) continue; 52 if (tmp1 > 0) continue; 53 if (tmp0 < 0) { 54 const size_t pos0 = var (lit0).trail; 55 if (pos0 < propagated) { 56 propagated = pos0; 57 LOG ("literal %d resets propagated to %zd", lit0, pos0); 58 } 59 } 60 if (tmp1 < 0) { 61 const size_t pos1 = var (lit1).trail; 62 if (pos1 < propagated) { 63 propagated = pos1; 64 LOG ("literal %d resets propagated to %zd", lit1, pos1); 65 } 66 } 67 } 68 } 69 70 STOP (connect); 71 } 72 73 void Internal::sort_watches () { 74 assert (watching ()); 75 LOG ("sorting watches"); 76 Watches saved; 77 for (auto lit : lits) { 78 Watches & ws = watches (lit); 79 80 const const_watch_iterator end = ws.end (); 81 watch_iterator j = ws.begin (); 82 const_watch_iterator i; 83 84 assert (saved.empty ()); 85 86 for (i = j; i != end; i++) { 87 const Watch w = *i; 88 if (w.binary ()) *j++ = w; 89 else saved.push_back (w); 90 } 91 92 std::copy (saved.cbegin (), saved.cend (), j); 93 94 saved.clear (); 95 } 96 } 97 98 }
涉及void Internal::sort_watches () 使用的函数 lookahead.cpp中 lookahead_probing() 1 // We run probing on all literals with some differences: 2 // 3 // * no limit on the number of propagations. We rely on terminating to stop() 4 // * we run only one round 5 // 6 // The run can be expensive, so we actually first run the cheaper 7 // occurrence version and only then run lookahead. 8 // 我们对所有不同的字面量运行探测: 对传播次数没有限制。我们依靠终止来停止()。 我们只运行一轮,这个运行可能很昂贵,所以我们实际上首先运行便宜的发生版本,然后才运行向前看。 9 int Internal::lookahead_probing() { 10 11 if (!active ()) 12 return 0; 13 14 MSG ("lookahead-probe-round %" PRId64 15 " without propagations limit and %zu assumptions", 16 stats.probingrounds, assumptions.size()); 17 18 termination_forced = false; 19 20 #ifndef QUIET 21 int old_failed = stats.failed; 22 int64_t old_probed = stats.probed; 23 #endif 24 int64_t old_hbrs = stats.hbrs; 25 26 if (unsat) return INT_MIN; 27 if (level) backtrack (); 28 if (!propagate ()) { 29 MSG ("empty clause before probing"); 30 learn_empty_clause (); 31 return INT_MIN; 32 } 33 34 if (terminating_asked()) 35 return most_occurring_literal(); 36 37 decompose (); 38 39 if (ternary ()) // If we derived a binary clause 40 decompose (); // then start another round of ELS. 41 42 // Remove duplicated binary clauses and perform in essence hyper unary 43 // resolution, i.e., derive the unit '2' from '1 2' and '-1 2'. 44 // 45 mark_duplicated_binary_clauses_as_garbage (); 46 47 lim.conflicts = -1; 48 49 if (!probes.empty ()) lookahead_flush_probes (); 50 51 // We reset 'propfixed' since there was at least another conflict thus 52 // a new learned clause, which might produce new propagations (and hyper 53 // binary resolvents). During 'generate_probes' we keep the old value. 54 // 55 for (int idx = 1; idx <= max_var; idx++) 56 propfixed (idx) = propfixed (-idx) = -1; 57 58 assert (unsat || propagated == trail.size ()); 59 propagated = propagated2 = trail.size (); 60 61 int probe; 62 int res = most_occurring_literal(); 63 int max_hbrs = -1; 64 65 set_mode (PROBE); 66 67 MSG("unsat = %d, terminating_asked () = %d ", unsat, terminating_asked ()); 68 while (!unsat && 69 !terminating_asked () && 70 (probe = lookahead_next_probe ())) { 71 stats.probed++; 72 int hbrs; 73 74 probe_assign_decision (probe); 75 if (probe_propagate ()) 76 hbrs = trail.size(), backtrack(); 77 else hbrs = 0, failed_literal (probe); 78 if (max_hbrs < hbrs || 79 (max_hbrs == hbrs && 80 internal->bumped(probe) > internal->bumped(res))) { 81 res = probe; 82 max_hbrs = hbrs; 83 } 84 } 85 86 reset_mode (PROBE); 87 88 if (unsat) { 89 MSG ("probing derived empty clause"); 90 res = INT_MIN; 91 } 92 else if (propagated < trail.size ()) { 93 MSG ("probing produced %zd units", 94 (size_t)(trail.size () - propagated)); 95 if (!propagate ()) { 96 MSG ("propagating units after probing results in empty clause"); 97 learn_empty_clause (); 98 res = INT_MIN; 99 } else sort_watches (); 100 } 101 102 #ifndef QUIET 103 int failed = stats.failed - old_failed; 104 int64_t probed = stats.probed - old_probed; 105 #endif 106 int64_t hbrs = stats.hbrs - old_hbrs; 107 108 MSG ("lookahead-probe-round %" PRId64 " probed %" PRId64 109 " and found %d failed literals", 110 stats.probingrounds, 111 probed, failed); 112 113 if (hbrs) 114 PHASE ("lookahead-probe-round", stats.probingrounds, 115 "found %" PRId64 " hyper binary resolvents", hbrs); 116 117 MSG ("lookahead literal %d with %d\n", res, max_hbrs); 118 119 return res; 120 }
在文件transred.cpp中 transred () 1 #include "internal.hpp" 2 3 namespace CaDiCaL { 4 5 // Implement transitive reduction in the binary implication graph. This is 6 // important for hyper binary resolution, which has the risk to produce too 7 // many hyper binary resolvents otherwise. This algorithm only works on 8 // binary clauses and is usually pretty fast. It will also find some failed 9 // literals (in the binary implication graph). 10 11 void Internal::transred () { 12 13 if (unsat) return; 14 if (terminated_asynchronously ()) return; 15 if (!stats.current.redundant && !stats.current.irredundant) return; 16 17 assert (opts.transred); 18 assert (!level); 19 20 START_SIMPLIFIER (transred, TRANSRED); 21 stats.transreds++; 22 23 // Transitive reduction can not be run to completion for larger formulas 24 // with many binary clauses. We bound it in the same way as 'probe_core'. 25 // 26 int64_t limit = stats.propagations.search; 27 limit -= last.transred.propagations; 28 limit *= 1e-3 * opts.transredreleff; 29 if (limit < opts.transredmineff) limit = opts.transredmineff; 30 if (limit > opts.transredmaxeff) limit = opts.transredmaxeff; 31 32 PHASE ("transred", stats.transreds, 33 "transitive reduction limit of %" PRId64 " propagations", limit); 34 35 const auto end = clauses.end (); 36 auto i = clauses.begin (); 37 38 // Find first clause not checked for being transitive yet. 39 // 40 for (; i != end; i++) { 41 Clause * c = *i; 42 if (c->garbage) continue; 43 if (c->size != 2) continue; 44 if (c->redundant && c->hyper) continue; 45 if (!c->transred) break; 46 } 47 48 // If all candidate clauses have been checked reschedule all. 49 // 50 if (i == end) { 51 52 PHASE ("transred", stats.transreds, 53 "rescheduling all clauses since no clauses to check left"); 54 for (i = clauses.begin (); i != end; i++) { 55 Clause * c = *i; 56 if (c->transred) c->transred = false; 57 } 58 i = clauses.begin (); 59 } 60 61 // Move watches of binary clauses to the front. Thus we can stop iterating 62 // watches as soon a long clause is found during watch traversal. 63 // 64 sort_watches (); 65 66 // This working stack plays the same role as the 'trail' during standard 67 // propagation. 68 // 69 vector<int> work; 70 71 int64_t propagations = 0, units = 0, removed = 0; 72 73 while (!unsat && 74 i != end && 75 !terminated_asynchronously () && 76 propagations < limit) 77 { 78 Clause * c = *i++; 79 80 // A clause is a candidate for being transitive if it is binary, and not 81 // the result of hyper binary resolution. The reason for excluding 82 // those, is that they come in large numbers, most of them are reduced 83 // away anyhow and further are non-transitive at the point they are 84 // added (see the code in 'hyper_binary_resolve' in 'prope.cpp' and 85 // also check out our CPAIOR paper on tree-based look ahead). 86 // 87 if (c->garbage) continue; 88 if (c->size != 2) continue; 89 if (c->redundant && c->hyper) continue; 90 if (c->transred) continue; // checked before? 91 c->transred = true; // marked as checked 92 93 LOG (c, "checking transitive reduction of"); 94 95 // Find a different path from 'src' to 'dst' in the binary implication 96 // graph, not using 'c'. Since this is the same as checking whether 97 // there is a path from '-dst' to '-src', we can do the reverse search 98 // if the number of watches of '-dst' is larger than those of 'src'. 99 // 100 int src = -c->literals[0]; 101 int dst = c->literals[1]; 102 if (val (src) || val (dst)) continue; 103 if (watches (-src).size () < watches (dst).size ()) { 104 int tmp = dst; 105 dst = -src; src = -tmp; 106 } 107 108 LOG ("searching path from %d to %d", src, dst); 109 110 // If the candidate clause is irredundant then we can not use redundant 111 // binary clauses in the implication graph. See our inprocessing rules 112 // paper, why this restriction is required. 113 // 114 const bool irredundant = !c->redundant; 115 116 assert (work.empty ()); 117 mark (src); 118 work.push_back (src); 119 LOG ("transred assign %d", src); 120 121 bool transitive = false; // found path from 'src' to 'dst'? 122 bool failed = false; // 'src' failed literal? 123 124 size_t j = 0; // 'propagated' in BFS 125 126 while (!transitive && !failed && j < work.size ()) { 127 const int lit = work[j++]; 128 assert (marked (lit) > 0); 129 LOG ("transred propagating %d", lit); 130 propagations++; 131 const Watches & ws = watches (-lit); 132 const const_watch_iterator eow = ws.end (); 133 const_watch_iterator k; 134 for (k = ws.begin (); !transitive && !failed && k != eow; k++) { 135 const Watch & w = *k; 136 if (!w.binary ()) break; // since we sorted watches above 137 Clause * d = w.clause; 138 if (d == c) continue; 139 if (irredundant && d->redundant) continue; 140 if (d->garbage) continue; 141 const int other = w.blit; 142 if (other == dst) transitive = true; // 'dst' reached 143 else { 144 const int tmp = marked (other); 145 if (tmp > 0) continue; 146 else if (tmp < 0) { 147 LOG ("found both %d and %d reachable", -other, other); 148 failed = true; 149 } else { 150 mark (other); 151 work.push_back (other); 152 LOG ("transred assign %d", other); 153 } 154 } 155 } 156 } 157 158 // Unassign all assigned literals (same as '[bp]acktrack'). 159 // 160 while (!work.empty ()) { 161 const int lit = work.back (); 162 work.pop_back (); 163 unmark (lit); 164 } 165 166 if (transitive) { 167 removed++; 168 stats.transitive++; 169 LOG (c, "transitive redundant"); 170 mark_garbage (c); 171 } else if (failed) { 172 units++; 173 LOG ("found failed literal %d during transitive reduction", src); 174 stats.failed++; 175 stats.transredunits++; 176 assign_unit (-src); 177 if (!propagate ()) { 178 VERBOSE (1, "propagating new unit results in conflict"); 179 learn_empty_clause (); 180 } 181 } 182 } 183 184 last.transred.propagations = stats.propagations.search; 185 stats.propagations.transred += propagations; 186 erase_vector (work); 187 188 PHASE ("transred", stats.transreds, 189 "removed %" PRId64 " transitive clauses, found %" PRId64 " units", 190 removed, units); 191 192 STOP_SIMPLIFIER (transred, TRANSRED); 193 report ('t', !opts.reportall && !(removed + units)); 194 } 195 196 } 在文件probe.cpp中 probe_round() 1 bool Internal::probe_round () { 2 3 if (unsat) return false; 4 if (terminated_asynchronously ()) return false; 5 6 START_SIMPLIFIER (probe, PROBE); 7 stats.probingrounds++; 8 9 // Probing is limited in terms of non-probing propagations 10 // 'stats.propagations'. We allow a certain percentage 'opts.probereleff' 11 // (say %5) of probing propagations in each probing with a lower bound of 12 // 'opts.probmineff'. 13 // 14 int64_t delta = stats.propagations.search; 15 delta -= last.probe.propagations; 16 delta *= 1e-3 * opts.probereleff; 17 if (delta < opts.probemineff) delta = opts.probemineff; 18 if (delta > opts.probemaxeff) delta = opts.probemaxeff; 19 delta += 2l * active (); 20 21 PHASE ("probe-round", stats.probingrounds, 22 "probing limit of %" PRId64 " propagations ", delta); 23 24 int64_t limit = stats.propagations.probe + delta; 25 26 int old_failed = stats.failed; 27 #ifndef QUIET 28 int64_t old_probed = stats.probed; 29 #endif 30 int64_t old_hbrs = stats.hbrs; 31 32 if (!probes.empty ()) flush_probes (); 33 34 // We reset 'propfixed' since there was at least another conflict thus 35 // a new learned clause, which might produce new propagations (and hyper 36 // binary resolvents). During 'generate_probes' we keep the old value. 37 // 38 for (auto idx : vars) 39 propfixed (idx) = propfixed (-idx) = -1; 40 41 assert (unsat || propagated == trail.size ()); 42 propagated = propagated2 = trail.size (); 43 44 int probe; 45 while (!unsat && 46 !terminated_asynchronously () && 47 stats.propagations.probe < limit && 48 (probe = next_probe ())) { 49 stats.probed++; 50 LOG ("probing %d", probe); 51 probe_assign_decision (probe); 52 if (probe_propagate ()) backtrack (); 53 else failed_literal (probe); 54 } 55 56 if (unsat) LOG ("probing derived empty clause"); 57 else if (propagated < trail.size ()) { 58 LOG ("probing produced %zd units", (size_t)(trail.size () - propagated)); 59 if (!propagate ()) { 60 LOG ("propagating units after probing results in empty clause"); 61 learn_empty_clause (); 62 } else sort_watches (); 63 } 64 65 int failed = stats.failed - old_failed; 66 #ifndef QUIET 67 int64_t probed = stats.probed - old_probed; 68 #endif 69 int64_t hbrs = stats.hbrs - old_hbrs; 70 71 PHASE ("probe-round", stats.probingrounds, 72 "probed %" PRId64 " and found %d failed literals", probed, failed); 73 74 if (hbrs) 75 PHASE ("probe-round", stats.probingrounds, 76 "found %" PRId64 " hyper binary resolvents", hbrs); 77 78 STOP_SIMPLIFIER (probe, PROBE); 79 80 report ('p', !opts.reportall && !(unsat + failed + hbrs)); 81 82 return !unsat && failed; 83 }
|
|