1 /******************************************
2 Copyright (c) 2016, Mate Soos
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 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
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 ***********************************************/
22
23 #include "varreplacer.h"
24 #include "varupdatehelper.h"
25 #include "solver.h"
26 #include "clausecleaner.h"
27 #include "time_mem.h"
28 #include "clauseallocator.h"
29 #include "sqlstats.h"
30 #include "sccfinder.h"
31 #ifdef USE_BREAKID
32 #include "cms_breakid.h"
33 #endif
34
35 #include <iostream>
36 #include <iomanip>
37 #include <set>
38 using std::cout;
39 using std::endl;
40
41 #ifdef VERBOSE_DEBUG
42 #define REPLACE_STATISTICS
43 #define VERBOSE_DEBUG_BIN_REPLACER
44 #endif
45
46 using namespace CMSat;
47
48 //#define VERBOSE_DEBUG
49 //#define REPLACE_STATISTICS
50 //#define DEBUG_BIN_REPLACER
51 //#define VERBOSE_DEBUG_BIN_REPLACER
52
VarReplacer(Solver * _solver)53 VarReplacer::VarReplacer(Solver* _solver) :
54 solver(_solver)
55 {
56 scc_finder = new SCCFinder(_solver);
57 ps_tmp.resize(2);
58 }
59
~VarReplacer()60 VarReplacer::~VarReplacer()
61 {
62 delete scc_finder;
63 }
64
new_var(const uint32_t orig_outer)65 void VarReplacer::new_var(const uint32_t orig_outer)
66 {
67 if (orig_outer == std::numeric_limits<uint32_t>::max()) {
68 table.push_back(Lit(table.size(), false));
69 }
70 }
71
check_no_replaced_var_set() const72 void VarReplacer::check_no_replaced_var_set() const
73 {
74 for(uint32_t var = 0; var < solver->nVarsOuter(); var++) {
75 if (solver->value(var) != l_Undef) {
76 if (solver->varData[var].removed != Removed::none)
77 {
78 cout << "ERROR: var " << var + 1 << " has removed: "
79 << removed_type_to_string(solver->varData[var].removed)
80 << " but is set to " << solver->value(var) << endl;
81 assert(solver->varData[var].removed == Removed::none);
82 exit(-1);
83 }
84 }
85 }
86 }
87
new_vars(const size_t n)88 void VarReplacer::new_vars(const size_t n)
89 {
90 size_t oldsize = table.size();
91 table.insert(table.end(), n, lit_Undef);
92 for(size_t i = oldsize; i < table.size(); i++) {
93 table[i] = Lit(i, false);
94 }
95 }
96
save_on_var_memory()97 void VarReplacer::save_on_var_memory()
98 {
99 }
100
updateVars(const std::vector<uint32_t> &,const std::vector<uint32_t> &)101 void VarReplacer::updateVars(
102 const std::vector< uint32_t >& /*outerToInter*/
103 , const std::vector< uint32_t >& /*interToOuter*/
104 ) {
105 //Nothing to do, we keep OUTER in all these data structures
106 //hence, it needs no update
107 }
108
printReplaceStats() const109 void VarReplacer::printReplaceStats() const
110 {
111 uint32_t i = 0;
112 for (vector<Lit>::const_iterator
113 it = table.begin(); it != table.end()
114 ; ++it, i++
115 ) {
116 if (it->var() == i) continue;
117 cout << "Replacing var " << i+1 << " with Lit " << *it << endl;
118 }
119 }
120
121 // Updating activities/data about variables.
122 // Given: a V b
123 // -a V -b
124 // Means: a = ~b
125 // a is replaced by ~b
126 // Then: orig = a
127 // replaced_with = ~b
update_vardata_and_activities(const Lit orig,const Lit replaced_with)128 void VarReplacer::update_vardata_and_activities(
129 const Lit orig
130 , const Lit replaced_with
131 ) {
132 uint32_t orig_var = orig.var();
133 uint32_t replaced_with_var = replaced_with.var();
134
135 //Not replaced_with, or not replaceable, so skip
136 if (orig_var == replaced_with_var
137 || solver->varData[replaced_with_var].removed == Removed::decomposed
138 || solver->varData[replaced_with_var].removed == Removed::elimed
139 ) {
140 return;
141 }
142
143 //Has already been handled previously, just skip
144 if (solver->varData[orig_var].removed == Removed::replaced) {
145 return;
146 }
147
148 //Okay, so unset decision, and set the other one decision
149 assert(orig_var != replaced_with_var);
150 solver->varData[orig_var].removed = Removed::replaced;
151 assert(solver->varData[replaced_with_var].removed == Removed::none);
152 assert(solver->value(replaced_with_var) == l_Undef);
153
154 //Update activities
155 solver->var_act_vsids[replaced_with_var].add_in(solver->var_act_vsids[orig_var]);
156 solver->var_act_maple[replaced_with_var].add_in(solver->var_act_maple[orig_var]);
157
158 assert(orig_var <= solver->nVars() && replaced_with_var <= solver->nVars());
159 }
160
enqueueDelayedEnqueue()161 bool VarReplacer::enqueueDelayedEnqueue()
162 {
163 for(Lit lit: delayedEnqueue) {
164 lit = get_lit_replaced_with(lit);
165 if (solver->value(lit) == l_Undef) {
166 solver->enqueue(lit);
167 #ifdef STATS_NEEDED
168 solver->propStats.propsUnit++;
169 #endif
170 } else if (solver->value(lit) == l_False) {
171 solver->ok = false;
172 break;
173 }
174 }
175 delayedEnqueue.clear();
176
177 if (!solver->ok)
178 return false;
179
180 solver->ok = solver->propagate<false>().isNULL();
181 return solver->okay();
182 }
183
attach_delayed_attach()184 void VarReplacer::attach_delayed_attach()
185 {
186 for(Clause* c: delayed_attach_or_free) {
187 if (c->size() <= 2) {
188 solver->free_cl(c);
189 } else {
190 c->unset_removed();
191 solver->attachClause(*c);
192 }
193 }
194 delayed_attach_or_free.clear();
195 }
196
update_all_vardata_activities()197 void VarReplacer::update_all_vardata_activities()
198 {
199 uint32_t var = 0;
200 for (vector<Lit>::const_iterator
201 it = table.begin(); it != table.end()
202 ; ++it, var++
203 ) {
204 const uint32_t orig = solver->map_outer_to_inter(var);
205 const Lit orig_lit = Lit(orig, false);
206
207 const uint32_t repl = solver->map_outer_to_inter(it->var());
208 const Lit repl_lit = Lit(repl, it->sign());
209
210 update_vardata_and_activities(orig_lit, repl_lit);
211 }
212 }
213
perform_replace()214 bool VarReplacer::perform_replace()
215 {
216 assert(solver->ok);
217 checkUnsetSanity();
218
219 //Set up stats
220 runStats.clear();
221 runStats.numCalls = 1;
222 const double myTime = cpuTime();
223 const size_t origTrailSize = solver->trail_size();
224
225 solver->clauseCleaner->remove_and_clean_all();
226 #ifdef DEBUG_ATTACH_MORE
227 solver->test_all_clause_attached();
228 #endif
229
230 //Printing stats
231 if (solver->conf.verbosity >= 5)
232 printReplaceStats();
233
234 update_all_vardata_activities();
235 check_no_replaced_var_set();
236
237 runStats.actuallyReplacedVars = replacedVars -lastReplacedVars;
238 lastReplacedVars = replacedVars;
239
240 #ifdef DEBUG_ATTACH_MORE
241 solver->test_all_clause_attached();
242 #endif
243 assert(solver->prop_at_head());
244
245 #ifdef DEBUG_IMPLICIT_STATS
246 solver->check_implicit_stats();
247 #endif
248 build_fast_inter_replace_lookup();
249
250 //Replace implicits
251 if (!replaceImplicit()) {
252 goto end;
253 }
254
255 //Replace longs
256 assert(solver->watches.get_smudged_list().empty());
257 assert(delayed_attach_or_free.empty());
258 if (!replace_set(solver->longIrredCls)) {
259 goto end;
260 }
261 for(auto& lredcls: solver->longRedCls) {
262 if (!replace_set(lredcls)) {
263 goto end;
264 }
265 }
266 solver->clean_occur_from_removed_clauses_only_smudged();
267 attach_delayed_attach();
268 if (!replace_xor_clauses(solver->xorclauses)) {
269 goto end;
270 }
271
272 if (!replace_xor_clauses(solver->xorclauses_unused)) {
273 goto end;
274 }
275 for(auto& v: solver->removed_xorclauses_clash_vars) {
276 v = get_var_replaced_with_fast(v);
277 }
278
279 //While replacing the clauses
280 //we cannot(for implicits) and/or shouldn't (for implicit & long cls) enqueue
281 //* We cannot because we are going through a struct and we might change it
282 //* We shouldn't because then non-dominators would end up in the 'trail'
283 if (!enqueueDelayedEnqueue()) {
284 goto end;
285 }
286
287 solver->update_assumptions_after_varreplace();
288 #ifdef USE_BREAKID
289 if (solver->breakid) {
290 solver->breakid->update_var_after_varreplace();
291 }
292 #endif
293
294 end:
295 delayed_attach_or_free.clear();
296 destroy_fast_inter_replace_lookup();
297 assert(solver->prop_at_head() || !solver->ok);
298
299 //Update stats
300 const double time_used = cpuTime() - myTime;
301 runStats.zeroDepthAssigns += solver->trail_size() - origTrailSize;
302 runStats.cpu_time = time_used;
303 globalStats += runStats;
304 if (solver->conf.verbosity) {
305 if (solver->conf.verbosity >= 3)
306 runStats.print(solver->nVarsOuter());
307 else
308 runStats.print_short(solver);
309 }
310 if (solver->sqlStats) {
311 solver->sqlStats->time_passed_min(
312 solver
313 , "vrep"
314 , time_used
315 );
316 }
317
318 if (solver->okay()) {
319 #ifdef DEBUG_ATTACH_MORE
320 solver->test_all_clause_attached();
321 #endif
322 solver->check_wrong_attach();
323 #ifdef DEBUG_IMPLICIT_STATS
324 solver->check_stats();
325 #endif
326 checkUnsetSanity();
327 }
328
329 return solver->okay();
330 }
331
replace_xor_clauses(vector<Xor> & xors)332 bool VarReplacer::replace_xor_clauses(vector<Xor>& xors)
333 {
334 for(Xor& x: xors) {
335 uint32_t j = 0;
336 for(uint32_t i = 0; i < x.clash_vars.size(); i++) {
337 uint32_t v = x.clash_vars[i];
338 uint32_t upd = get_var_replaced_with_fast(v);
339 if (!solver->seen[upd]) {
340 solver->seen[upd] = 1;
341 x.clash_vars[j++] = upd;
342 }
343 }
344 x.clash_vars.resize(j);
345
346 for(auto& v: x.clash_vars) {
347 solver->seen[v] = 0;
348 }
349
350 for(uint32_t& v: x) {
351 assert(v < solver->nVars());
352
353 Lit l = Lit(v, false);
354 if (get_lit_replaced_with_fast(l) != l) {
355 l = get_lit_replaced_with_fast(l);
356 x.rhs ^= l.sign();
357 v = l.var();
358 runStats.replacedLits++;
359 }
360 }
361
362 solver->clean_xor_vars_no_prop(x.get_vars(), x.rhs);
363 if (x.size() == 0 && x.rhs == true) {
364 solver->ok = false;
365 }
366 }
367
368 return solver->okay();
369 }
370
updateBin(Watched * i,Watched * & j,const Lit origLit1,const Lit origLit2,Lit lit1,Lit lit2)371 inline void VarReplacer::updateBin(
372 Watched* i
373 , Watched*& j
374 , const Lit origLit1
375 , const Lit origLit2
376 , Lit lit1
377 , Lit lit2
378 ) {
379 bool remove = false;
380
381 //Two lits are the same in BIN
382 if (lit1 == lit2) {
383 delayedEnqueue.push_back(lit2);
384 (*solver->drat) << add << lit2
385 #ifdef STATS_NEEDED
386 << 0
387 << solver->sumConflicts
388 #endif
389 << fin;
390 remove = true;
391 }
392
393 //Tautology
394 if (lit1 == ~lit2)
395 remove = true;
396
397 if (remove) {
398 impl_tmp_stats.remove(*i);
399
400 //Drat -- Delete only once
401 if (origLit1 < origLit2) {
402 (*solver->drat) << del << origLit1 << origLit2 << fin;
403 }
404
405 return;
406 }
407
408 //Drat
409 if (//Changed
410 (lit1 != origLit1
411 || lit2 != origLit2)
412 //Delete&attach only once
413 && (origLit1 < origLit2)
414 ) {
415 (*solver->drat)
416 << add << lit1 << lit2
417 #ifdef STATS_NEEDED
418 << 0
419 << solver->sumConflicts
420 #endif
421 << fin
422 << del << origLit1 << origLit2 << fin;
423 }
424
425 if (lit1 != origLit1) {
426 solver->watches[lit1].push(*i);
427 } else {
428 *j++ = *i;
429 }
430 }
431
updateStatsFromImplStats()432 void VarReplacer::updateStatsFromImplStats()
433 {
434 assert(impl_tmp_stats.removedRedBin % 2 == 0);
435 solver->binTri.redBins -= impl_tmp_stats.removedRedBin/2;
436
437 assert(impl_tmp_stats.removedIrredBin % 2 == 0);
438 solver->binTri.irredBins -= impl_tmp_stats.removedIrredBin/2;
439
440 #ifdef DEBUG_IMPLICIT_STATS
441 solver->check_implicit_stats();
442 #endif
443
444 runStats.removedBinClauses += impl_tmp_stats.removedRedBin/2 + impl_tmp_stats.removedIrredBin/2;
445
446 impl_tmp_stats.clear();
447 }
448
replaceImplicit()449 bool VarReplacer::replaceImplicit()
450 {
451 impl_tmp_stats.clear();
452 delayedEnqueue.clear();
453 delayed_attach_bin.clear();
454 assert(solver->watches.get_smudged_list().empty());
455
456 for(size_t i = 0; i < solver->nVars()*2; i++) {
457 const Lit lit = Lit::toLit(i);
458 if (get_lit_replaced_with_fast(lit) != lit) {
459 solver->watches.smudge(lit);
460 }
461 }
462
463 for(size_t at = 0; at < solver->watches.get_smudged_list().size(); at++) {
464 const Lit origLit1 = solver->watches.get_smudged_list()[at];
465 watch_subarray ws = solver->watches[origLit1];
466
467 Watched* i = ws.begin();
468 Watched* j = i;
469 for (Watched *end2 = ws.end(); i != end2; i++) {
470 //Don't bother clauses
471 if (i->isClause()) {
472 *j++ = *i;
473 continue;
474 }
475 runStats.bogoprops += 1;
476
477 const Lit origLit2 = i->lit2();
478 assert(solver->value(origLit1) == l_Undef);
479 assert(solver->value(origLit2) == l_Undef);
480 assert(origLit1.var() != origLit2.var());
481
482 //Update main lit
483 Lit lit1 = origLit1;
484 if (get_lit_replaced_with_fast(lit1) != lit1) {
485 lit1 = get_lit_replaced_with_fast(lit1);
486 runStats.replacedLits++;
487 solver->watches.smudge(origLit2);
488 }
489
490 //Update lit2
491 Lit lit2 = origLit2;
492 if (get_lit_replaced_with_fast(lit2) != lit2) {
493 lit2 = get_lit_replaced_with_fast(lit2);
494 i->setLit2(lit2);
495 runStats.replacedLits++;
496 }
497
498 assert(i->isBin());
499 updateBin(i, j, origLit1, origLit2, lit1, lit2);
500 }
501 ws.shrink_(i-j);
502 }
503
504 for(const BinaryClause& bincl : delayed_attach_bin) {
505 solver->attach_bin_clause(bincl.getLit1(), bincl.getLit2(), bincl.isRed());
506 }
507 delayed_attach_bin.clear();
508
509 #ifdef VERBOSE_DEBUG_BIN_REPLACER
510 cout << "c debug bin replacer start" << endl;
511 cout << "c debug bin replacer end" << endl;
512 #endif
513
514 updateStatsFromImplStats();
515 solver->watches.clear_smudged();
516
517 return solver->okay();
518 }
519
520 /**
521 @brief Replaces variables in long clauses
522 */
replace_set(vector<ClOffset> & cs)523 bool VarReplacer::replace_set(vector<ClOffset>& cs)
524 {
525 assert(!solver->drat->something_delayed());
526 vector<ClOffset>::iterator i = cs.begin();
527 vector<ClOffset>::iterator j = i;
528 for (vector<ClOffset>::iterator end = cs.end(); i != end; i++) {
529 runStats.bogoprops += 3;
530 assert(!solver->drat->something_delayed());
531
532 Clause& c = *solver->cl_alloc.ptr(*i);
533 assert(!c.getRemoved());
534 assert(c.size() > 2);
535
536 bool changed = false;
537 (*solver->drat) << deldelay << c << fin;
538
539 const Lit origLit1 = c[0];
540 const Lit origLit2 = c[1];
541
542 for (Lit& l: c) {
543 if (isReplaced_fast(l)) {
544 changed = true;
545 l = get_lit_replaced_with_fast(l);
546 runStats.replacedLits++;
547 }
548 }
549
550 if (changed && handleUpdatedClause(c, origLit1, origLit2)) {
551 runStats.removedLongClauses++;
552 if (!solver->ok) {
553 return false;
554 }
555 } else {
556 *j++ = *i;
557 solver->drat->forget_delay();
558 }
559
560 }
561 cs.resize(cs.size() - (i-j));
562 assert(!solver->drat->something_delayed());
563
564 return solver->okay();
565 }
566
my_lit_find(Clause & cl,const Lit lit)567 Lit* my_lit_find(Clause& cl, const Lit lit)
568 {
569 for(Lit* a = cl.begin(); a != cl.end(); a++) {
570 if (*a == lit)
571 return a;
572 }
573 return NULL;
574 }
575
576 /**
577 @returns TRUE if needs removal
578 */
handleUpdatedClause(Clause & c,const Lit origLit1,const Lit origLit2)579 bool VarReplacer::handleUpdatedClause(
580 Clause& c
581 , const Lit origLit1
582 , const Lit origLit2
583 ) {
584 assert(!c.getRemoved());
585 bool satisfied = false;
586 std::sort(c.begin(), c.end());
587 Lit p;
588 uint32_t i, j;
589 const uint32_t origSize = c.size();
590 for (i = j = 0, p = lit_Undef; i != origSize; i++) {
591 assert(solver->varData[c[i].var()].removed == Removed::none);
592 if (solver->value(c[i]) == l_True || c[i] == ~p) {
593 satisfied = true;
594 break;
595 }
596 else if (solver->value(c[i]) != l_False && c[i] != p) {
597 c[j++] = p = c[i];
598 }
599 }
600 c.shrink(i - j);
601 c.setStrenghtened();
602
603 runStats.bogoprops += 10;
604 if (c.red()) {
605 solver->litStats.redLits -= origSize;
606 } else {
607 solver->litStats.irredLits -= origSize;
608 }
609 delayed_attach_or_free.push_back(&c);
610
611 #ifdef VERBOSE_DEBUG
612 cout << "clause after replacing: " << c << endl;
613 #endif
614
615 if (satisfied) {
616 (*solver->drat) << findelay;
617 c.shrink(c.size()); //needed to make clause cleaner happy
618 solver->watches.smudge(origLit1);
619 solver->watches.smudge(origLit2);
620 c.setRemoved();
621 return true;
622 }
623 (*solver->drat) << add << c
624 #ifdef STATS_NEEDED
625 << solver->sumConflicts
626 #endif
627 << fin << findelay;
628
629 runStats.bogoprops += 3;
630 switch(c.size()) {
631 case 0:
632 c.setRemoved();
633 solver->ok = false;
634 return true;
635 case 1 :
636 c.setRemoved();
637 solver->watches.smudge(origLit1);
638 solver->watches.smudge(origLit2);
639
640 delayedEnqueue.push_back(c[0]);
641 runStats.removedLongLits += origSize;
642 return true;
643 case 2:
644 c.setRemoved();
645 solver->watches.smudge(origLit1);
646 solver->watches.smudge(origLit2);
647
648 solver->attach_bin_clause(c[0], c[1], c.red());
649 runStats.removedLongLits += origSize;
650 return true;
651
652 default:
653 Lit* at = my_lit_find(c, origLit1);
654 if (at != NULL) {
655 std::swap(c[0], *at);
656 }
657 Lit* at2 = my_lit_find(c, origLit2);
658 if (at2 != NULL) {
659 std::swap(c[1], *at2);
660 }
661 if (at != NULL && at2 != NULL) {
662 delayed_attach_or_free.pop_back();
663 if (c.red()) {
664 solver->litStats.redLits += c.size();
665 } else {
666 solver->litStats.irredLits += c.size();
667 }
668 } else {
669 c.setRemoved();
670 solver->watches.smudge(origLit1);
671 solver->watches.smudge(origLit2);
672 }
673
674 runStats.removedLongLits += origSize - c.size();
675 return false;
676 }
677
678 release_assert(false);
679 }
680
set_sub_var_during_solution_extension(uint32_t var,const uint32_t sub_var)681 void VarReplacer::set_sub_var_during_solution_extension(uint32_t var, const uint32_t sub_var)
682 {
683 const lbool to_set = solver->model[var] ^ table[sub_var].sign();
684 const uint32_t sub_var_inter = solver->map_outer_to_inter(sub_var);
685 assert(solver->varData[sub_var_inter].removed == Removed::replaced);
686 #ifdef VERBOSE_DEBUG
687 if (solver->model_value(sub_var) != l_Undef) {
688 cout << "ERROR: var " << sub_var +1 << " is set but it's replaced!" << endl;
689 }
690 #endif
691 assert(solver->model_value(sub_var) == l_Undef);
692
693 if (solver->conf.verbosity > 10) {
694 cout << "Varreplace-extend: setting outer " << sub_var+1
695 << " to " << to_set << " because of " << var+1 << endl;
696 }
697 solver->model[sub_var] = to_set;
698 }
699
700 //NOTE: 'var' is OUTER
extend_model(const uint32_t var)701 void VarReplacer::extend_model(const uint32_t var)
702 {
703 assert(solver->model[var] != l_Undef);
704 auto it = reverseTable.find(var);
705 if (it == reverseTable.end())
706 return;
707
708 assert(it->first == var);
709 for(const uint32_t sub_var: it->second)
710 {
711 set_sub_var_during_solution_extension(var, sub_var);
712 }
713 }
714
extend_pop_queue(vector<Lit> & pop)715 void VarReplacer::extend_pop_queue(vector<Lit>& pop)
716 {
717 vector<Lit> extra;
718 for (Lit p: pop) {
719 const auto& repl = reverseTable[p.var()];
720 for(uint32_t x: repl) {
721 extra.push_back(Lit(x, table[x].sign() ^ p.sign()));
722 }
723 }
724
725 for(Lit x: extra) {
726 pop.push_back(x);
727 }
728 }
729
extend_model_already_set()730 void VarReplacer::extend_model_already_set()
731 {
732 assert(solver->model.size() == solver->nVarsOuter());
733 for (auto it = reverseTable.begin() , end = reverseTable.end()
734 ; it != end
735 ; ++it
736 ) {
737 if (solver->model_value(it->first) == l_Undef) {
738 continue;
739 }
740
741 for(const uint32_t sub_var: it->second)
742 {
743 set_sub_var_during_solution_extension(it->first, sub_var);
744 }
745 }
746 }
747
extend_model_set_undef()748 void VarReplacer::extend_model_set_undef()
749 {
750 assert(solver->model.size() == solver->nVarsOuter());
751 for (auto it = reverseTable.begin() , end = reverseTable.end()
752 ; it != end
753 ; ++it
754 ) {
755 if (solver->model_value(it->first) == l_Undef) {
756 solver->model[it->first] = l_False;
757 for(const uint32_t sub_var: it->second)
758 {
759 set_sub_var_during_solution_extension(it->first, sub_var);
760 }
761 }
762 }
763 }
764
replaceChecks(const uint32_t var1,const uint32_t var2) const765 void VarReplacer::replaceChecks(const uint32_t var1, const uint32_t var2) const
766 {
767
768 assert(solver->ok);
769 assert(solver->decisionLevel() == 0);
770 assert(solver->value(var1) == l_Undef);
771 assert(solver->value(var2) == l_Undef);
772
773 assert(solver->varData[var1].removed == Removed::none);
774 assert(solver->varData[var2].removed == Removed::none);
775 }
776
handleAlreadyReplaced(const Lit lit1,const Lit lit2)777 bool VarReplacer::handleAlreadyReplaced(const Lit lit1, const Lit lit2)
778 {
779 //OOps, already inside, but with inverse polarity, UNSAT
780 if (lit1.sign() != lit2.sign()) {
781 (*solver->drat)
782 << add << ~lit1 << lit2
783 #ifdef STATS_NEEDED
784 << 0
785 << solver->sumConflicts
786 #endif
787 << fin
788
789 << add << lit1 << ~lit2
790 #ifdef STATS_NEEDED
791 << 0
792 << solver->sumConflicts
793 #endif
794 << fin
795
796 << add << lit1
797 #ifdef STATS_NEEDED
798 << 0
799 << solver->sumConflicts
800 #endif
801 << fin
802
803 << add << ~lit1
804 #ifdef STATS_NEEDED
805 << 0
806 << solver->sumConflicts
807 #endif
808 << fin;
809
810 solver->ok = false;
811 return false;
812 }
813
814 //Already inside in the correct way, return
815 return true;
816 }
817
replace_vars_already_set(const Lit lit1,const lbool val1,const Lit,const lbool val2)818 bool VarReplacer::replace_vars_already_set(
819 const Lit lit1
820 , const lbool val1
821 , const Lit /*lit2*/
822 , const lbool val2
823 ) {
824 if (val1 != val2) {
825 (*solver->drat)
826 << add << ~lit1
827 #ifdef STATS_NEEDED
828 << 0
829 << solver->sumConflicts
830 #endif
831 << fin
832
833 << add << lit1
834 #ifdef STATS_NEEDED
835 << 0
836 << solver->sumConflicts
837 #endif
838 << fin;
839
840 solver->ok = false;
841 }
842
843 //Already set, return with correct code
844 return solver->okay();
845 }
846
handleOneSet(const Lit lit1,const lbool val1,const Lit lit2,const lbool val2)847 bool VarReplacer::handleOneSet(
848 const Lit lit1
849 , const lbool val1
850 , const Lit lit2
851 , const lbool val2
852 ) {
853 if (solver->ok) {
854 Lit toEnqueue;
855 if (val1 != l_Undef) {
856 toEnqueue = lit2 ^ (val1 == l_False);
857 } else {
858 toEnqueue = lit1 ^ (val2 == l_False);
859 }
860 solver->enqueue(toEnqueue);
861 (*solver->drat) << add << toEnqueue
862 #ifdef STATS_NEEDED
863 << 0
864 << solver->sumConflicts
865 #endif
866 << fin;
867
868 #ifdef STATS_NEEDED
869 solver->propStats.propsUnit++;
870 #endif
871
872 solver->ok = (solver->propagate<false>().isNULL());
873 }
874 return solver->okay();
875 }
876
877 /**
878 @brief Replaces two two lits with one another
879 */
replace(uint32_t var1,uint32_t var2,const bool xor_is_true)880 bool VarReplacer::replace(
881 uint32_t var1
882 , uint32_t var2
883 , const bool xor_is_true
884 )
885 {
886 #ifdef VERBOSE_DEBUG
887 cout
888 << "replace() called with var " << Lit(var1, false)
889 << " and var " << Lit(var2, false)
890 << " with xor_is_true " << xor_is_true << endl;
891 #endif
892
893 replaceChecks(var1, var2);
894
895 #ifdef DRAT_DEBUG
896 (*solver->drat)
897 << add << Lit(var1, true) << (Lit(var2, false) ^ xor_is_true) << fin
898 << add << Lit(var1, false) << (Lit(var2, true) ^ xor_is_true) << fin
899 ;
900 #endif
901
902 //Move forward
903 const Lit lit1 = get_lit_replaced_with(Lit(var1, false));
904 const Lit lit2 = get_lit_replaced_with(Lit(var2, false)) ^ xor_is_true;
905
906 //Already inside?
907 if (lit1.var() == lit2.var()) {
908 return handleAlreadyReplaced(lit1, lit2);
909 }
910 (*solver->drat)
911 << add << ~lit1 << lit2
912 #ifdef STATS_NEEDED
913 << 0
914 << solver->sumConflicts
915 #endif
916 << fin
917 << add << lit1 << ~lit2
918 #ifdef STATS_NEEDED
919 << 0
920 << solver->sumConflicts
921 #endif
922 << fin;
923
924 //None should be removed, only maybe queued for replacement
925 assert(solver->varData[lit1.var()].removed == Removed::none);
926 assert(solver->varData[lit2.var()].removed == Removed::none);
927
928 const lbool val1 = solver->value(lit1);
929 const lbool val2 = solver->value(lit2);
930
931 //Both are set
932 if (val1 != l_Undef && val2 != l_Undef) {
933 return replace_vars_already_set(lit1, val1, lit2, val2);
934 }
935
936 //exactly one set
937 if ((val1 != l_Undef && val2 == l_Undef)
938 || (val2 != l_Undef && val1 == l_Undef)
939 ) {
940 return handleOneSet(lit1, val1, lit2, val2);
941 }
942
943 assert(val1 == l_Undef && val2 == l_Undef);
944
945 const Lit lit1_outer = solver->map_inter_to_outer(lit1);
946 const Lit lit2_outer = solver->map_inter_to_outer(lit2);
947 return update_table_and_reversetable(lit1_outer, lit2_outer);
948 }
949
update_table_and_reversetable(const Lit lit1,const Lit lit2)950 bool VarReplacer::update_table_and_reversetable(const Lit lit1, const Lit lit2)
951 {
952 if (reverseTable.find(lit1.var()) == reverseTable.end()) {
953 reverseTable[lit2.var()].push_back(lit1.var());
954 table[lit1.var()] = lit2 ^ lit1.sign();
955 replacedVars++;
956 return true;
957 }
958
959 if (reverseTable.find(lit2.var()) == reverseTable.end()) {
960 reverseTable[lit1.var()].push_back(lit2.var());
961 table[lit2.var()] = lit1 ^ lit2.sign();
962 replacedVars++;
963 return true;
964 }
965
966 //both have children
967 setAllThatPointsHereTo(lit1.var(), lit2 ^ lit1.sign());
968 replacedVars++;
969 return true;
970 }
971
972 /**
973 @brief Changes internal graph to set everything that pointed to var to point to lit
974 */
setAllThatPointsHereTo(const uint32_t var,const Lit lit)975 void VarReplacer::setAllThatPointsHereTo(const uint32_t var, const Lit lit)
976 {
977 map<uint32_t, vector<uint32_t> >::iterator it = reverseTable.find(var);
978 if (it != reverseTable.end()) {
979 for(const uint32_t var2: it->second) {
980 assert(table[var2].var() == var);
981 if (lit.var() != var2) {
982 table[var2] = lit ^ table[var2].sign();
983 reverseTable[lit.var()].push_back(var2);
984 }
985 }
986 reverseTable.erase(it);
987 }
988 table[var] = lit;
989 reverseTable[lit.var()].push_back(var);
990 }
991
checkUnsetSanity()992 void VarReplacer::checkUnsetSanity()
993 {
994 for(size_t i = 0; i < solver->nVarsOuter(); i++) {
995 const Lit repLit = get_lit_replaced_with(Lit(i, false));
996 const uint32_t repVar = get_var_replaced_with(i);
997
998 if (solver->varData[i].removed == Removed::none
999 && solver->varData[repVar].removed == Removed::none
1000 && solver->value(i) != solver->value(repLit)
1001 ) {
1002 cout
1003 << "Variable " << (i+1)
1004 << " has been set to " << solver->value(i)
1005 << " but it has been replaced with lit "
1006 << get_lit_replaced_with(Lit(i, false))
1007 << " and that has been set to "
1008 << solver->value(get_lit_replaced_with(Lit(i, false)))
1009 << endl;
1010
1011 assert(solver->value(i) == solver->value(repLit));
1012 std::exit(-1);
1013 }
1014 }
1015
1016 #ifdef SLOW_DEBUG
1017 check_no_replaced_var_set();
1018 #endif
1019 }
1020
add_xor_as_bins(const BinaryXor & bin_xor)1021 bool VarReplacer::add_xor_as_bins(const BinaryXor& bin_xor)
1022 {
1023 ps_tmp[0] = Lit(bin_xor.vars[0], false);
1024 ps_tmp[1] = Lit(bin_xor.vars[1], true ^ bin_xor.rhs);
1025 solver->add_clause_int(ps_tmp);
1026 if (!solver->ok) {
1027 return false;
1028 }
1029
1030 ps_tmp[0] = Lit(bin_xor.vars[0], true);
1031 ps_tmp[1] = Lit(bin_xor.vars[1], false ^ bin_xor.rhs);
1032 solver->add_clause_int(ps_tmp);
1033 if (!solver->ok) {
1034 return false;
1035 }
1036
1037 return true;
1038 }
1039
replace_if_enough_is_found(const size_t limit,uint64_t * bogoprops_given,bool * replaced)1040 bool VarReplacer::replace_if_enough_is_found(const size_t limit, uint64_t* bogoprops_given, bool *replaced)
1041 {
1042 if (replaced)
1043 *replaced = false;
1044
1045 scc_finder->performSCC(bogoprops_given);
1046 if (scc_finder->get_num_binxors_found() < limit) {
1047 scc_finder->clear_binxors();
1048 return solver->okay();
1049 }
1050
1051 #ifdef USE_GAUSS
1052 assert(solver->gmatrices.empty());
1053 assert(solver->gqueuedata.empty());
1054 #endif
1055
1056 if (replaced)
1057 *replaced = true;
1058
1059 const set<BinaryXor>& xors_found = scc_finder->get_binxors();
1060 for(BinaryXor bin_xor: xors_found) {
1061 if (!add_xor_as_bins(bin_xor)) {
1062 return false;
1063 }
1064
1065 if (solver->value(bin_xor.vars[0]) == l_Undef
1066 && solver->value(bin_xor.vars[1]) == l_Undef
1067 ) {
1068 replace(bin_xor.vars[0], bin_xor.vars[1], bin_xor.rhs);
1069 if (!solver->okay()) {
1070 return false;
1071 }
1072 }
1073 }
1074
1075 const bool ret = perform_replace();
1076 if (bogoprops_given) {
1077 *bogoprops_given += runStats.bogoprops;
1078 }
1079 scc_finder->clear_binxors();
1080
1081 return ret;
1082 }
1083
mem_used() const1084 size_t VarReplacer::mem_used() const
1085 {
1086 size_t b = 0;
1087 b += scc_finder->mem_used();
1088 b += delayedEnqueue.capacity()*sizeof(Lit);
1089 b += table.capacity()*sizeof(Lit);
1090 for(map<uint32_t, vector<uint32_t> >::const_iterator
1091 it = reverseTable.begin(), end = reverseTable.end()
1092 ; it != end
1093 ; ++it
1094 ) {
1095 b += it->second.capacity()*sizeof(Lit);
1096 }
1097 //TODO under-counting
1098 b += reverseTable.size()*(sizeof(uint32_t) + sizeof(vector<uint32_t>));
1099
1100 return b;
1101 }
1102
print_equivalent_literals(bool outer_numbering,std::ostream * os) const1103 uint32_t VarReplacer::print_equivalent_literals(bool outer_numbering, std::ostream *os) const
1104 {
1105 uint32_t num = 0;
1106 vector<Lit> tmpCl;
1107 for (uint32_t var = 0; var < table.size(); var++) {
1108 const Lit lit = table[var];
1109 if (lit.var() == var)
1110 continue;
1111
1112 //They have been renumbered in a way that cannot be dumped
1113 Lit lit1;
1114 Lit lit2;
1115 if (outer_numbering) {
1116 lit1 = lit;
1117 lit2 = Lit(var, false);
1118 } else {
1119 lit1 = solver->map_outer_to_inter(lit);
1120 lit2 = solver->map_outer_to_inter(Lit(var, false));
1121
1122 if (lit1.var() >= solver->nVars() ||
1123 lit2.var() >= solver->nVars()
1124 ) {
1125 continue;
1126 }
1127 }
1128
1129 if (os) {
1130 tmpCl.clear();
1131 tmpCl.push_back(~lit1);
1132 tmpCl.push_back(lit2);
1133 std::sort(tmpCl.begin(), tmpCl.end());
1134
1135 *os
1136 << tmpCl[0] << " "
1137 << tmpCl[1]
1138 << " 0\n";
1139
1140 tmpCl[0] ^= true;
1141 tmpCl[1] ^= true;
1142
1143 *os
1144 << tmpCl[0] << " "
1145 << tmpCl[1]
1146 << " 0\n";
1147 }
1148 num++;
1149 }
1150 return num;
1151 }
1152
print_some_stats(const double global_cpu_time) const1153 void VarReplacer::print_some_stats(const double global_cpu_time) const
1154 {
1155 print_stats_line("c vrep replace time"
1156 , globalStats.cpu_time
1157 , stats_line_percent(globalStats.cpu_time, global_cpu_time)
1158 , "% time"
1159 );
1160
1161 print_stats_line("c vrep tree roots"
1162 , getNumTrees()
1163 );
1164
1165 print_stats_line("c vrep trees' crown"
1166 , get_num_replaced_vars()
1167 , float_div(get_num_replaced_vars(), getNumTrees())
1168 , "leafs/tree"
1169 );
1170 }
1171
print(const size_t nVars) const1172 void VarReplacer::Stats::print(const size_t nVars) const
1173 {
1174 cout << "c --------- VAR REPLACE STATS ----------" << endl;
1175 print_stats_line("c time"
1176 , cpu_time
1177 , float_div(cpu_time, numCalls)
1178 , "per call"
1179 );
1180
1181 print_stats_line("c trees' crown"
1182 , actuallyReplacedVars
1183 , stats_line_percent(actuallyReplacedVars, nVars)
1184 , "% of vars"
1185 );
1186
1187 print_stats_line("c 0-depth assigns"
1188 , zeroDepthAssigns
1189 , stats_line_percent(zeroDepthAssigns, nVars)
1190 , "% vars"
1191 );
1192
1193 print_stats_line("c lits replaced"
1194 , replacedLits
1195 );
1196
1197 print_stats_line("c bin cls removed"
1198 , removedBinClauses
1199 );
1200
1201 print_stats_line("c long cls removed"
1202 , removedLongClauses
1203 );
1204
1205 print_stats_line("c long lits removed"
1206 , removedLongLits
1207 );
1208
1209 print_stats_line("c bogoprops"
1210 , bogoprops
1211 );
1212 cout << "c --------- VAR REPLACE STATS END ----------" << endl;
1213 }
1214
print_short(const Solver * solver) const1215 void VarReplacer::Stats::print_short(const Solver* solver) const
1216 {
1217 cout
1218 << "c [vrep]"
1219 << " vars " << actuallyReplacedVars
1220 << " lits " << replacedLits
1221 << " rem-bin-cls " << removedBinClauses
1222 << " rem-long-cls " << removedLongClauses
1223 << " BP " << bogoprops/(1000*1000) << "M"
1224 << solver->conf.print_times(cpu_time)
1225 << endl;
1226 }
1227
operator +=(const Stats & other)1228 VarReplacer::Stats& VarReplacer::Stats::operator+=(const Stats& other)
1229 {
1230 numCalls += other.numCalls;
1231 cpu_time += other.cpu_time;
1232 replacedLits += other.replacedLits;
1233 zeroDepthAssigns += other.zeroDepthAssigns;
1234 actuallyReplacedVars += other.actuallyReplacedVars;
1235 removedBinClauses += other.removedBinClauses;
1236 removedLongClauses += other.removedLongClauses;
1237 removedLongLits += other.removedLongLits;
1238 bogoprops += other.bogoprops;
1239
1240 return *this;
1241 }
1242
build_fast_inter_replace_lookup()1243 void VarReplacer::build_fast_inter_replace_lookup()
1244 {
1245 fast_inter_replace_lookup.clear();
1246 fast_inter_replace_lookup.reserve(solver->nVars());
1247 for(uint32_t var = 0; var < solver->nVars(); var++) {
1248 fast_inter_replace_lookup.push_back(get_lit_replaced_with(Lit(var, false)));
1249 }
1250 }
1251
destroy_fast_inter_replace_lookup()1252 void VarReplacer::destroy_fast_inter_replace_lookup()
1253 {
1254 vector<Lit> tmp;
1255 fast_inter_replace_lookup.swap(tmp);
1256 }
1257
get_lit_replaced_with(Lit lit) const1258 Lit VarReplacer::get_lit_replaced_with(Lit lit) const
1259 {
1260 lit = solver->map_inter_to_outer(lit);
1261 Lit lit2 = get_lit_replaced_with_outer(lit);
1262 return solver->map_outer_to_inter(lit2);
1263 }
1264
get_var_replaced_with(uint32_t var) const1265 uint32_t VarReplacer::get_var_replaced_with(uint32_t var) const
1266 {
1267 var = solver->map_inter_to_outer(var);
1268 uint32_t var2 = table[var].var();
1269 return solver->map_outer_to_inter(var2);
1270 }
1271
get_vars_replacing(uint32_t var) const1272 vector<uint32_t> VarReplacer::get_vars_replacing(uint32_t var) const
1273 {
1274 vector<uint32_t> ret;
1275 var = solver->map_inter_to_outer(var);
1276 map<uint32_t, vector<uint32_t> >::const_iterator it = reverseTable.find(var);
1277 if (it != reverseTable.end()) {
1278 for(uint32_t v: it->second) {
1279 ret.push_back(solver->map_outer_to_inter(v));
1280 }
1281 }
1282
1283 return ret;
1284 }
1285
get_all_binary_xors_outer() const1286 vector<pair<Lit, Lit> > VarReplacer::get_all_binary_xors_outer() const
1287 {
1288 vector<pair<Lit, Lit> > ret;
1289 for(size_t i = 0; i < table.size(); i++) {
1290 if (table[i] != Lit(i, false)) {
1291 ret.push_back(std::make_pair(Lit(i, false), table[i]));
1292 }
1293 }
1294
1295 return ret;
1296 }
1297
save_state(SimpleOutFile & f) const1298 void VarReplacer::save_state(SimpleOutFile& f) const
1299 {
1300 f.put_vector(table);
1301 f.put_uint32_t(replacedVars);
1302
1303 f.put_uint32_t(reverseTable.size());
1304 for(auto const& elem: reverseTable) {
1305 f.put_uint32_t(elem.first);
1306 f.put_vector(elem.second);
1307 }
1308 }
load_state(SimpleInFile & f)1309 void VarReplacer::load_state(SimpleInFile& f)
1310 {
1311 f.get_vector(table);
1312 replacedVars = f.get_uint32_t();
1313
1314 vector<uint32_t> point_to;
1315 uint32_t num = f.get_uint32_t();
1316 for(uint32_t i = 0; i < num; i++)
1317 {
1318 uint32_t v = f.get_uint32_t();
1319 point_to.clear();
1320 f.get_vector(point_to);
1321 reverseTable[v] = point_to;
1322 }
1323 }
1324
get_scc_depth_warning_triggered() const1325 bool VarReplacer::get_scc_depth_warning_triggered() const
1326 {
1327 return scc_finder->depth_warning_triggered();
1328 }
1329