cadical 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +26 -0
  3. data/README.md +101 -0
  4. data/ext/cadical/cadical/LICENSE +28 -0
  5. data/ext/cadical/cadical/README.md +65 -0
  6. data/ext/cadical/cadical/VERSION +1 -0
  7. data/ext/cadical/cadical/src/analyze.cpp +1360 -0
  8. data/ext/cadical/cadical/src/arena.cpp +30 -0
  9. data/ext/cadical/cadical/src/arena.hpp +105 -0
  10. data/ext/cadical/cadical/src/assume.cpp +616 -0
  11. data/ext/cadical/cadical/src/averages.cpp +34 -0
  12. data/ext/cadical/cadical/src/averages.hpp +37 -0
  13. data/ext/cadical/cadical/src/backbone.cpp +631 -0
  14. data/ext/cadical/cadical/src/backtrack.cpp +177 -0
  15. data/ext/cadical/cadical/src/backward.cpp +231 -0
  16. data/ext/cadical/cadical/src/bins.cpp +22 -0
  17. data/ext/cadical/cadical/src/bins.hpp +22 -0
  18. data/ext/cadical/cadical/src/block.cpp +824 -0
  19. data/ext/cadical/cadical/src/block.hpp +37 -0
  20. data/ext/cadical/cadical/src/cadical.cpp +1026 -0
  21. data/ext/cadical/cadical/src/cadical.hpp +1419 -0
  22. data/ext/cadical/cadical/src/ccadical.cpp +208 -0
  23. data/ext/cadical/cadical/src/ccadical.h +74 -0
  24. data/ext/cadical/cadical/src/checker.cpp +649 -0
  25. data/ext/cadical/cadical/src/checker.hpp +173 -0
  26. data/ext/cadical/cadical/src/clause.cpp +689 -0
  27. data/ext/cadical/cadical/src/clause.hpp +190 -0
  28. data/ext/cadical/cadical/src/collect.cpp +545 -0
  29. data/ext/cadical/cadical/src/compact.cpp +550 -0
  30. data/ext/cadical/cadical/src/condition.cpp +940 -0
  31. data/ext/cadical/cadical/src/config.cpp +101 -0
  32. data/ext/cadical/cadical/src/config.hpp +20 -0
  33. data/ext/cadical/cadical/src/congruence.cpp +7880 -0
  34. data/ext/cadical/cadical/src/congruence.hpp +757 -0
  35. data/ext/cadical/cadical/src/constrain.cpp +64 -0
  36. data/ext/cadical/cadical/src/contract.cpp +27 -0
  37. data/ext/cadical/cadical/src/contract.hpp +139 -0
  38. data/ext/cadical/cadical/src/cover.cpp +704 -0
  39. data/ext/cadical/cadical/src/cover.hpp +34 -0
  40. data/ext/cadical/cadical/src/decide.cpp +347 -0
  41. data/ext/cadical/cadical/src/decompose.cpp +738 -0
  42. data/ext/cadical/cadical/src/decompose.hpp +23 -0
  43. data/ext/cadical/cadical/src/deduplicate.cpp +275 -0
  44. data/ext/cadical/cadical/src/definition.cpp +283 -0
  45. data/ext/cadical/cadical/src/delay.hpp +38 -0
  46. data/ext/cadical/cadical/src/drattracer.cpp +153 -0
  47. data/ext/cadical/cadical/src/drattracer.hpp +55 -0
  48. data/ext/cadical/cadical/src/elim.cpp +1171 -0
  49. data/ext/cadical/cadical/src/elim.hpp +53 -0
  50. data/ext/cadical/cadical/src/elimfast.cpp +570 -0
  51. data/ext/cadical/cadical/src/ema.cpp +95 -0
  52. data/ext/cadical/cadical/src/ema.hpp +68 -0
  53. data/ext/cadical/cadical/src/extend.cpp +289 -0
  54. data/ext/cadical/cadical/src/external.cpp +1034 -0
  55. data/ext/cadical/cadical/src/external.hpp +487 -0
  56. data/ext/cadical/cadical/src/external_propagate.cpp +1316 -0
  57. data/ext/cadical/cadical/src/factor.cpp +1011 -0
  58. data/ext/cadical/cadical/src/factor.hpp +54 -0
  59. data/ext/cadical/cadical/src/file.cpp +506 -0
  60. data/ext/cadical/cadical/src/file.hpp +210 -0
  61. data/ext/cadical/cadical/src/flags.cpp +135 -0
  62. data/ext/cadical/cadical/src/flags.hpp +93 -0
  63. data/ext/cadical/cadical/src/flip.cpp +269 -0
  64. data/ext/cadical/cadical/src/format.cpp +89 -0
  65. data/ext/cadical/cadical/src/format.hpp +36 -0
  66. data/ext/cadical/cadical/src/frattracer.cpp +277 -0
  67. data/ext/cadical/cadical/src/frattracer.hpp +67 -0
  68. data/ext/cadical/cadical/src/gates.cpp +766 -0
  69. data/ext/cadical/cadical/src/heap.hpp +212 -0
  70. data/ext/cadical/cadical/src/idruptracer.cpp +566 -0
  71. data/ext/cadical/cadical/src/idruptracer.hpp +112 -0
  72. data/ext/cadical/cadical/src/instantiate.cpp +365 -0
  73. data/ext/cadical/cadical/src/instantiate.hpp +45 -0
  74. data/ext/cadical/cadical/src/internal.cpp +1265 -0
  75. data/ext/cadical/cadical/src/internal.hpp +1941 -0
  76. data/ext/cadical/cadical/src/inttypes.hpp +34 -0
  77. data/ext/cadical/cadical/src/ipasir.cpp +47 -0
  78. data/ext/cadical/cadical/src/ipasir.h +37 -0
  79. data/ext/cadical/cadical/src/kitten.c +2599 -0
  80. data/ext/cadical/cadical/src/kitten.h +97 -0
  81. data/ext/cadical/cadical/src/level.hpp +33 -0
  82. data/ext/cadical/cadical/src/lidruptracer.cpp +657 -0
  83. data/ext/cadical/cadical/src/lidruptracer.hpp +122 -0
  84. data/ext/cadical/cadical/src/limit.cpp +146 -0
  85. data/ext/cadical/cadical/src/limit.hpp +168 -0
  86. data/ext/cadical/cadical/src/logging.cpp +214 -0
  87. data/ext/cadical/cadical/src/logging.hpp +98 -0
  88. data/ext/cadical/cadical/src/lookahead.cpp +520 -0
  89. data/ext/cadical/cadical/src/lratchecker.cpp +833 -0
  90. data/ext/cadical/cadical/src/lratchecker.hpp +168 -0
  91. data/ext/cadical/cadical/src/lrattracer.cpp +200 -0
  92. data/ext/cadical/cadical/src/lrattracer.hpp +61 -0
  93. data/ext/cadical/cadical/src/lucky.cpp +506 -0
  94. data/ext/cadical/cadical/src/message.cpp +218 -0
  95. data/ext/cadical/cadical/src/message.hpp +65 -0
  96. data/ext/cadical/cadical/src/minimize.cpp +224 -0
  97. data/ext/cadical/cadical/src/mobical.cpp +5588 -0
  98. data/ext/cadical/cadical/src/occs.cpp +52 -0
  99. data/ext/cadical/cadical/src/occs.hpp +36 -0
  100. data/ext/cadical/cadical/src/options.cpp +359 -0
  101. data/ext/cadical/cadical/src/options.hpp +442 -0
  102. data/ext/cadical/cadical/src/parse.cpp +471 -0
  103. data/ext/cadical/cadical/src/parse.hpp +75 -0
  104. data/ext/cadical/cadical/src/phases.cpp +56 -0
  105. data/ext/cadical/cadical/src/phases.hpp +19 -0
  106. data/ext/cadical/cadical/src/probe.cpp +990 -0
  107. data/ext/cadical/cadical/src/profile.cpp +107 -0
  108. data/ext/cadical/cadical/src/profile.hpp +283 -0
  109. data/ext/cadical/cadical/src/proof.cpp +691 -0
  110. data/ext/cadical/cadical/src/proof.hpp +125 -0
  111. data/ext/cadical/cadical/src/propagate.cpp +584 -0
  112. data/ext/cadical/cadical/src/queue.cpp +90 -0
  113. data/ext/cadical/cadical/src/queue.hpp +74 -0
  114. data/ext/cadical/cadical/src/radix.hpp +180 -0
  115. data/ext/cadical/cadical/src/random.cpp +207 -0
  116. data/ext/cadical/cadical/src/random.h +44 -0
  117. data/ext/cadical/cadical/src/random.hpp +98 -0
  118. data/ext/cadical/cadical/src/range.hpp +125 -0
  119. data/ext/cadical/cadical/src/reap.cpp +127 -0
  120. data/ext/cadical/cadical/src/reap.hpp +28 -0
  121. data/ext/cadical/cadical/src/reduce.cpp +278 -0
  122. data/ext/cadical/cadical/src/reluctant.hpp +82 -0
  123. data/ext/cadical/cadical/src/rephase.cpp +402 -0
  124. data/ext/cadical/cadical/src/report.cpp +313 -0
  125. data/ext/cadical/cadical/src/resources.cpp +160 -0
  126. data/ext/cadical/cadical/src/resources.hpp +16 -0
  127. data/ext/cadical/cadical/src/restart.cpp +178 -0
  128. data/ext/cadical/cadical/src/restore.cpp +267 -0
  129. data/ext/cadical/cadical/src/score.cpp +51 -0
  130. data/ext/cadical/cadical/src/score.hpp +16 -0
  131. data/ext/cadical/cadical/src/shrink.cpp +507 -0
  132. data/ext/cadical/cadical/src/signal.cpp +136 -0
  133. data/ext/cadical/cadical/src/signal.hpp +33 -0
  134. data/ext/cadical/cadical/src/solution.cpp +50 -0
  135. data/ext/cadical/cadical/src/solver.cpp +1871 -0
  136. data/ext/cadical/cadical/src/stable.cpp +31 -0
  137. data/ext/cadical/cadical/src/stack.h +110 -0
  138. data/ext/cadical/cadical/src/stats.cpp +920 -0
  139. data/ext/cadical/cadical/src/stats.hpp +418 -0
  140. data/ext/cadical/cadical/src/subsume.cpp +645 -0
  141. data/ext/cadical/cadical/src/sweep.cpp +1960 -0
  142. data/ext/cadical/cadical/src/sweep.hpp +61 -0
  143. data/ext/cadical/cadical/src/terminal.cpp +38 -0
  144. data/ext/cadical/cadical/src/terminal.hpp +96 -0
  145. data/ext/cadical/cadical/src/ternary.cpp +450 -0
  146. data/ext/cadical/cadical/src/testing.hpp +24 -0
  147. data/ext/cadical/cadical/src/tier.cpp +189 -0
  148. data/ext/cadical/cadical/src/tracer.hpp +186 -0
  149. data/ext/cadical/cadical/src/transred.cpp +253 -0
  150. data/ext/cadical/cadical/src/unstable.cpp +29 -0
  151. data/ext/cadical/cadical/src/util.cpp +129 -0
  152. data/ext/cadical/cadical/src/util.hpp +181 -0
  153. data/ext/cadical/cadical/src/var.cpp +39 -0
  154. data/ext/cadical/cadical/src/var.hpp +22 -0
  155. data/ext/cadical/cadical/src/veripbtracer.cpp +427 -0
  156. data/ext/cadical/cadical/src/veripbtracer.hpp +106 -0
  157. data/ext/cadical/cadical/src/version.cpp +107 -0
  158. data/ext/cadical/cadical/src/version.hpp +13 -0
  159. data/ext/cadical/cadical/src/vivify.cpp +1893 -0
  160. data/ext/cadical/cadical/src/vivify.hpp +50 -0
  161. data/ext/cadical/cadical/src/walk.cpp +1088 -0
  162. data/ext/cadical/cadical/src/walk.hpp +91 -0
  163. data/ext/cadical/cadical/src/walk_full_occs.cpp +966 -0
  164. data/ext/cadical/cadical/src/warmup.cpp +403 -0
  165. data/ext/cadical/cadical/src/watch.cpp +126 -0
  166. data/ext/cadical/cadical/src/watch.hpp +77 -0
  167. data/ext/cadical/cadical_ext.c +778 -0
  168. data/ext/cadical/extconf.rb +26 -0
  169. data/lib/cadical/version.rb +3 -0
  170. data/lib/cadical.rb +12 -0
  171. metadata +218 -0
