collect.cpp
有关子句满足性判断、在watches中位置调整、是否可以撤销、撤销空间前copy垃圾收集器、释放空间等
包括以下internal类型的成员函数:
| 1 | int Internal::clause_contains_fixed_literal (Clause * c); |
| 2 | void Internal::remove_falsified_literals (Clause * c); |
| 3 | void Internal::mark_satisfied_clauses_as_garbage () ; |
| 4 | void Internal::protect_reasons () ; |
| 5 | void Internal::unprotect_reasons (); |
| 6 | size_t Internal::flush_occs (int lit); |
| 7 | inline void Internal::flush_watches (int lit, Watches & saved); |
| 8 | void Internal::flush_all_occs_and_watches (); |
| 9 | void Internal::update_reason_references (); |
| 10 | void Internal::delete_garbage_clauses (); |
| 11 | void Internal::copy_clause (Clause * c); |
| 12 | void Internal::copy_non_garbage_clauses () |
| 13 | void Internal::check_clause_stats (); |
| 14 | bool Internal::arenaing (); |
| 15 | void Internal::garbage_collection (); |
代码解读
1.
|
Returns the positive number '1' ( > 0) if the given clause is root level satisfied or the negative number '-1' ( < 0) if it is not root level satisfied but contains a root level falsified literal. Otherwise, if it contains neither a satisfied nor falsified literal, then '0' is returned. 译文:如果给定子句满足根级别,则返回正数'1'(> 0);如果不满足根级别,但包含根级别假文字,则返回负数'-1'(< 0)。译文:否则,如果它既不包含满意的字面值,也不包含伪造的字面值,则返回'0'。
|
|
1 // Returns the positive number '1' ( > 0) if the given clause is root level 2 // satisfied or the negative number '-1' ( < 0) if it is not root level 3 // satisfied but contains a root level falsified literal. Otherwise, if it 4 // contains neither a satisfied nor falsified literal, then '0' is returned. 5 6 int Internal::clause_contains_fixed_literal (Clause * c) { 7 int satisfied = 0, falsified = 0; 8 for (const auto & lit : *c) { 9 const int tmp = fixed (lit); 10 if (tmp > 0) { 11 LOG (c, "root level satisfied literal %d in", lit); 12 satisfied++; 13 } 14 if (tmp < 0) { 15 LOG (c, "root level falsified literal %d in", lit); 16 falsified++; 17 } 18 } 19 if (satisfied) return 1; 20 else if (falsified) return -1; 21 else return 0; 22 }
|
2
|
Assume that the clause is not root level satisfied but contains a literal 假设子句没有满足根级别,但包含一个设为false的文字(根级别伪文本),所以它可以缩小。此时,子句数据并没有实际重新分配,以避免处理监视二进制子句的特殊策略或子句是否被扩展的问题。只有它的大小字段会在清空根级别伪字面值后进行相应的调整。 |
|
1 void Internal::remove_falsified_literals (Clause * c) { 2 const const_literal_iterator end = c->end (); 3 const_literal_iterator i; 4 int num_non_false = 0; 5 for (i = c->begin (); num_non_false < 2 && i != end; i++) 6 if (fixed (*i) >= 0) num_non_false++; 7 if (num_non_false < 2) return; 8 if (proof) proof->flush_clause (c); 9 literal_iterator j = c->begin (); 10 for (i = j; i != end; i++) { 11 const int lit = *j++ = *i, tmp = fixed (lit); 12 assert (tmp <= 0); 13 if (tmp >= 0) continue; 14 LOG ("flushing %d", lit); 15 j--; 16 } 17 stats.collected += shrink_clause (c, j - c->begin ()); 18 }
|
3.
|
If there are new units (fixed variables) since the last garbage collection we go over all clauses, mark satisfied ones as garbage and flush falsified literals. Otherwise if no new units have been generated since the last garbage collection just skip this step. 译文:如果在上次垃圾收集之后出现了新的单元(固定变量),我们将检查所有子句,将满足要求的子句标记为垃圾并刷新伪造的字面值。否则,如果自上次垃圾收集以来没有生成新的单元,则跳过此步骤。 |
|
1 // If there are new units (fixed variables) since the last garbage 2 // collection we go over all clauses, mark satisfied ones as garbage and 3 // flush falsified literals. Otherwise if no new units have been generated 4 // since the last garbage collection just skip this step. 5 6 void Internal::mark_satisfied_clauses_as_garbage () { 7 8 if (last.collect.fixed >= stats.all.fixed) return; 9 last.collect.fixed = stats.all.fixed; 10 11 LOG ("marking satisfied clauses and removing falsified literals"); 12 13 for (const auto & c : clauses) { 14 if (c->garbage) continue; 15 const int tmp = clause_contains_fixed_literal (c); 16 if (tmp > 0) mark_garbage (c); 17 else if (tmp < 0) remove_falsified_literals (c); 18 } 19 }
|
4.
|
// Reason clauses can not be collected. |
|
1 /*------------------------------------------------------------------------*/ 2 3 // Reason clauses can not be collected. 4 // 5 // We protect reasons before and release protection after garbage collection 6 // (actually within garbage collection). 7 // 8 // For 'reduce' we still need to make sure that all clauses which should not 9 // be removed are marked as such and thus we need to call it before marking 10 // clauses to be flushed. 11 12 void Internal::protect_reasons () { 13 LOG ("protecting reason clauses of all assigned variables on trail"); 14 assert (!protected_reasons); 15 size_t count = 0; 16 for (const auto & lit : trail) { 17 if (!active (lit)) continue; 18 assert (val (lit)); 19 Var & v = var (lit); 20 assert (v.level > 0); 21 Clause * reason = v.reason; 22 if (!reason) continue; 23 LOG (reason, "protecting assigned %d reason %p", lit, reason); 24 assert (!reason->reason); 25 reason->reason = true; 26 count++; 27 } 28 LOG ("protected %zd reason clauses referenced on trail", count); 29 protected_reasons = true; 30 }
|
5.
|
After garbage collection we reset the 'reason' flag of the reasons 译文:在垃圾收集之后,我们在轨迹中重置了指定文本的原因的“reason”标志。 |
|
/*------------------------------------------------------------------------*/ // After garbage collection we reset the 'reason' flag of the reasons // of assigned literals on the trail. void Internal::unprotect_reasons () { LOG ("unprotecting reasons clauses of all assigned variables on trail"); assert (protected_reasons); size_t count = 0; for (const auto & lit : trail) { if (!active (lit)) continue; assert (val (lit)); Var & v = var (lit); assert (v.level > 0); Clause * reason = v.reason; if (!reason) continue; LOG (reason, "unprotecting assigned %d reason %p", lit, reason); assert (reason->reason); reason->reason = false; count++; } LOG ("unprotected %zd reason clauses referenced on trail", count); protected_reasons = false; }
|
6.
|
Update occurrence lists before deleting garbage clauses in the context of 在预处理的上下文中,在删除垃圾子句之前更新发生列表,例如在有界变量消除“elim”期间。 结果是剩余子句的数量,在这里是指非垃圾子句的数量。 |
|
1 /*------------------------------------------------------------------------*/ 2 3 // Update occurrence lists before deleting garbage clauses in the context of 4 // preprocessing, e.g., during bounded variable elimination 'elim'. The 5 // result is the number of remaining clauses, which in this context means 6 // the number of non-garbage clauses. 7 8 size_t Internal::flush_occs (int lit) { 9 Occs & os = occs (lit); 10 const const_occs_iterator end = os.end (); 11 occs_iterator j = os.begin (); 12 const_occs_iterator i; 13 size_t res = 0; 14 Clause * c; 15 for (i = j; i != end; i++) { 16 c = *i; 17 if (c->collect ()) continue; 18 *j++ = c->moved ? c->copy : c; 19 assert (!c->redundant); 20 res++; 21 } 22 os.resize (j - os.begin ()); 23 shrink_occs (os); 24 return res; 25 }
|
7. 8.
|
Update watch lists before deleting garbage clauses in the context of 在删除“reduce”上下文中的垃圾子句之前更新观察列表,在这里我们观察和没有发生列表。我们必须保护reason子句不被收集,因此我们有这个额外的检查隐藏在'子句。对于预处理的根级上下文来说,它实际上是多余的。 |
|
// Update watch lists before deleting garbage clauses in the context of // 'reduce' where we watch and no occurrence lists. We have to protect // reason clauses not be collected and thus we have this additional check // hidden in 'Clause.collect', which for the root level context of // preprocessing is actually redundant. inline void Internal::flush_watches (int lit, Watches & saved) { assert (saved.empty ()); Watches & ws = watches (lit); const const_watch_iterator end = ws.end (); watch_iterator j = ws.begin (); const_watch_iterator i; for (i = j; i != end; i++) { Watch w = *i; Clause * c = w.clause; if (c->collect ()) continue; if (c->moved) c = w.clause = c->copy; w.size = c->size; const int new_blit_pos = (c->literals[0] == lit); assert (c->literals[!new_blit_pos] == lit); /*FW1*/ w.blit = c->literals[new_blit_pos]; if (w.binary ()) *j++ = w; else saved.push_back (w); } ws.resize (j - ws.begin ()); for (const auto & w : saved) ws.push_back (w); saved.clear (); shrink_vector (ws); }
|
|
1 void Internal::flush_all_occs_and_watches () { 2 if (occurring ()) 3 for (auto idx : vars) 4 flush_occs (idx), flush_occs (-idx); 5 6 if (watching ()) { 7 Watches tmp; 8 for (auto idx : vars) 9 flush_watches (idx, tmp), flush_watches (-idx, tmp); 10 } 11 }
|
9.
1 /*------------------------------------------------------------------------*/ 2 3 void Internal::update_reason_references () { 4 LOG ("update assigned reason references"); 5 size_t count = 0; 6 for (auto & lit : trail) { 7 if (!active (lit)) continue; 8 Var & v = var (lit); 9 Clause * c = v.reason; 10 if (!c) continue; 11 LOG (c, "updating assigned %d reason", lit); 12 assert (c->reason); 13 assert (c->moved); 14 Clause * d = c->copy; 15 v.reason = d; 16 count++; 17 } 18 LOG ("updated %zd assigned reason references", count); 19 }
|
|
10.
|
This is a simple garbage collector which does not move clauses. It needs 译文:这是一个不移动子句的简单垃圾收集器。 它比基于arena的子句分配器需要更少的空间,但缓存效率不高, 因为复制垃圾收集器可以将子句放在一起,这些子句可能会被依次访问。 |
|
1 /*------------------------------------------------------------------------*/ 2 3 // This is a simple garbage collector which does not move clauses. It needs 4 // less space than the arena based clause allocator, but is not as cache 5 // efficient, since the copying garbage collector can put clauses together 6 // which are likely accessed after each other. 7 8 void Internal::delete_garbage_clauses () { 9 10 flush_all_occs_and_watches (); 11 12 LOG ("deleting garbage clauses"); 13 int64_t collected_bytes = 0, collected_clauses = 0; 14 const auto end = clauses.end (); 15 auto j = clauses.begin (), i = j; 16 while (i != end) { 17 Clause * c = *j++ = *i++; 18 if (!c->collect ()) continue; 19 collected_bytes += c->bytes (); 20 collected_clauses++; 21 delete_clause (c); 22 j--; 23 } 24 clauses.resize (j - clauses.begin ()); 25 shrink_vector (clauses); 26 27 PHASE ("collect", stats.collections, 28 "collected %" PRId64 " bytes of %" PRId64 " garbage clauses", 29 collected_bytes, collected_clauses); 30 }
|
11.
|
This is the start of the copying garbage collector using the arena. At 译文:这是使用arena复制垃圾收集器的开始。核心是以下函数, 它将一个子句复制到arena的“to”空间。如果这一条款是一个分配的原因, 要小心。在这种情况下,更新原因引用 |
|
1 /*------------------------------------------------------------------------*/ 2 3 // This is the start of the copying garbage collector using the arena. At 4 // the core is the following function, which copies a clause to the 'to' 5 // space of the arena. Be careful if this clause is a reason of an 6 // assignment. In that case update the reason reference. 7 // 8 void Internal::copy_clause (Clause * c) { 9 LOG (c, "moving"); 10 assert (!c->moved); 11 char * p = (char*) c; 12 char * q = arena.copy (p, c->bytes ()); 13 c->copy = (Clause *) q; 14 c->moved = true; 15 LOG ("copied clause[%" PRId64 "] from %p to %p", c->id, c, c->copy); 16 }
|
12.
|
// This is the moving garbage collector.译文:这是移动的垃圾收集器。
// Localize according to current clause order.译文:根据当前子句顺序进行本地化 // If the option 'opts.arenatype == 1' is set, then this means the // Copy clauses according to the order of calling 'copy_clause', which
// Localize according to (original) variable order. // This is almost the version used by MiniSAT and descendants.
// Localize according to decision queue order. // This is the default for search. It allocates clauses in the order of
|
|
1 // This is the moving garbage collector. 2 3 void Internal::copy_non_garbage_clauses () { 4 5 size_t collected_clauses = 0, collected_bytes = 0; 6 size_t moved_clauses = 0, moved_bytes = 0; 7 8 // First determine 'moved_bytes' and 'collected_bytes'. 9 // 10 for (const auto & c : clauses) 11 if (!c->collect ()) moved_bytes += c->bytes (), moved_clauses++; 12 else collected_bytes += c->bytes (), collected_clauses++; 13 14 PHASE ("collect", stats.collections, 15 "moving %zd bytes %.0f%% of %zd non garbage clauses", 16 moved_bytes, 17 percent (moved_bytes, collected_bytes + moved_bytes), 18 moved_clauses); 19 20 // Prepare 'to' space of size 'moved_bytes'. 21 // 22 arena.prepare (moved_bytes); 23 24 // Keep clauses in arena in the same order. 25 // 26 if (opts.arenacompact) 27 for (const auto & c : clauses) 28 if (!c->collect () && arena.contains (c)) 29 copy_clause (c); 30 31 if (opts.arenatype == 1 || !watching ()) { 32 33 // Localize according to current clause order. 34 35 // If the option 'opts.arenatype == 1' is set, then this means the 36 // solver uses the original order of clauses. If there are no watches, 37 // we can not use the watched based copying policies below. This 38 // happens if garbage collection is triggered during bounded variable 39 // elimination. 40 41 // Copy clauses according to the order of calling 'copy_clause', which 42 // in essence just gives a compacting garbage collector, since their 43 // relative order is kept, and actually already gives the largest 44 // benefit due to better cache locality. 45 46 for (const auto & c : clauses) 47 if (!c->moved && !c->collect ()) 48 copy_clause (c); 49 50 } else if (opts.arenatype == 2) { 51 52 // Localize according to (original) variable order. 53 54 // This is almost the version used by MiniSAT and descendants. 55 // Our version uses saved phases too. 56 57 for (int sign = -1; sign <= 1; sign += 2) 58 for (auto idx : vars) 59 for (const auto & w : watches (sign * likely_phase (idx))) 60 if (!w.clause->moved && !w.clause->collect ()) 61 copy_clause (w.clause); 62 63 } else { 64 65 // Localize according to decision queue order. 66 67 // This is the default for search. It allocates clauses in the order of 68 // the decision queue and also uses saved phases. It seems faster than 69 // the MiniSAT version and thus we keep 'opts.arenatype == 3'. 70 71 assert (opts.arenatype == 3); 72 73 for (int sign = -1; sign <= 1; sign += 2) 74 for (int idx = queue.last; idx; idx = link (idx).prev) 75 for (const auto & w : watches (sign * likely_phase (idx))) 76 if (!w.clause->moved && !w.clause->collect ()) 77 copy_clause (w.clause); 78 } 79 80 // Do not forget to move clauses which are not watched, which happened in 81 // a rare situation, and now is only left as defensive code. 82 // 83 for (const auto & c : clauses) 84 if (!c->collect () && !c->moved) 85 copy_clause (c); 86 87 flush_all_occs_and_watches (); 88 update_reason_references (); 89 90 // Replace and flush clause references in 'clauses'. 91 // 92 const auto end = clauses.end (); 93 auto j = clauses.begin (), i = j; 94 for (; i != end; i++) { 95 Clause * c = *i; 96 if (c->collect ()) delete_clause (c); 97 else assert (c->moved), *j++ = c->copy, deallocate_clause (c); 98 } 99 clauses.resize (j - clauses.begin ()); 100 if (clauses.size () < clauses.capacity ()/2) shrink_vector (clauses); 101 102 if (opts.arenasort) 103 rsort (clauses.begin (), clauses.end (), pointer_rank ()); 104 105 // Release 'from' space completely and then swap 'to' with 'from'. 106 // 107 arena.swap (); 108 109 PHASE ("collect", stats.collections, 110 "collected %zd bytes %.0f%% of %zd garbage clauses", 111 collected_bytes, 112 percent (collected_bytes, collected_bytes + moved_bytes), 113 collected_clauses); 114 }
|
13.
|
Maintaining clause statistics is complex and error prone but necessary 译文:维护子句统计信息是复杂且容易出错的,但对于垃圾收集的适当调度是必要的, 特别是在有界变量消除期间。使用这个函数,我们可以检查这些统计信息是否被正确更新。 |
|
1 /*------------------------------------------------------------------------*/ 2 3 // Maintaining clause statistics is complex and error prone but necessary 4 // for proper scheduling of garbage collection, particularly during bounded 5 // variable elimination. With this function we can check whether these 6 // statistics are updated correctly. 7 8 void Internal::check_clause_stats () { 9 #ifndef NDEBUG 10 int64_t irredundant = 0, redundant = 0, total = 0, irrbytes = 0; 11 for (const auto & c : clauses) { 12 if (c->garbage) continue; 13 if (c->redundant) redundant++; else irredundant++; 14 if (!c->redundant) irrbytes += c->bytes (); 15 total++; 16 } 17 assert (stats.current.irredundant == irredundant); 18 assert (stats.current.redundant == redundant); 19 assert (stats.current.total == total); 20 assert (stats.irrbytes == irrbytes); 21 #endif 22 }
|
14
1 /*------------------------------------------------------------------------*/ 2 3 bool Internal::arenaing () { 4 return opts.arena && (stats.collections > 1); 5 }
|
15.
1 void Internal::garbage_collection () { 2 if (unsat) return; 3 START (collect); 4 report ('G', 1); 5 stats.collections++; 6 mark_satisfied_clauses_as_garbage (); 7 if (!protected_reasons) protect_reasons (); 8 if (arenaing ()) copy_non_garbage_clauses (); 9 else delete_garbage_clauses (); 10 check_clause_stats (); 11 check_var_stats (); 12 unprotect_reasons (); 13 report ('C', 1); 14 STOP (collect); 15 }
|
|
浙公网安备 33010602011771号