ABC: A System for Sequential Synthesis and Verification
 
Loading...
Searching...
No Matches
cadical_restore.cpp
Go to the documentation of this file.
1#include "global.h"
2
3#include "internal.hpp"
4
6
7namespace CaDiCaL {
8
9/*------------------------------------------------------------------------*/
10
11// In incremental solving after a first call to 'solve' has finished and
12// before calling the internal 'solve' again incrementally we have to
13// restore clauses which have the negation of a literal as a witness literal
14// on the extension stack, which was added as original literal in a new
15// clause or in an assumption. This procedure has to be applied
16// recursively, i.e., the literals of restored clauses are treated in the
17// same way as literals of a new original clause.
18//
19// To figure out whether literals are such witnesses we have a 'witness'
20// bit for each external literal, which is set in 'block', 'elim', and
21// 'decompose' if a clause is pushed on the extension stack. The witness
22// bits are recomputed after restoring clauses.
23//
24// We further mark in the external solver newly internalized external
25// literals in 'add' and 'assume' since the last call to 'solve' as tainted
26// if they occur negated as a witness literal on the extension stack. Then
27// we go through the extension stack and restore all clauses which have a
28// tainted literal (and its negation a marked as witness).
29//
30// Since the API contract disallows to call 'val' and 'failed' in an
31// 'UNKNOWN' state. We do not have to internalize literals there.
32//
33// In order to have tainted literals accepted by the internal solver they
34// have to be active and thus we might need to 'reactivate' them before
35// restoring clauses if they are inactive. In case they have completely
36// been eliminated and removed from the internal solver in 'compact', then
37// we just use a new internal variable. This is performed in 'internalize'
38// during marking external literals as tainted.
39//
40// To check that this approach is correct the external solver can maintain a
41// stack of original clauses and current assumptions both in terms of
42// external literals. Whenever 'solve' determines that the current
43// incremental call is satisfiable we check that the (extended) witness does
44// satisfy the saved original clauses, as well as all the assumptions. To
45// enable these checks set 'opts.check' as well as 'opts.checkwitness' and
46// 'opts.checkassumptions' all to 'true'. The model based tester actually
47// prefers to enable the 'opts.check' option and the other two are 'true' by
48// default anyhow.
49//
50// See our SAT'19 paper [FazekasBiereScholl-SAT'19] for more details.
51
52/*------------------------------------------------------------------------*/
53
56 const int64_t id) {
57 LOG (begin, end, "restoring external clause[%" PRId64 "]", id);
58 CADICAL_assert (eclause.empty ());
59 CADICAL_assert (id);
60 for (auto p = begin; p != end; p++) {
61 eclause.push_back (*p);
62 if (internal->proof && internal->lrat) {
63 const auto &elit = *p;
64 unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit);
65 CADICAL_assert ((size_t) eidx < ext_units.size ());
66 const int64_t id = ext_units[eidx];
67 bool added = ext_flags[abs (elit)];
68 if (id && !added) {
69 ext_flags[abs (elit)] = true;
70 internal->lrat_chain.push_back (id);
71 }
72 }
73 int ilit = internalize (*p);
74 internal->add_original_lit (ilit), internal->stats.restoredlits++;
75 }
76 if (internal->proof && internal->lrat) {
77 for (const auto &elit : eclause) {
78 ext_flags[abs (elit)] = false;
79 }
80 }
81 internal->finish_added_clause_with_id (id, true);
82 eclause.clear ();
83 internal->stats.restored++;
84}
85
86/*------------------------------------------------------------------------*/
87
89
90 CADICAL_assert (internal->opts.restoreall == 2 || !tainted.empty ());
91
92 START (restore);
93 internal->stats.restorations++;
94
95 struct {
96 int64_t weakened, satisfied, restored, removed;
97 } clauses;
98 memset (&clauses, 0, sizeof clauses);
99
100 if (internal->opts.restoreall && tainted.empty ())
101 PHASE ("restore", internal->stats.restorations,
102 "forced to restore all clauses");
103
104#ifndef CADICAL_QUIET
105 {
106 unsigned numtainted = 0;
107 for (const auto b : tainted)
108 if (b)
109 numtainted++;
110
111 PHASE ("restore", internal->stats.restorations,
112 "starting with %u tainted literals %.0f%%", numtainted,
113 percent (numtainted, 2u * max_var));
114 }
115#endif
116
117 auto end_of_extension = extension.end ();
118 auto p = extension.begin (), q = p;
119
120 // Go over all witness labelled clauses on the extension stack, restore
121 // those necessary, remove restored and flush satisfied clauses.
122 //
123 while (p != end_of_extension) {
124
125 clauses.weakened++;
126
127 CADICAL_assert (!*p);
128 const auto saved = q; // Save old start.
129 *q++ = *p++; // Copy zero '0'.
130
131 // Copy witness part and try to find a tainted witness literal in it.
132 //
133 int tlit = 0; // Negation tainted.
134 int elit;
135 //
136 CADICAL_assert (p != end_of_extension);
137 //
138 while ((elit = *q++ = *p++)) {
139
140 if (marked (tainted, -elit)) {
141 tlit = elit;
142 LOG ("negation of witness literal %d tainted", tlit);
143 }
144
145 CADICAL_assert (p != end_of_extension);
146 }
147
148 // now copy the id of the clause
149 const int64_t id = ((int64_t) (*p) << 32) + (int64_t) * (p + 1);
150 LOG ("id is %" PRId64, id);
151 *q++ = *p++;
152 *q++ = *p++;
153 CADICAL_assert (id);
154 CADICAL_assert (!*p);
155 *q++ = *p++;
156
157 // Now find 'end_of_clause' (clause starts at 'p') and at the same time
158 // figure out whether the clause is actually root level satisfied.
159 //
160 int satisfied = 0;
161 auto end_of_clause = p;
162 while (end_of_clause != end_of_extension && (elit = *end_of_clause)) {
163 if (!satisfied && fixed (elit) > 0)
164 satisfied = elit;
165 end_of_clause++;
166 }
167 CADICAL_assert (id);
168
169 // Do not apply our 'FLUSH' rule to remove satisfied (implied) clauses
170 // if the corresponding option is set simply by resetting 'satisfied'.
171 //
172 if (satisfied && !internal->opts.restoreflush) {
173 LOG (p, end_of_clause, "forced to not remove %d satisfied",
174 satisfied);
175 satisfied = 0;
176 }
177
178 if (satisfied || tlit || internal->opts.restoreall) {
179
180 if (satisfied) {
181 LOG (p, end_of_clause,
182 "flushing implied clause satisfied by %d from extension stack",
183 satisfied);
184 clauses.satisfied++;
185 } else {
186 restore_clause (p, end_of_clause, id); // Might taint literals.
187 clauses.restored++;
188 }
189
190 clauses.removed++;
191 p = end_of_clause;
192 q = saved;
193
194 } else {
195
196 LOG (p, end_of_clause, "keeping clause on extension stack");
197
198 while (p != end_of_clause) // Copy clause too.
199 *q++ = *p++;
200 }
201 }
202
203 extension.resize (q - extension.begin ());
205
206#ifndef CADICAL_QUIET
207 if (clauses.satisfied)
208 PHASE ("restore", internal->stats.restorations,
209 "removed %" PRId64 " satisfied %.0f%% of %" PRId64
210 " weakened clauses",
211 clauses.satisfied, percent (clauses.satisfied, clauses.weakened),
212 clauses.weakened);
213 else
214 PHASE ("restore", internal->stats.restorations,
215 "no satisfied clause removed out of %" PRId64
216 " weakened clauses",
217 clauses.weakened);
218
219 if (clauses.restored)
220 PHASE ("restore", internal->stats.restorations,
221 "restored %" PRId64 " clauses %.0f%% out of %" PRId64
222 " weakened clauses",
223 clauses.restored, percent (clauses.restored, clauses.weakened),
224 clauses.weakened);
225 else
226 PHASE ("restore", internal->stats.restorations,
227 "no clause restored out of %" PRId64 " weakened clauses",
228 clauses.weakened);
229 {
230 unsigned numtainted = 0;
231 for (const auto &b : tainted)
232 if (b)
233 numtainted++;
234
235 PHASE ("restore", internal->stats.restorations,
236 "finishing with %u tainted literals %.0f%%", numtainted,
237 percent (numtainted, 2u * max_var));
238 }
239
240#endif
241 LOG ("extension stack clean");
242 tainted.clear ();
243
244 // Finally recompute the witness bits.
245 //
246 witness.clear ();
247 const auto begin_of_extension = extension.begin ();
248 p = extension.end ();
249 while (p != begin_of_extension) {
250 while (*--p)
251 CADICAL_assert (p != begin_of_extension);
252 int elit;
253 CADICAL_assert (p != begin_of_extension);
254 --p;
255 CADICAL_assert (p != begin_of_extension);
256 CADICAL_assert (*p || *(p - 1));
257 --p;
258 CADICAL_assert (p != begin_of_extension);
259 CADICAL_assert (!*p);
260 --p;
261 CADICAL_assert (p != begin_of_extension);
262 while ((elit = *--p)) {
263 mark (witness, elit);
264 CADICAL_assert (p != begin_of_extension);
265 }
266 }
267
268 STOP (restore);
269}
270
271} // namespace CaDiCaL
272
#define ABC_NAMESPACE_IMPL_START
#define ABC_NAMESPACE_IMPL_END
#define CADICAL_assert(ignore)
Definition global.h:14
#define LOG(...)
Cube * p
Definition exorList.c:222
#define PHASE(...)
Definition message.hpp:52
void shrink_vector(std::vector< T > &v)
Definition util.hpp:101
double percent(double a, double b)
Definition util.hpp:21
#define STOP(P)
Definition profile.hpp:158
#define START(P)
Definition profile.hpp:150
vector< bool > ext_flags
Definition external.hpp:74
vector< bool > tainted
Definition external.hpp:88
bool marked(const vector< bool > &map, int elit) const
Definition external.hpp:216
vector< bool > witness
Definition external.hpp:87
void restore_clause(const vector< int >::const_iterator &begin, const vector< int >::const_iterator &end, const int64_t id)
vector< int64_t > ext_units
Definition external.hpp:73
vector< int > extension
Definition external.hpp:85
Internal * internal
Definition external.hpp:61
vector< int > eclause
Definition external.hpp:75
int fixed(int elit) const
int internalize(int, bool extension=false)
char * memset()
signed char mark
Definition value.h:8