@@ -0,0 +1,125 @@
1
+ #ifndef _proof_h_INCLUDED
2
+ #define _proof_h_INCLUDED
3
+
4
+ #include "tracer.hpp"
5
+ #include <stdint.h>
6
+
7
+ namespace CaDiCaL {
8
+
9
+ /*------------------------------------------------------------------------*/
10
+
11
+ class File;
12
+ struct Clause;
13
+ struct Internal;
14
+ class Tracer;
15
+ class FileTracer;
16
+
17
+ /*------------------------------------------------------------------------*/
18
+
19
+ // Provides proof checking and writing.
20
+
21
+ class Proof {
22
+
23
+ Internal *internal;
24
+
25
+ std::vector<int> clause; // of external literals
26
+ std::vector<int64_t> proof_chain; // LRAT style proof chain of clause
27
+ int64_t clause_id; // id of added clause
28
+ bool redundant;
29
+ int witness;
30
+
31
+ // the 'tracers'
32
+ std::vector<Tracer *> tracers; // tracers (ie checker)
33
+ std::vector<FileTracer *> file_tracers; // file tracers (ie LRAT tracer)
34
+
35
+ void add_literal (int internal_lit); // add to 'clause'
36
+ void add_literals (Clause *); // add to 'clause'
37
+
38
+ void add_literals (const std::vector<int> &); // ditto
39
+
40
+ void add_original_clause (
41
+ bool restore = false); // notify observers of original clauses
42
+ void add_derived_clause ();
43
+ void add_assumption_clause ();
44
+ void delete_clause ();
45
+ void demote_clause ();
46
+ void weaken_minus ();
47
+ void strengthen ();
48
+ void finalize_clause ();
49
+ void add_assumption ();
50
+ void add_constraint ();
51
+
52
+ public:
53
+ Proof (Internal *);
54
+ ~Proof ();
55
+
56
+ void connect (Tracer *t) { tracers.push_back (t); }
57
+ void disconnect (Tracer *t);
58
+ // Add original clauses to the proof (for online proof checking).
59
+ //
60
+ void add_original_clause (int64_t, bool, const std::vector<int> &);
61
+
62
+ void add_assumption_clause (int64_t, const std::vector<int> &,
63
+ const std::vector<int64_t> &);
64
+ void add_assumption_clause (int64_t, int, const std::vector<int64_t> &);
65
+ void add_assumption (int);
66
+ void add_constraint (const std::vector<int> &);
67
+ void reset_assumptions ();
68
+
69
+ // Add/delete original clauses to/from the proof using their original
70
+ // external literals (from external->eclause)
71
+ //
72
+ void add_external_original_clause (int64_t, bool,
73
+ const std::vector<int> &,
74
+ bool restore = false);
75
+ void delete_external_original_clause (int64_t, bool,
76
+ const std::vector<int> &);
77
+
78
+ // Add derived (such as learned) clauses to the proof.
79
+ //
80
+ void add_derived_empty_clause (int64_t, const std::vector<int64_t> &);
81
+ void add_derived_unit_clause (int64_t, int unit,
82
+ const std::vector<int64_t> &);
83
+ void add_derived_clause (Clause *c, const std::vector<int64_t> &);
84
+ void add_derived_clause (int64_t, bool, const std::vector<int> &,
85
+ const std::vector<int64_t> &);
86
+ void add_derived_rat_clause (int64_t, bool, int, const std::vector<int> &,
87
+ const std::vector<int64_t> &);
88
+ void add_derived_rat_clause (Clause *c, int w,
89
+ const std::vector<int64_t> &);
90
+
91
+ // deletion of clauses. It comes in several variants, depending if the
92
+ // clause should be restored or not
93
+ void delete_clause (int64_t, bool, const std::vector<int> &);
94
+ void weaken_minus (int64_t, const std::vector<int> &);
95
+ void weaken_plus (int64_t, const std::vector<int> &);
96
+ void delete_unit_clause (int64_t id, const int lit);
97
+ void delete_clause (Clause *);
98
+ void weaken_minus (Clause *);
99
+ void weaken_plus (Clause *);
100
+ void strengthen (int64_t);
101
+
102
+ void finalize_unit (int64_t, int);
103
+ void finalize_external_unit (int64_t, int);
104
+ void finalize_clause (int64_t, const std::vector<int> &c);
105
+ void finalize_clause (Clause *);
106
+
107
+ void report_status (int, int64_t);
108
+ void begin_proof (int64_t);
109
+ void conclude_unsat (ConclusionType, const std::vector<int64_t> &);
110
+ void conclude_sat (const std::vector<int> &model);
111
+ void conclude_unknown (const std::vector<int> &trace);
112
+ void solve_query ();
113
+ // These two actually pretend to add and remove a clause.
114
+ //
115
+ void flush_clause (Clause *); // remove falsified literals
116
+ void strengthen_clause (Clause *, int, const std::vector<int64_t> &);
117
+ void otfs_strengthen_clause (Clause *, const std::vector<int> &,
118
+ const std::vector<int64_t> &);
119
+
120
+ void flush ();
121
+ };
122
+
123
+ } // namespace CaDiCaL
124
+
125
+ #endif
@@ -0,0 +1,584 @@
1
+ #include "internal.hpp"
2
+
3
+ namespace CaDiCaL {
4
+
5
+ /*------------------------------------------------------------------------*/
6
+
7
+ // We are using the address of 'decision_reason' as pseudo reason for
8
+ // decisions to distinguish assignment decisions from other assignments.
9
+ // Before we added chronological backtracking all learned units were
10
+ // assigned at decision level zero ('Solver.level == 0') and we just used a
11
+ // zero pointer as reason. After allowing chronological backtracking units
12
+ // were also assigned at higher decision level (but with assignment level
13
+ // zero), and it was not possible anymore to just distinguish the case
14
+ // 'unit' versus 'decision' by just looking at the current level. Both had
15
+ // a zero pointer as reason. Now only units have a zero reason and
16
+ // decisions need to use the pseudo reason 'decision_reason'.
17
+
18
+ // External propagation steps use the pseudo reason 'external_reason'.
19
+ // The corresponding actual reason clauses are learned only when they are
20
+ // relevant in conflict analysis or in root-level fixing steps.
21
+
22
+ static Clause decision_reason_clause;
23
+ Clause *Internal::decision_reason = &decision_reason_clause;
24
+
25
+ // If chronological backtracking is used the actual assignment level might
26
+ // be lower than the current decision level. In this case the assignment
27
+ // level is defined as the maximum level of the literals in the reason
28
+ // clause except the literal for which the clause is a reason. This
29
+ // function determines this assignment level. For non-chronological
30
+ // backtracking as in classical CDCL this function always returns the
31
+ // current decision level, the concept of assignment level does not make
32
+ // sense, and accordingly this function can be skipped.
33
+
34
+ // In case of external propagation, it is implicitly assumed that the
35
+ // assignment level is the level of the literal (since the reason clause,
36
+ // i.e., the set of other literals, is unknown).
37
+
38
+ inline int Internal::assignment_level (int lit, Clause *reason) {
39
+
40
+ assert (opts.chrono || external_prop);
41
+ if (!reason || reason == external_reason)
42
+ return level;
43
+
44
+ int res = 0;
45
+
46
+ for (const auto &other : *reason) {
47
+ if (other == lit)
48
+ continue;
49
+ assert (val (other));
50
+ int tmp = var (other).level;
51
+ if (tmp > res)
52
+ res = tmp;
53
+ }
54
+
55
+ return res;
56
+ }
57
+
58
+ // calculate lrat_chain
59
+ //
60
+ void Internal::build_chain_for_units (int lit, Clause *reason,
61
+ bool forced) {
62
+ if (!lrat)
63
+ return;
64
+ if (opts.chrono && assignment_level (lit, reason) && !forced)
65
+ return;
66
+ else if (!opts.chrono && level && !forced)
67
+ return; // not decision level 0
68
+ assert (lrat_chain.empty ());
69
+ for (auto &reason_lit : *reason) {
70
+ if (lit == reason_lit)
71
+ continue;
72
+ assert (val (reason_lit));
73
+ if (!val (reason_lit))
74
+ continue;
75
+ const int signed_reason_lit = val (reason_lit) * reason_lit;
76
+ int64_t id = unit_id (signed_reason_lit);
77
+ lrat_chain.push_back (id);
78
+ }
79
+ lrat_chain.push_back (reason->id);
80
+ }
81
+
82
+ // same code as above but reason is assumed to be conflict and lit is not
83
+ // needed
84
+ //
85
+ void Internal::build_chain_for_empty () {
86
+ if (!lrat || !lrat_chain.empty ())
87
+ return;
88
+ assert (!level || in_mode (BACKBONE));
89
+ assert (lrat_chain.empty ());
90
+ assert (conflict);
91
+ LOG (conflict, "lrat for global empty clause with conflict");
92
+ for (auto &lit : *conflict) {
93
+ assert (val (lit) < 0);
94
+ int64_t id = unit_id (-lit);
95
+ lrat_chain.push_back (id);
96
+ }
97
+ lrat_chain.push_back (conflict->id);
98
+ }
99
+
100
+ /*------------------------------------------------------------------------*/
101
+
102
+ inline void Internal::search_assign (int lit, Clause *reason) {
103
+
104
+ if (level)
105
+ require_mode (SEARCH);
106
+
107
+ const int idx = vidx (lit);
108
+ const bool from_external = reason == external_reason;
109
+ assert (!val (idx));
110
+ assert (!flags (idx).eliminated () || reason == decision_reason ||
111
+ reason == external_reason);
112
+ Var &v = var (idx);
113
+ int lit_level;
114
+ assert (!lrat || level || reason == external_reason ||
115
+ reason == decision_reason || !lrat_chain.empty ());
116
+ // The following cases are explained in the two comments above before
117
+ // 'decision_reason' and 'assignment_level'.
118
+ //
119
+ // External decision reason means that the propagation was done by
120
+ // an external propagation and the reason clause not known (yet).
121
+ // In that case it is assumed that the propagation is NOT out of
122
+ // order (i.e. lit_level = level), because due to lazy explanation,
123
+ // we can not calculate the real assignment level.
124
+ // The function assignment_level () will also assign the current level
125
+ // to literals with external reason.
126
+ if (!reason)
127
+ lit_level = 0; // unit
128
+ else if (reason == decision_reason)
129
+ lit_level = level, reason = 0;
130
+ else if (opts.chrono)
131
+ lit_level = assignment_level (lit, reason);
132
+ else
133
+ lit_level = level;
134
+ if (!lit_level)
135
+ reason = 0;
136
+
137
+ v.level = lit_level;
138
+ v.trail = trail.size ();
139
+ v.reason = reason;
140
+ assert ((int) num_assigned < max_var);
141
+ assert (num_assigned == trail.size ());
142
+ num_assigned++;
143
+ if (!lit_level && !from_external)
144
+ learn_unit_clause (lit); // increases 'stats.fixed'
145
+ assert (lit_level || !from_external);
146
+ const signed char tmp = sign (lit);
147
+ set_val (idx, tmp);
148
+ assert (val (lit) > 0); // Just a bit paranoid but useful.
149
+ assert (val (-lit) < 0); // Ditto.
150
+ if (!searching_lucky_phases)
151
+ phases.saved[idx] = tmp; // phase saving during search
152
+ trail.push_back (lit);
153
+ #ifdef LOGGING
154
+ if (!lit_level)
155
+ LOG ("root-level unit assign %d @ 0", lit);
156
+ else
157
+ LOG (reason, "search assign %d @ %d", lit, lit_level);
158
+ #endif
159
+
160
+ if (watching ()) {
161
+ const Watches &ws = watches (-lit);
162
+ if (!ws.empty ()) {
163
+ const Watch &w = ws[0];
164
+ __builtin_prefetch (&w, 0, 1);
165
+ }
166
+ }
167
+ lrat_chain.clear ();
168
+ }
169
+
170
+ /*------------------------------------------------------------------------*/
171
+
172
+ // External versions of 'search_assign' which are not inlined. They either
173
+ // are used to assign unit clauses on the root-level, in 'decide' to assign
174
+ // a decision or in 'analyze' to assign the literal 'driven' by a learned
175
+ // clause. This happens far less frequently than the 'search_assign' above,
176
+ // which is called directly in 'propagate' below and thus is inlined.
177
+
178
+ void Internal::assign_unit (int lit) {
179
+ assert (!level);
180
+ search_assign (lit, 0);
181
+ }
182
+
183
+ // Just assume the given literal as decision (increase decision level and
184
+ // assign it). This is used below in 'decide'.
185
+
186
+ void Internal::search_assume_decision (int lit) {
187
+ require_mode (SEARCH);
188
+ assert (propagated == trail.size ());
189
+ new_trail_level (lit);
190
+ notify_decision ();
191
+ LOG ("search decide %d", lit);
192
+ search_assign (lit, decision_reason);
193
+ }
194
+
195
+ void Internal::search_assign_driving (int lit, Clause *c) {
196
+ require_mode (SEARCH);
197
+ search_assign (lit, c);
198
+ notify_assignments ();
199
+ }
200
+
201
+ void Internal::search_assign_external (int lit) {
202
+ require_mode (SEARCH);
203
+ search_assign (lit, external_reason);
204
+ notify_assignments ();
205
+ }
206
+
207
+ /*------------------------------------------------------------------------*/
208
+
209
+ // The 'propagate' function is usually the hot-spot of a CDCL SAT solver.
210
+ // The 'trail' stack saves assigned variables and is used here as BFS queue
211
+ // for checking clauses with the negation of assigned variables for being in
212
+ // conflict or whether they produce additional assignments.
213
+
214
+ // This version of 'propagate' uses lazy watches and keeps two watched
215
+ // literals at the beginning of the clause. We also use 'blocking literals'
216
+ // to reduce the number of times clauses have to be visited (2008 JSAT paper
217
+ // by Chu, Harwood and Stuckey). The watches know if a watched clause is
218
+ // binary, in which case it never has to be visited. If a binary clause is
219
+ // falsified we continue propagating.
220
+
221
+ // Finally, for long clauses we save the position of the last watch
222
+ // replacement in 'pos', which in turn reduces certain quadratic accumulated
223
+ // propagation costs (2013 JAIR article by Ian Gent) at the expense of four
224
+ // more bytes for each clause.
225
+
226
+ bool Internal::propagate () {
227
+
228
+ if (level)
229
+ require_mode (SEARCH);
230
+ assert (!unsat);
231
+ LOG ("starting propagate");
232
+ START (propagate);
233
+
234
+ // Updating statistics counter in the propagation loops is costly so we
235
+ // delay until propagation ran to completion.
236
+ //
237
+ int64_t before = propagated;
238
+ int64_t ticks = 0;
239
+
240
+ while (!conflict && propagated != trail.size ()) {
241
+
242
+ const int lit = -trail[propagated++];
243
+ LOG ("propagating %d", -lit);
244
+ Watches &ws = watches (lit);
245
+
246
+ const const_watch_iterator eow = ws.end ();
247
+ watch_iterator j = ws.begin ();
248
+ const_watch_iterator i = j;
249
+ ticks += 1 + cache_lines (ws.size (), sizeof *i);
250
+
251
+ while (i != eow) {
252
+
253
+ const Watch w = *j++ = *i++;
254
+ const signed char b = val (w.blit);
255
+ LOG (w.clause, "checking");
256
+
257
+ if (b > 0)
258
+ continue; // blocking literal satisfied
259
+
260
+ if (w.binary ()) {
261
+
262
+ // assert (w.clause->redundant || !w.clause->garbage);
263
+
264
+ // In principle we can ignore garbage binary clauses too, but that
265
+ // would require to dereference the clause pointer all the time with
266
+ //
267
+ // if (w.clause->garbage) { j--; continue; } // (*)
268
+ //
269
+ // This is too costly. It is however necessary to produce correct
270
+ // proof traces if binary clauses are traced to be deleted ('d ...'
271
+ // line) immediately as soon they are marked as garbage. Actually
272
+ // finding instances where this happens is pretty difficult (six
273
+ // parallel fuzzing jobs in parallel took an hour), but it does
274
+ // occur. Our strategy to avoid generating incorrect proofs now is
275
+ // to delay tracing the deletion of binary clauses marked as garbage
276
+ // until they are really deleted from memory. For large clauses
277
+ // this is not necessary since we have to access the clause anyhow.
278
+ //
279
+ // Thanks go to Mathias Fleury, who wanted me to explain why the
280
+ // line '(*)' above was in the code. Removing it actually really
281
+ // improved running times and thus I tried to find concrete
282
+ // instances where this happens (which I found), and then
283
+ // implemented the described fix.
284
+
285
+ // Binary clauses are treated separately since they do not require
286
+ // to access the clause at all (only during conflict analysis, and
287
+ // there also only to simplify the code).
288
+
289
+ if (b < 0)
290
+ conflict = w.clause; // but continue ...
291
+ else {
292
+ build_chain_for_units (w.blit, w.clause, 0);
293
+ search_assign (w.blit, w.clause);
294
+ // lrat_chain.clear (); done in search_assign
295
+ ticks++;
296
+ }
297
+
298
+ } else {
299
+ assert (w.clause->size > 2);
300
+
301
+ if (conflict)
302
+ break; // Stop if there was a binary conflict already.
303
+
304
+ // The cache line with the clause data is forced to be loaded here
305
+ // and thus this first memory access below is the real hot-spot of
306
+ // the solver. Note, that this check is positive very rarely and
307
+ // thus branch prediction should be almost perfect here.
308
+
309
+ ticks++;
310
+
311
+ if (w.clause->garbage) {
312
+ j--;
313
+ continue;
314
+ }
315
+
316
+ literal_iterator lits = w.clause->begin ();
317
+ assert (lits[0] == lit || lits[1] == lit);
318
+
319
+ // Simplify code by forcing 'lit' to be the second literal in the
320
+ // clause. This goes back to MiniSAT. We use a branch-less version
321
+ // for conditionally swapping the first two literals, since it
322
+ // turned out to be substantially faster than this one
323
+ //
324
+ // if (lits[0] == lit) swap (lits[0], lits[1]);
325
+ //
326
+ // which achieves the same effect, but needs a branch.
327
+ //
328
+ const int other = lits[0] ^ lits[1] ^ lit;
329
+ const signed char u = val (other); // value of the other watch
330
+
331
+ if (u > 0)
332
+ j[-1].blit = other; // satisfied, just replace blit
333
+ else {
334
+
335
+ // This follows Ian Gent's (JAIR'13) idea of saving the position
336
+ // of the last watch replacement. In essence it needs two copies
337
+ // of the default search for a watch replacement (in essence the
338
+ // code in the 'if (v < 0) { ... }' block below), one starting at
339
+ // the saved position until the end of the clause and then if that
340
+ // one failed to find a replacement another one starting at the
341
+ // first non-watched literal until the saved position.
342
+
343
+ const int size = w.clause->size;
344
+ const literal_iterator middle = lits + w.clause->pos;
345
+ const const_literal_iterator end = lits + size;
346
+ literal_iterator k = middle;
347
+
348
+ // Find replacement watch 'r' at position 'k' with value 'v'.
349
+ assert (lits + 2 <= k);
350
+ LOG (w.clause, "search starting at %d", w.clause->pos);
351
+ int r = 0;
352
+ signed char v = -1;
353
+
354
+ while (k != end && (v = val (r = *k)) < 0)
355
+ k++;
356
+
357
+ if (v < 0) { // need second search starting at the head?
358
+
359
+ k = lits + 2;
360
+ assert (w.clause->pos <= size);
361
+ while (k != middle && (v = val (r = *k)) < 0)
362
+ k++;
363
+ }
364
+
365
+ w.clause->pos = k - lits; // always save position
366
+
367
+ assert (lits + 2 <= k), assert (k <= w.clause->end ());
368
+
369
+ if (v > 0) {
370
+
371
+ // Replacement satisfied, so just replace 'blit'.
372
+
373
+ j[-1].blit = r;
374
+
375
+ } else if (!v) {
376
+
377
+ // Found new unassigned replacement literal to be watched.
378
+
379
+ LOG (w.clause, "unwatch %d in", lit);
380
+
381
+ lits[0] = other;
382
+ lits[1] = r;
383
+ *k = lit;
384
+
385
+ watch_literal (r, lit, w.clause);
386
+
387
+ j--; // Drop this watch from the watch list of 'lit'.
388
+
389
+ ticks++;
390
+
391
+ } else if (!u) {
392
+
393
+ assert (v < 0);
394
+
395
+ // The other watch is unassigned ('!u') and all other literals
396
+ // assigned to false (still 'v < 0'), thus we found a unit.
397
+ //
398
+ build_chain_for_units (other, w.clause, 0);
399
+ search_assign (other, w.clause);
400
+ // lrat_chain.clear (); done in search_assign
401
+ ticks++;
402
+
403
+ // Similar code is in the implementation of the SAT'18 paper on
404
+ // chronological backtracking but in our experience, this code
405
+ // first does not really seem to be necessary for correctness,
406
+ // and further does not improve running time either.
407
+ //
408
+ if (opts.chrono > 1) {
409
+
410
+ const int other_level = var (other).level;
411
+
412
+ if (other_level > var (lit).level) {
413
+
414
+ // The assignment level of the new unit 'other' is larger
415
+ // than the assignment level of 'lit'. Thus we should find
416
+ // another literal in the clause at that higher assignment
417
+ // level and watch that instead of 'lit'.
418
+
419
+ assert (size > 2);
420
+
421
+ int pos, s = 0;
422
+
423
+ for (pos = 2; pos < size; pos++)
424
+ if (var (s = lits[pos]).level == other_level)
425
+ break;
426
+
427
+ assert (s);
428
+ assert (pos < size);
429
+
430
+ LOG (w.clause, "unwatch %d in", lit);
431
+ lits[pos] = lit;
432
+ lits[0] = other;
433
+ lits[1] = s;
434
+ watch_literal (s, lit, w.clause);
435
+
436
+ j--; // Drop this watch from the watch list of 'lit'.
437
+ }
438
+ }
439
+ } else {
440
+
441
+ assert (u < 0);
442
+ assert (v < 0);
443
+
444
+ // The other watch is assigned false ('u < 0') and all other
445
+ // literals as well (still 'v < 0'), thus we found a conflict.
446
+
447
+ conflict = w.clause;
448
+ break;
449
+ }
450
+ }
451
+ }
452
+ }
453
+
454
+ if (j != i) {
455
+
456
+ while (i != eow)
457
+ *j++ = *i++;
458
+
459
+ ws.resize (j - ws.begin ());
460
+ }
461
+ }
462
+
463
+ if (searching_lucky_phases) {
464
+
465
+ if (conflict)
466
+ LOG (conflict, "ignoring lucky conflict");
467
+
468
+ } else {
469
+
470
+ // Avoid updating stats eagerly in the hot-spot of the solver.
471
+ //
472
+ stats.propagations.search += propagated - before;
473
+ stats.ticks.search[stable] += ticks;
474
+
475
+ if (!conflict)
476
+ no_conflict_until = propagated;
477
+ else {
478
+
479
+ if (stable)
480
+ stats.stabconflicts++;
481
+ stats.conflicts++;
482
+
483
+ LOG (conflict, "conflict");
484
+
485
+ // The trail before the current decision level was conflict free.
486
+ //
487
+ no_conflict_until = control[level].trail;
488
+ }
489
+ }
490
+
491
+ if (conflict && randomized_deciding) {
492
+ if (!--randomized_deciding)
493
+ VERBOSE (3, "last random decision conflict");
494
+ }
495
+ STOP (propagate);
496
+
497
+ return !conflict;
498
+ }
499
+
500
+ /*------------------------------------------------------------------------*/
501
+
502
+ void Internal::propergate () {
503
+
504
+ assert (!conflict);
505
+ assert (propagated == trail.size ());
506
+
507
+ while (propergated != trail.size ()) {
508
+
509
+ const int lit = -trail[propergated++];
510
+ LOG ("propergating %d", -lit);
511
+ Watches &ws = watches (lit);
512
+
513
+ const const_watch_iterator eow = ws.end ();
514
+ watch_iterator j = ws.begin ();
515
+ const_watch_iterator i = j;
516
+
517
+ while (i != eow) {
518
+
519
+ const Watch w = *j++ = *i++;
520
+ LOG (w.clause, "propergate");
521
+ if (w.binary ()) {
522
+ assert (val (w.blit) > 0);
523
+ continue;
524
+ }
525
+ if (w.clause->garbage) {
526
+ j--;
527
+ continue;
528
+ }
529
+
530
+ literal_iterator lits = w.clause->begin ();
531
+
532
+ const int other = lits[0] ^ lits[1] ^ lit;
533
+ const signed char u = val (other);
534
+
535
+ // TODO: check if u == 0 can happen.
536
+ if (u > 0)
537
+ continue;
538
+ assert (u < 0);
539
+
540
+ const int size = w.clause->size;
541
+ const literal_iterator middle = lits + w.clause->pos;
542
+ const const_literal_iterator end = lits + size;
543
+ literal_iterator k = middle;
544
+
545
+ int r = 0;
546
+ signed char v = -1;
547
+
548
+ while (k != end && (v = val (r = *k)) < 0)
549
+ k++;
550
+
551
+ if (v < 0) {
552
+ k = lits + 2;
553
+ assert (w.clause->pos <= size);
554
+ while (k != middle && (v = val (r = *k)) < 0)
555
+ k++;
556
+ }
557
+
558
+ assert (lits + 2 <= k), assert (k <= w.clause->end ());
559
+ w.clause->pos = k - lits;
560
+
561
+ assert (v > 0);
562
+
563
+ LOG (w.clause, "unwatch %d in", lit);
564
+
565
+ lits[0] = other;
566
+ lits[1] = r;
567
+ *k = lit;
568
+
569
+ watch_literal (r, lit, w.clause);
570
+
571
+ j--;
572
+ }
573
+
574
+ if (j != i) {
575
+
576
+ while (i != eow)
577
+ *j++ = *i++;
578
+
579
+ ws.resize (j - ws.begin ());
580
+ }
581
+ }
582
+ }
583
+
584
+ } // namespace CaDiCaL