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