1 |
|
/***********************************************************************************[SimpSolver.cc] |
2 |
|
Copyright (c) 2006, Niklas Een, Niklas Sorensson |
3 |
|
Copyright (c) 2007-2010, Niklas Sorensson |
4 |
|
|
5 |
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
6 |
|
associated documentation files (the "Software"), to deal in the Software without restriction, |
7 |
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, |
8 |
|
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
9 |
|
furnished to do so, subject to the following conditions: |
10 |
|
|
11 |
|
The above copyright notice and this permission notice shall be included in all copies or |
12 |
|
substantial portions of the Software. |
13 |
|
|
14 |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
15 |
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
16 |
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
17 |
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT |
18 |
|
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
19 |
|
**************************************************************************************************/ |
20 |
|
|
21 |
|
#include "prop/bvminisat/simp/SimpSolver.h" |
22 |
|
|
23 |
|
#include "base/check.h" |
24 |
|
#include "options/bv_options.h" |
25 |
|
#include "options/smt_options.h" |
26 |
|
#include "proof/clause_id.h" |
27 |
|
#include "prop/bvminisat/mtl/Sort.h" |
28 |
|
#include "prop/bvminisat/utils/System.h" |
29 |
|
|
30 |
|
namespace cvc5 { |
31 |
|
namespace BVMinisat { |
32 |
|
|
33 |
|
//================================================================================================= |
34 |
|
// Options: |
35 |
|
|
36 |
|
|
37 |
|
static const char* _cat = "SIMP"; |
38 |
|
|
39 |
9245 |
static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false); |
40 |
9245 |
static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false); |
41 |
9245 |
static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true); |
42 |
9245 |
static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0); |
43 |
9245 |
static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX)); |
44 |
9245 |
static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX)); |
45 |
9245 |
static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false)); |
46 |
|
|
47 |
|
|
48 |
|
//================================================================================================= |
49 |
|
// Constructor/Destructor: |
50 |
|
|
51 |
8927 |
SimpSolver::SimpSolver(cvc5::context::Context* context) |
52 |
|
: Solver(context), |
53 |
|
grow(opt_grow), |
54 |
|
clause_lim(opt_clause_lim), |
55 |
|
subsumption_lim(opt_subsumption_lim), |
56 |
|
simp_garbage_frac(opt_simp_garbage_frac), |
57 |
|
use_asymm(opt_use_asymm), |
58 |
|
use_rcheck(opt_use_rcheck), |
59 |
|
use_elim(opt_use_elim |
60 |
1621451 |
&& cvc5::options::bitblastMode() |
61 |
8927 |
== cvc5::options::BitblastMode::EAGER |
62 |
8942 |
&& !cvc5::options::produceModels()), |
63 |
|
merges(0), |
64 |
|
asymm_lits(0), |
65 |
|
eliminated_vars(0), |
66 |
|
elimorder(1), |
67 |
|
use_simplification(true), |
68 |
17854 |
occurs(ClauseDeleted(ca)), |
69 |
17854 |
elim_heap(ElimLt(n_occ)), |
70 |
|
bwdsub_assigns(0), |
71 |
53562 |
n_touched(0) |
72 |
|
{ |
73 |
|
|
74 |
17854 |
vec<Lit> dummy(1,lit_Undef); |
75 |
8927 |
ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below. |
76 |
8927 |
bwdsub_tmpunit = ca.alloc(dummy); |
77 |
8927 |
remove_satisfied = false; |
78 |
|
|
79 |
|
// add the initialization for all the internal variables |
80 |
26781 |
for (int i = frozen.size(); i < vardata.size(); ++ i) { |
81 |
17854 |
frozen .push(1); |
82 |
17854 |
eliminated.push(0); |
83 |
17854 |
if (use_simplification){ |
84 |
17854 |
n_occ .push(0); |
85 |
17854 |
n_occ .push(0); |
86 |
17854 |
occurs .init(i); |
87 |
17854 |
touched .push(0); |
88 |
17854 |
elim_heap .insert(i); |
89 |
|
} |
90 |
|
} |
91 |
|
|
92 |
8927 |
} |
93 |
|
|
94 |
|
|
95 |
17854 |
SimpSolver::~SimpSolver() |
96 |
|
{ |
97 |
|
// cvc5::StatisticsRegistry::unregisterStat(&total_eliminate_time); |
98 |
17854 |
} |
99 |
|
|
100 |
|
|
101 |
1978747 |
Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) { |
102 |
1978747 |
Var v = Solver::newVar(sign, dvar); |
103 |
|
|
104 |
1978747 |
frozen .push((char)false); |
105 |
1978747 |
eliminated.push((char)false); |
106 |
|
|
107 |
1978747 |
if (use_simplification){ |
108 |
1978747 |
n_occ .push(0); |
109 |
1978747 |
n_occ .push(0); |
110 |
1978747 |
occurs .init(v); |
111 |
1978747 |
touched .push(0); |
112 |
1978747 |
elim_heap .insert(v); |
113 |
1978747 |
if (freeze) { |
114 |
268193 |
setFrozen(v, true); |
115 |
|
} |
116 |
|
} |
117 |
1978747 |
return v; |
118 |
|
} |
119 |
|
|
120 |
|
|
121 |
|
|
122 |
9917 |
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) |
123 |
|
{ |
124 |
9917 |
only_bcp = false; |
125 |
|
|
126 |
19834 |
vec<Var> extra_frozen; |
127 |
9917 |
lbool result = l_True; |
128 |
|
|
129 |
9917 |
do_simp &= use_simplification; |
130 |
|
|
131 |
9917 |
if (do_simp) { |
132 |
|
// Assumptions must be temporarily frozen to run variable elimination: |
133 |
785132 |
for (int i = 0; i < assumptions.size(); i++){ |
134 |
775215 |
Var v = var(assumptions[i]); |
135 |
|
|
136 |
|
// If an assumption has been eliminated, remember it. |
137 |
775215 |
Assert(!isEliminated(v)); |
138 |
|
|
139 |
775215 |
if (!frozen[v]){ |
140 |
|
// Freeze and store. |
141 |
|
setFrozen(v, true); |
142 |
|
extra_frozen.push(v); |
143 |
|
} } |
144 |
|
|
145 |
9917 |
if (do_simp && clause_added) { |
146 |
5945 |
cancelUntil(0); |
147 |
5945 |
result = lbool(eliminate(turn_off_simp)); |
148 |
5945 |
clause_added = false; |
149 |
|
} |
150 |
|
} |
151 |
|
|
152 |
9917 |
if (result == l_True) |
153 |
9917 |
result = Solver::solve_(); |
154 |
|
else if (verbosity >= 1) |
155 |
|
printf("===============================================================================\n"); |
156 |
|
|
157 |
9917 |
if (do_simp) |
158 |
|
// Unfreeze the assumptions that were frozen: |
159 |
9917 |
for (int i = 0; i < extra_frozen.size(); i++) |
160 |
|
setFrozen(extra_frozen[i], false); |
161 |
|
|
162 |
19834 |
return result; |
163 |
|
} |
164 |
|
|
165 |
|
|
166 |
|
|
167 |
7607263 |
bool SimpSolver::addClause_(vec<Lit>& ps, ClauseId& id) |
168 |
|
{ |
169 |
|
#ifdef CVC5_ASSERTIONS |
170 |
7607263 |
for (int i = 0; i < ps.size(); i++) Assert(!isEliminated(var(ps[i]))); |
171 |
|
#endif |
172 |
|
|
173 |
7607263 |
int nclauses = clauses.size(); |
174 |
|
|
175 |
7607263 |
if (use_rcheck && implied(ps)) |
176 |
|
return true; |
177 |
|
|
178 |
7607263 |
if (!Solver::addClause_(ps, id)) |
179 |
|
return false; |
180 |
|
|
181 |
7607263 |
if (use_simplification && clauses.size() == nclauses + 1){ |
182 |
7595842 |
CRef cr = clauses.last(); |
183 |
7595842 |
const Clause& clause = ca[cr]; |
184 |
|
|
185 |
|
// NOTE: the clause is added to the queue immediately and then |
186 |
|
// again during 'gatherTouchedClauses()'. If nothing happens |
187 |
|
// in between, it will only be checked once. Otherwise, it may |
188 |
|
// be checked twice unnecessarily. This is an unfortunate |
189 |
|
// consequence of how backward subsumption is used to mimic |
190 |
|
// forward subsumption. |
191 |
7595842 |
subsumption_queue.insert(cr); |
192 |
28260569 |
for (int i = 0; i < clause.size(); i++) |
193 |
|
{ |
194 |
20664727 |
occurs[var(clause[i])].push(cr); |
195 |
20664727 |
n_occ[toInt(clause[i])]++; |
196 |
20664727 |
touched[var(clause[i])] = 1; |
197 |
20664727 |
n_touched++; |
198 |
20664727 |
if (elim_heap.inHeap(var(clause[i]))) |
199 |
19462056 |
elim_heap.increase(var(clause[i])); |
200 |
|
} |
201 |
|
} |
202 |
|
|
203 |
7607263 |
return true; |
204 |
|
} |
205 |
|
|
206 |
|
|
207 |
53346 |
void SimpSolver::removeClause(CRef cr) |
208 |
|
{ |
209 |
53346 |
const Clause& clause = ca[cr]; |
210 |
|
|
211 |
53346 |
if (use_simplification) |
212 |
|
{ |
213 |
218556 |
for (int i = 0; i < clause.size(); i++) |
214 |
|
{ |
215 |
165210 |
n_occ[toInt(clause[i])]--; |
216 |
165210 |
updateElimHeap(var(clause[i])); |
217 |
165210 |
occurs.smudge(var(clause[i])); |
218 |
|
} |
219 |
|
} |
220 |
53346 |
Solver::removeClause(cr); |
221 |
53346 |
} |
222 |
|
|
223 |
|
|
224 |
44137 |
bool SimpSolver::strengthenClause(CRef cr, Lit l) |
225 |
|
{ |
226 |
44137 |
Clause& clause = ca[cr]; |
227 |
44137 |
Assert(decisionLevel() == 0); |
228 |
44137 |
Assert(use_simplification); |
229 |
|
|
230 |
|
// FIX: this is too inefficient but would be nice to have (properly |
231 |
|
// implemented) if (!find(subsumption_queue, &clause)) |
232 |
44137 |
subsumption_queue.insert(cr); |
233 |
|
|
234 |
44137 |
if (clause.size() == 2) |
235 |
|
{ |
236 |
3481 |
removeClause(cr); |
237 |
3481 |
clause.strengthen(l); |
238 |
|
} |
239 |
|
else |
240 |
|
{ |
241 |
40656 |
detachClause(cr, true); |
242 |
40656 |
clause.strengthen(l); |
243 |
40656 |
attachClause(cr); |
244 |
40656 |
remove(occurs[var(l)], cr); |
245 |
40656 |
n_occ[toInt(l)]--; |
246 |
40656 |
updateElimHeap(var(l)); |
247 |
|
} |
248 |
|
|
249 |
44137 |
return clause.size() == 1 ? enqueue(clause[0]) && propagate() == CRef_Undef |
250 |
44137 |
: true; |
251 |
|
} |
252 |
|
|
253 |
|
|
254 |
|
// Returns FALSE if clause is always satisfied ('out_clause' should not be used). |
255 |
28059 |
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause) |
256 |
|
{ |
257 |
28059 |
merges++; |
258 |
28059 |
out_clause.clear(); |
259 |
|
|
260 |
28059 |
bool ps_smallest = _ps.size() < _qs.size(); |
261 |
28059 |
const Clause& ps = ps_smallest ? _qs : _ps; |
262 |
28059 |
const Clause& qs = ps_smallest ? _ps : _qs; |
263 |
|
|
264 |
58929 |
for (int i = 0; i < qs.size(); i++) |
265 |
|
{ |
266 |
47675 |
if (var(qs[i]) != v) |
267 |
|
{ |
268 |
139521 |
for (int j = 0; j < ps.size(); j++) |
269 |
|
{ |
270 |
125484 |
if (var(ps[j]) == var(qs[i])) |
271 |
|
{ |
272 |
20470 |
if (ps[j] == ~qs[i]) |
273 |
16805 |
return false; |
274 |
|
else |
275 |
3665 |
goto next; |
276 |
|
} |
277 |
|
} |
278 |
14037 |
out_clause.push(qs[i]); |
279 |
|
} |
280 |
44038 |
next:; |
281 |
|
} |
282 |
|
|
283 |
57606 |
for (int i = 0; i < ps.size(); i++) |
284 |
46352 |
if (var(ps[i]) != v) |
285 |
35098 |
out_clause.push(ps[i]); |
286 |
|
|
287 |
11254 |
return true; |
288 |
|
} |
289 |
|
|
290 |
|
|
291 |
|
// Returns FALSE if clause is always satisfied. |
292 |
57407 |
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size) |
293 |
|
{ |
294 |
57407 |
merges++; |
295 |
|
|
296 |
57407 |
bool ps_smallest = _ps.size() < _qs.size(); |
297 |
57407 |
const Clause& ps = ps_smallest ? _qs : _ps; |
298 |
57407 |
const Clause& qs = ps_smallest ? _ps : _qs; |
299 |
57407 |
const Lit* __ps = (const Lit*)ps; |
300 |
57407 |
const Lit* __qs = (const Lit*)qs; |
301 |
|
|
302 |
57407 |
size = ps.size()-1; |
303 |
|
|
304 |
148391 |
for (int i = 0; i < qs.size(); i++) |
305 |
|
{ |
306 |
116469 |
if (var(__qs[i]) != v) |
307 |
|
{ |
308 |
395641 |
for (int j = 0; j < ps.size(); j++) |
309 |
|
{ |
310 |
347652 |
if (var(__ps[j]) == var(__qs[i])) |
311 |
|
{ |
312 |
33100 |
if (__ps[j] == ~__qs[i]) |
313 |
25485 |
return false; |
314 |
|
else |
315 |
7615 |
goto next; |
316 |
|
} |
317 |
|
} |
318 |
47989 |
size++; |
319 |
|
} |
320 |
126364 |
next:; |
321 |
|
} |
322 |
|
|
323 |
31922 |
return true; |
324 |
|
} |
325 |
|
|
326 |
|
|
327 |
5956 |
void SimpSolver::gatherTouchedClauses() |
328 |
|
{ |
329 |
5956 |
if (n_touched == 0) return; |
330 |
|
|
331 |
|
int i,j; |
332 |
6291873 |
for (i = j = 0; i < subsumption_queue.size(); i++) |
333 |
6285919 |
if (ca[subsumption_queue[i]].mark() == 0) |
334 |
6285919 |
ca[subsumption_queue[i]].mark(2); |
335 |
|
|
336 |
19349928 |
for (i = 0; i < touched.size(); i++) |
337 |
19343974 |
if (touched[i]){ |
338 |
1791671 |
const vec<CRef>& cs = occurs.lookup(i); |
339 |
29723196 |
for (j = 0; j < cs.size(); j++) |
340 |
27931525 |
if (ca[cs[j]].mark() == 0){ |
341 |
8217514 |
subsumption_queue.insert(cs[j]); |
342 |
8217514 |
ca[cs[j]].mark(2); |
343 |
|
} |
344 |
1791671 |
touched[i] = 0; |
345 |
|
} |
346 |
|
|
347 |
14509387 |
for (i = 0; i < subsumption_queue.size(); i++) |
348 |
14503433 |
if (ca[subsumption_queue[i]].mark() == 2) |
349 |
14503433 |
ca[subsumption_queue[i]].mark(0); |
350 |
|
|
351 |
5954 |
n_touched = 0; |
352 |
|
} |
353 |
|
|
354 |
|
bool SimpSolver::implied(const vec<Lit>& clause) |
355 |
|
{ |
356 |
|
Assert(decisionLevel() == 0); |
357 |
|
|
358 |
|
trail_lim.push(trail.size()); |
359 |
|
for (int i = 0; i < clause.size(); i++) |
360 |
|
{ |
361 |
|
if (value(clause[i]) == l_True) |
362 |
|
{ |
363 |
|
cancelUntil(0); |
364 |
|
return false; |
365 |
|
} |
366 |
|
else if (value(clause[i]) != l_False) |
367 |
|
{ |
368 |
|
Assert(value(clause[i]) == l_Undef); |
369 |
|
uncheckedEnqueue(~clause[i]); |
370 |
|
} |
371 |
|
} |
372 |
|
|
373 |
|
bool result = propagate() != CRef_Undef; |
374 |
|
cancelUntil(0); |
375 |
|
return result; |
376 |
|
} |
377 |
|
|
378 |
|
|
379 |
|
// Backward subsumption + backward subsumption resolution |
380 |
8476 |
bool SimpSolver::backwardSubsumptionCheck(bool verbose) |
381 |
|
{ |
382 |
8476 |
int cnt = 0; |
383 |
8476 |
int subsumed = 0; |
384 |
8476 |
int deleted_literals = 0; |
385 |
8476 |
Assert(decisionLevel() == 0); |
386 |
|
|
387 |
29139046 |
while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){ |
388 |
|
|
389 |
|
// Empty subsumption queue and return immediately on user-interrupt: |
390 |
14565285 |
if (asynch_interrupt){ |
391 |
|
subsumption_queue.clear(); |
392 |
|
bwdsub_assigns = trail.size(); |
393 |
|
break; } |
394 |
|
|
395 |
|
// Check top-level assignments by creating a dummy clause and placing it in the queue: |
396 |
14565285 |
if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){ |
397 |
6461 |
Lit l = trail[bwdsub_assigns++]; |
398 |
6461 |
ca[bwdsub_tmpunit][0] = l; |
399 |
6461 |
ca[bwdsub_tmpunit].calcAbstraction(); |
400 |
6461 |
subsumption_queue.insert(bwdsub_tmpunit); } |
401 |
|
|
402 |
14565285 |
CRef cr = subsumption_queue.peek(); subsumption_queue.pop(); |
403 |
14565285 |
Clause& clause = ca[cr]; |
404 |
|
|
405 |
14565285 |
if (clause.mark()) continue; |
406 |
|
|
407 |
14540160 |
if (verbose && verbosity >= 2 && cnt++ % 1000 == 0) |
408 |
|
printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals); |
409 |
|
|
410 |
14540160 |
Assert(clause.size() > 1 |
411 |
|
|| value(clause[0]) == l_True); // Unit-clauses should have been |
412 |
|
// propagated before this point. |
413 |
|
|
414 |
|
// Find best variable to scan: |
415 |
14540160 |
Var best = var(clause[0]); |
416 |
42210171 |
for (int i = 1; i < clause.size(); i++) |
417 |
27670011 |
if (occurs[var(clause[i])].size() < occurs[best].size()) |
418 |
12825980 |
best = var(clause[i]); |
419 |
|
|
420 |
|
// Search all candidates: |
421 |
14540160 |
vec<CRef>& _cs = occurs.lookup(best); |
422 |
14540160 |
CRef* cs = (CRef*)_cs; |
423 |
|
|
424 |
162866454 |
for (int j = 0; j < _cs.size(); j++) |
425 |
148326294 |
if (clause.mark()) |
426 |
|
break; |
427 |
444977668 |
else if (!ca[cs[j]].mark() && cs[j] != cr |
428 |
415909056 |
&& (subsumption_lim == -1 |
429 |
133791381 |
|| ca[cs[j]].size() < subsumption_lim)) |
430 |
|
{ |
431 |
133791381 |
Lit l = clause.subsumes(ca[cs[j]]); |
432 |
|
|
433 |
133791381 |
if (l == lit_Undef) |
434 |
33577 |
subsumed++, removeClause(cs[j]); |
435 |
133757804 |
else if (l != lit_Error) |
436 |
|
{ |
437 |
44137 |
deleted_literals++; |
438 |
|
|
439 |
44137 |
if (!strengthenClause(cs[j], ~l)) return false; |
440 |
|
|
441 |
|
// Did current candidate get deleted from cs? Then check candidate |
442 |
|
// at index j again: |
443 |
44137 |
if (var(l) == best) j--; |
444 |
|
} |
445 |
|
} |
446 |
|
} |
447 |
|
|
448 |
8476 |
return true; |
449 |
|
} |
450 |
|
|
451 |
|
|
452 |
|
bool SimpSolver::asymm(Var v, CRef cr) |
453 |
|
{ |
454 |
|
Clause& clause = ca[cr]; |
455 |
|
Assert(decisionLevel() == 0); |
456 |
|
|
457 |
|
if (clause.mark() || satisfied(clause)) return true; |
458 |
|
|
459 |
|
trail_lim.push(trail.size()); |
460 |
|
Lit l = lit_Undef; |
461 |
|
for (int i = 0; i < clause.size(); i++) |
462 |
|
if (var(clause[i]) != v && value(clause[i]) != l_False) |
463 |
|
uncheckedEnqueue(~clause[i]); |
464 |
|
else |
465 |
|
l = clause[i]; |
466 |
|
|
467 |
|
if (propagate() != CRef_Undef) |
468 |
|
{ |
469 |
|
cancelUntil(0); |
470 |
|
asymm_lits++; |
471 |
|
if (!strengthenClause(cr, l)) return false; |
472 |
|
} |
473 |
|
else |
474 |
|
cancelUntil(0); |
475 |
|
|
476 |
|
return true; |
477 |
|
} |
478 |
|
|
479 |
|
|
480 |
|
bool SimpSolver::asymmVar(Var v) |
481 |
|
{ |
482 |
|
Assert(use_simplification); |
483 |
|
|
484 |
|
const vec<CRef>& cls = occurs.lookup(v); |
485 |
|
|
486 |
|
if (value(v) != l_Undef || cls.size() == 0) return true; |
487 |
|
|
488 |
|
for (int i = 0; i < cls.size(); i++) |
489 |
|
if (!asymm(v, cls[i])) return false; |
490 |
|
|
491 |
|
return backwardSubsumptionCheck(); |
492 |
|
} |
493 |
|
|
494 |
|
|
495 |
2520 |
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x) |
496 |
|
{ |
497 |
2520 |
elimclauses.push(toInt(x)); |
498 |
2520 |
elimclauses.push(1); |
499 |
2520 |
} |
500 |
|
|
501 |
6220 |
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& clause) |
502 |
|
{ |
503 |
6220 |
int first = elimclauses.size(); |
504 |
6220 |
int v_pos = -1; |
505 |
|
|
506 |
|
// Copy clause to elimclauses-vector. Remember position where the |
507 |
|
// variable 'v' occurs: |
508 |
29061 |
for (int i = 0; i < clause.size(); i++) |
509 |
|
{ |
510 |
22841 |
elimclauses.push(toInt(clause[i])); |
511 |
22841 |
if (var(clause[i]) == v) v_pos = i + first; |
512 |
|
} |
513 |
6220 |
Assert(v_pos != -1); |
514 |
|
|
515 |
|
// Swap the first literal with the 'v' literal, so that the literal |
516 |
|
// containing 'v' will occur first in the clause: |
517 |
6220 |
uint32_t tmp = elimclauses[v_pos]; |
518 |
6220 |
elimclauses[v_pos] = elimclauses[first]; |
519 |
6220 |
elimclauses[first] = tmp; |
520 |
|
|
521 |
|
// Store the length of the clause last: |
522 |
6220 |
elimclauses.push(clause.size()); |
523 |
6220 |
} |
524 |
|
|
525 |
|
|
526 |
|
|
527 |
4028 |
bool SimpSolver::eliminateVar(Var v) |
528 |
|
{ |
529 |
4028 |
Assert(!frozen[v]); |
530 |
4028 |
Assert(!isEliminated(v)); |
531 |
4028 |
Assert(value(v) == l_Undef); |
532 |
|
|
533 |
|
// Split the occurrences into positive and negative: |
534 |
|
// |
535 |
4028 |
const vec<CRef>& cls = occurs.lookup(v); |
536 |
8056 |
vec<CRef> pos, neg; |
537 |
39476 |
for (int i = 0; i < cls.size(); i++) |
538 |
35448 |
(find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); |
539 |
|
|
540 |
|
// Check whether the increase in number of clauses stays within the allowed |
541 |
|
// ('grow'). Moreover, no clause must exceed the limit on the maximal clause |
542 |
|
// size (if it is set): |
543 |
|
// |
544 |
4028 |
int cnt = 0; |
545 |
4028 |
int clause_size = 0; |
546 |
|
|
547 |
14005 |
for (int i = 0; i < pos.size(); i++) |
548 |
67384 |
for (int j = 0; j < neg.size(); j++) |
549 |
114814 |
if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) |
550 |
58915 |
&& (++cnt > cls.size() + grow |
551 |
30414 |
|| (clause_lim != -1 && clause_size > clause_lim))) |
552 |
1508 |
return true; |
553 |
|
|
554 |
|
// Delete and store old clauses: |
555 |
2520 |
eliminated[v] = true; |
556 |
2520 |
setDecisionVar(v, false); |
557 |
2520 |
eliminated_vars++; |
558 |
|
|
559 |
2520 |
if (pos.size() > neg.size()) |
560 |
|
{ |
561 |
734 |
for (int i = 0; i < neg.size(); i++) |
562 |
496 |
mkElimClause(elimclauses, v, ca[neg[i]]); |
563 |
238 |
mkElimClause(elimclauses, mkLit(v)); |
564 |
|
} |
565 |
|
else |
566 |
|
{ |
567 |
8006 |
for (int i = 0; i < pos.size(); i++) |
568 |
5724 |
mkElimClause(elimclauses, v, ca[pos[i]]); |
569 |
2282 |
mkElimClause(elimclauses, ~mkLit(v)); |
570 |
|
} |
571 |
|
|
572 |
2520 |
for (int i = 0; i < cls.size(); i++) removeClause(cls[i]); |
573 |
|
|
574 |
|
// Produce clauses in cross product: |
575 |
2520 |
vec<Lit>& resolvent = add_tmp; |
576 |
8987 |
for (int i = 0; i < pos.size(); i++) |
577 |
34526 |
for (int j = 0; j < neg.size(); j++) { |
578 |
28059 |
ClauseId id = -1; |
579 |
39313 |
if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && |
580 |
11254 |
!addClause_(resolvent, id)) |
581 |
|
return false; |
582 |
|
} |
583 |
|
|
584 |
|
// Free occurs list for this variable: |
585 |
2520 |
occurs[v].clear(true); |
586 |
|
|
587 |
|
// Free watchers lists for this variable, if possible: |
588 |
2520 |
if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true); |
589 |
2520 |
if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true); |
590 |
|
|
591 |
2520 |
return backwardSubsumptionCheck(); |
592 |
|
} |
593 |
|
|
594 |
|
|
595 |
|
bool SimpSolver::substitute(Var v, Lit x) |
596 |
|
{ |
597 |
|
Assert(!frozen[v]); |
598 |
|
Assert(!isEliminated(v)); |
599 |
|
Assert(value(v) == l_Undef); |
600 |
|
|
601 |
|
if (!ok) return false; |
602 |
|
|
603 |
|
eliminated[v] = true; |
604 |
|
setDecisionVar(v, false); |
605 |
|
const vec<CRef>& cls = occurs.lookup(v); |
606 |
|
|
607 |
|
vec<Lit>& subst_clause = add_tmp; |
608 |
|
for (int i = 0; i < cls.size(); i++) |
609 |
|
{ |
610 |
|
Clause& clause = ca[cls[i]]; |
611 |
|
|
612 |
|
subst_clause.clear(); |
613 |
|
for (int j = 0; j < clause.size(); j++) |
614 |
|
{ |
615 |
|
Lit p = clause[j]; |
616 |
|
subst_clause.push(var(p) == v ? x ^ sign(p) : p); |
617 |
|
} |
618 |
|
|
619 |
|
removeClause(cls[i]); |
620 |
|
ClauseId id; |
621 |
|
if (!addClause_(subst_clause, id)) return ok = false; |
622 |
|
} |
623 |
|
|
624 |
|
return true; |
625 |
|
} |
626 |
|
|
627 |
|
|
628 |
|
void SimpSolver::extendModel() |
629 |
|
{ |
630 |
|
int i, j; |
631 |
|
Lit x; |
632 |
|
|
633 |
|
for (i = elimclauses.size()-1; i > 0; i -= j){ |
634 |
|
for (j = elimclauses[i--]; j > 1; j--, i--) |
635 |
|
if (modelValue(toLit(elimclauses[i])) != l_False) |
636 |
|
goto next; |
637 |
|
|
638 |
|
x = toLit(elimclauses[i]); |
639 |
|
model[var(x)] = lbool(!sign(x)); |
640 |
|
next:; |
641 |
|
} |
642 |
|
} |
643 |
|
|
644 |
|
|
645 |
5945 |
bool SimpSolver::eliminate(bool turn_off_elim) |
646 |
|
{ |
647 |
|
// cvc5::TimerStat::CodeTimer codeTimer(total_eliminate_time); |
648 |
|
|
649 |
5945 |
if (!simplify()) |
650 |
|
return false; |
651 |
5945 |
else if (!use_simplification) |
652 |
|
return true; |
653 |
|
|
654 |
|
// Main simplification loop: |
655 |
|
// |
656 |
17857 |
while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0) |
657 |
|
{ |
658 |
5956 |
gatherTouchedClauses(); |
659 |
|
// printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", |
660 |
|
// cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); |
661 |
11914 |
if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) |
662 |
11912 |
&& !backwardSubsumptionCheck(true)) |
663 |
|
{ |
664 |
|
ok = false; |
665 |
|
goto cleanup; |
666 |
|
} |
667 |
|
|
668 |
|
// Empty elim_heap and return immediately on user-interrupt: |
669 |
5956 |
if (asynch_interrupt) |
670 |
|
{ |
671 |
|
Assert(bwdsub_assigns == trail.size()); |
672 |
|
Assert(subsumption_queue.size() == 0); |
673 |
|
Assert(n_touched == 0); |
674 |
|
elim_heap.clear(); |
675 |
|
goto cleanup; |
676 |
|
} |
677 |
|
|
678 |
|
// printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), |
679 |
|
// elim_heap.size()); |
680 |
1643570 |
for (int cnt = 0; !elim_heap.empty(); cnt++) |
681 |
|
{ |
682 |
1637614 |
Var elim = elim_heap.removeMin(); |
683 |
|
|
684 |
1637614 |
if (asynch_interrupt) break; |
685 |
|
|
686 |
1637614 |
if (isEliminated(elim) || value(elim) != l_Undef) continue; |
687 |
|
|
688 |
1631184 |
if (verbosity >= 2 && cnt % 100 == 0) |
689 |
|
printf("elimination left: %10d\r", elim_heap.size()); |
690 |
|
|
691 |
1631184 |
if (use_asymm) |
692 |
|
{ |
693 |
|
// Temporarily freeze variable. Otherwise, it would immediately end up |
694 |
|
// on the queue again: |
695 |
|
bool was_frozen = frozen[elim]; |
696 |
|
frozen[elim] = true; |
697 |
|
if (!asymmVar(elim)) |
698 |
|
{ |
699 |
|
ok = false; |
700 |
|
goto cleanup; |
701 |
|
} |
702 |
|
frozen[elim] = was_frozen; |
703 |
|
} |
704 |
|
|
705 |
|
// At this point, the variable may have been set by assymetric branching, |
706 |
|
// so check it again. Also, don't eliminate frozen variables: |
707 |
3268335 |
if (use_elim && value(elim) == l_Undef && !frozen[elim] |
708 |
1635212 |
&& !eliminateVar(elim)) |
709 |
|
{ |
710 |
|
ok = false; |
711 |
|
goto cleanup; |
712 |
|
} |
713 |
|
|
714 |
1631184 |
checkGarbage(simp_garbage_frac); |
715 |
|
} |
716 |
|
|
717 |
5956 |
Assert(subsumption_queue.size() == 0); |
718 |
|
} |
719 |
5945 |
cleanup: |
720 |
|
|
721 |
|
// If no more simplification is needed, free all simplification-related data structures: |
722 |
5945 |
if (turn_off_elim){ |
723 |
|
touched .clear(true); |
724 |
|
occurs .clear(true); |
725 |
|
n_occ .clear(true); |
726 |
|
elim_heap.clear(true); |
727 |
|
subsumption_queue.clear(true); |
728 |
|
|
729 |
|
use_simplification = false; |
730 |
|
remove_satisfied = true; |
731 |
|
ca.extra_clause_field = false; |
732 |
|
|
733 |
|
// Force full cleanup (this is safe and desirable since it only happens once): |
734 |
|
rebuildOrderHeap(); |
735 |
|
garbageCollect(); |
736 |
|
}else{ |
737 |
|
// Cheaper cleanup: |
738 |
5945 |
cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow? |
739 |
5945 |
checkGarbage(); |
740 |
|
} |
741 |
|
|
742 |
5945 |
if (verbosity >= 1 && elimclauses.size() > 0) |
743 |
|
printf( |
744 |
|
"| Eliminated clauses: %10.2f Mb " |
745 |
|
" |\n", |
746 |
|
double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024)); |
747 |
|
|
748 |
5945 |
return ok; |
749 |
|
|
750 |
|
|
751 |
|
|
752 |
|
} |
753 |
|
|
754 |
|
|
755 |
6005 |
void SimpSolver::cleanUpClauses() |
756 |
|
{ |
757 |
6005 |
occurs.cleanAll(); |
758 |
|
int i,j; |
759 |
95610297 |
for (i = j = 0; i < clauses.size(); i++) |
760 |
95604292 |
if (ca[clauses[i]].mark() == 0) |
761 |
95550946 |
clauses[j++] = clauses[i]; |
762 |
6005 |
clauses.shrink(i - j); |
763 |
6005 |
} |
764 |
|
|
765 |
|
|
766 |
|
//================================================================================================= |
767 |
|
// Garbage Collection methods: |
768 |
|
|
769 |
|
|
770 |
60 |
void SimpSolver::relocAll(ClauseAllocator& to) |
771 |
|
{ |
772 |
60 |
if (!use_simplification) return; |
773 |
|
|
774 |
|
// All occurs lists: |
775 |
|
// |
776 |
44543 |
for (int i = 0; i < nVars(); i++){ |
777 |
44483 |
vec<CRef>& cs = occurs[i]; |
778 |
434754 |
for (int j = 0; j < cs.size(); j++) |
779 |
390271 |
ca.reloc(cs[j], to); |
780 |
|
} |
781 |
|
|
782 |
|
// Subsumption queue: |
783 |
|
// |
784 |
300 |
for (int i = 0; i < subsumption_queue.size(); i++) |
785 |
240 |
ca.reloc(subsumption_queue[i], to); |
786 |
|
|
787 |
|
// Temporary clause: |
788 |
|
// |
789 |
60 |
ca.reloc(bwdsub_tmpunit, to); |
790 |
|
} |
791 |
|
|
792 |
|
|
793 |
60 |
void SimpSolver::garbageCollect() |
794 |
|
{ |
795 |
|
// Initialize the next region to a size corresponding to the estimated utilization degree. This |
796 |
|
// is not precise but should avoid some unnecessary reallocations for the new region: |
797 |
120 |
ClauseAllocator to(ca.size() - ca.wasted()); |
798 |
|
|
799 |
60 |
cleanUpClauses(); |
800 |
60 |
to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. |
801 |
60 |
relocAll(to); |
802 |
60 |
Solver::relocAll(to); |
803 |
60 |
if (verbosity >= 2) |
804 |
|
printf( |
805 |
|
"| Garbage collection: %12d bytes => %12d bytes |\n", |
806 |
|
ca.size() * ClauseAllocator::Unit_Size, |
807 |
|
to.size() * ClauseAllocator::Unit_Size); |
808 |
60 |
to.moveTo(ca); |
809 |
60 |
} |
810 |
|
|
811 |
|
} // namespace BVMinisat |
812 |
1640259 |
} // namespace cvc5 |