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 #ifndef __CNF_H__
24 #define __CNF_H__
25 
26 #include <atomic>
27 #include <limits>
28 
29 #include "constants.h"
30 #include "vardata.h"
31 #include "propby.h"
32 #include "solverconf.h"
33 #include "solvertypes.h"
34 #include "watcharray.h"
35 #include "drat.h"
36 #include "clauseallocator.h"
37 #include "varupdatehelper.h"
38 #include "simplefile.h"
39 #include "gausswatched.h"
40 #include "xor.h"
41 
42 using std::numeric_limits;
43 
44 namespace CMSat {
45 
46 class ClauseAllocator;
47 
48 struct AssumptionPair {
AssumptionPairAssumptionPair49     AssumptionPair()
50     {}
51 
AssumptionPairAssumptionPair52     AssumptionPair(const Lit _outer, const Lit _outside):
53         lit_outer(_outer)
54         , lit_orig_outside(_outside)
55     {
56     }
57 
58     Lit lit_outer;
59     Lit lit_orig_outside; //not outer, but outside(!)
60 
61     bool operator==(const AssumptionPair& other) const {
62         return other.lit_outer == lit_outer &&
63         other.lit_orig_outside == lit_orig_outside;
64     }
65 
66     bool operator<(const AssumptionPair& other) const
67     {
68         //Yes, we need reverse in terms of inverseness
69         return ~lit_outer < ~other.lit_outer;
70     }
71 };
72 
73 struct BinTriStats
74 {
75     uint64_t irredBins = 0;
76     uint64_t redBins = 0;
77 };
78 
79 struct LitStats
80 {
81     uint64_t irredLits = 0;
82     uint64_t redLits = 0;
83 };
84 
85 class CNF
86 {
87 public:
88     void save_on_var_memory();
89     void updateWatch(watch_subarray ws, const vector<uint32_t>& outerToInter);
90     void updateVars(
91         const vector<uint32_t>& outerToInter
92         , const vector<uint32_t>& interToOuter
93         , const vector<uint32_t>& interToOuter2
94     );
95     size_t mem_used_renumberer() const;
96     size_t mem_used() const;
97 
CNF(const SolverConf * _conf,std::atomic<bool> * _must_interrupt_inter)98     CNF(const SolverConf *_conf, std::atomic<bool>* _must_interrupt_inter)
99     {
100         if (_conf != NULL) {
101             conf = *_conf;
102         }
103         drat = new Drat;
104         assert(_must_interrupt_inter != NULL);
105         must_interrupt_inter = _must_interrupt_inter;
106         longRedCls.resize(3);
107     }
108 
~CNF()109     virtual ~CNF()
110     {
111         delete drat;
112     }
113 
114     ClauseAllocator cl_alloc;
115     SolverConf conf;
116 
117     bool ok = true; //If FALSE, state of CNF is UNSAT
118 
119     watch_array watches;
120     #ifdef USE_GAUSS
121     vec<vec<GaussWatched>> gwatches;
122     uint32_t gqhead;
123     bool all_matrices_disabled = false;
124     #endif
125     uint32_t num_sls_called = 0;
126     vector<VarData> varData;
127     branch branch_strategy = branch::vsids;
128     string branch_strategy_str = "VSIDSX";
129     string branch_strategy_str_short = "vsx";
130     PolarityMode polarity_mode = PolarityMode::polarmode_automatic; //current polarity mode
131     uint32_t polar_stable_longest_trail_this_iter = 0;
132     uint32_t longest_trail_ever = 0;
133     vector<uint32_t> depth; //for ancestors in intree probing
134     uint32_t minNumVars = 0;
135 
136     uint64_t sumConflicts = 0;
137     uint64_t sumDecisions = 0;
138     uint64_t sumAntecedents = 0;
139     uint64_t sumPropagations = 0;
140     uint64_t sumConflictClauseLits = 0;
141     uint64_t sumAntecedentsLits = 0;
142     uint64_t sumDecisionBasedCl = 0;
143     uint64_t sumClLBD = 0;
144     uint64_t sumClSize = 0;
145 
146     uint32_t latest_satzilla_feature_calc = 0;
147     uint64_t last_satzilla_feature_calc_confl = 0;
148     uint32_t latest_vardist_feature_calc = 0;
149     uint64_t last_vardist_feature_calc_confl = 0;
150 
151     unsigned  cur_max_temp_red_lev2_cls = conf.max_temp_lev2_learnt_clauses;
152 
153     //Note that this array can have the same internal variable more than
154     //once, in case one has been replaced with the other. So if var 1 =  var 2
155     //and var 1 was set to TRUE and var 2 to be FALSE, then we'll have var 1
156     //insided this array twice, once it needs to be set to TRUE and once FALSE
157     vector<AssumptionPair> assumptions;
158 
159     //drat
160     Drat* drat;
161     void add_drat(std::ostream* os, bool add_ID);
162 
163     //Clauses
164     vector<ClOffset> longIrredCls;
165 
166     //if the solver object only saw add_clause and new_var(s)
167     bool fresh_solver = true;
168 
169     /**
170     level 0 = never remove
171     level 1 = check rarely
172     level 2 = check often
173     **/
174     vector<vector<ClOffset> > longRedCls;
175     vector<ClOffset> detached_xor_repr_cls; //these are still in longIrredCls
176     vector<Xor> xorclauses;
177     vector<Xor> xorclauses_unused;
178     vector<uint32_t> removed_xorclauses_clash_vars;
179     bool detached_xor_clauses = false;
180     bool xor_clauses_updated = false;
181     BinTriStats binTri;
182     LitStats litStats;
183     int64_t clauseID = 1;
184     int64_t restartID = 1;
185 
186     //Temporaries
187     vector<uint16_t> seen;
188     vector<uint8_t> seen2;
189     vector<uint64_t> permDiff;
190     vector<Lit>      toClear;
191     uint64_t MYFLAG = 1;
192 
okay()193     bool okay() const
194     {
195         return ok;
196     }
197 
value(const uint32_t x)198     lbool value (const uint32_t x) const
199     {
200         return assigns[x];
201     }
202 
value(const Lit p)203     lbool value (const Lit p) const
204     {
205         return assigns[p.var()] ^ p.sign();
206     }
207 
must_interrupt_asap()208     bool must_interrupt_asap() const
209     {
210         std::atomic_thread_fence(std::memory_order_acquire);
211         return *must_interrupt_inter;
212     }
213 
set_must_interrupt_asap()214     void set_must_interrupt_asap()
215     {
216         must_interrupt_inter->store(true, std::memory_order_relaxed);
217     }
218 
unset_must_interrupt_asap()219     void unset_must_interrupt_asap()
220     {
221         must_interrupt_inter->store(false, std::memory_order_relaxed);
222     }
223 
get_must_interrupt_inter_asap_ptr()224     std::atomic<bool>* get_must_interrupt_inter_asap_ptr()
225     {
226         return must_interrupt_inter;
227     }
228 
229     bool clause_locked(const Clause& c, const ClOffset offset) const;
230     void unmark_all_irred_clauses();
231     void unmark_all_red1_clauses();
232 
233     bool redundant(const Watched& ws) const;
234     bool redundant_or_removed(const Watched& ws) const;
235     size_t cl_size(const Watched& ws) const;
236     string watched_to_string(Lit otherLit, const Watched& ws) const;
237     string watches_to_string(const Lit lit, watch_subarray_const ws) const;
238 
239     uint64_t print_mem_used_longclauses(size_t totalMem) const;
240     uint64_t mem_used_longclauses() const;
241     template<class Function>
242     void for_each_lit(
243         const OccurClause& cl
244         ,  Function func
245         , int64_t* limit
246     ) const;
247     template<class Function>
248     void for_each_lit_except_watched(
249         const OccurClause& cl
250         , Function func
251         , int64_t* limit
252     ) const;
map_inter_to_outer(const uint32_t inter)253     uint32_t map_inter_to_outer(const uint32_t inter) const
254     {
255         return interToOuterMain[inter];
256     }
map_inter_to_outer(const Lit lit)257     Lit map_inter_to_outer(const Lit lit) const
258     {
259         return Lit(interToOuterMain[lit.var()], lit.sign());
260     }
map_outer_to_inter(const uint32_t outer)261     uint32_t map_outer_to_inter(const uint32_t outer) const
262     {
263         return outerToInterMain[outer];
264     }
map_outer_to_inter(const Lit outer)265     Lit map_outer_to_inter(const Lit outer) const
266     {
267         return Lit(outerToInterMain[outer.var()], outer.sign());
268     }
map_inter_to_outer(vector<Lit> & lits)269     void map_inter_to_outer(vector<Lit>& lits) const
270     {
271         updateLitsMap(lits, interToOuterMain);
272     }
273     void renumber_outer_to_inter_lits(vector<Lit>& ps) const;
274 
nVarsOutside()275     uint32_t nVarsOutside() const
276     {
277         #ifdef DEBUG_SLOW
278         assert(outer_to_with_bva_map.size() == nVarsOuter() - num_bva_vars);
279         #endif
280         return nVarsOuter() - num_bva_vars;
281     }
282 
map_to_with_bva(const Lit lit)283     Lit map_to_with_bva(const Lit lit) const
284     {
285         return Lit(outer_to_with_bva_map.at(lit.var()), lit.sign());
286     }
287 
map_to_with_bva(const uint32_t var)288     uint32_t map_to_with_bva(const uint32_t var) const
289     {
290         return outer_to_with_bva_map.at(var);
291     }
292 
nVars()293     size_t nVars() const
294     {
295         return minNumVars;
296     }
297 
nVarsOuter()298     size_t nVarsOuter() const
299     {
300         return assigns.size();
301     }
302 
get_num_bva_vars()303     size_t get_num_bva_vars() const
304     {
305         return num_bva_vars;
306     }
307     vector<uint32_t> get_outside_var_incidence();
308     vector<uint32_t> get_outside_var_incidence_also_red();
309 
310     vector<uint32_t> build_outer_to_without_bva_map() const;
311     void clean_occur_from_removed_clauses();
312     void clean_occur_from_removed_clauses_only_smudged();
313     void clean_occur_from_idx_types_only_smudged();
314     void clean_occur_from_idx(const Lit lit);
315     void clear_one_occur_from_removed_clauses(watch_subarray w);
316     bool no_marked_clauses() const;
317     void check_no_removed_or_freed_cl_in_watch() const;
318     bool normClauseIsAttached(const ClOffset offset) const;
319     void find_all_attach() const;
320     void find_all_attach(const vector<ClOffset>& cs) const;
321     bool find_clause(const ClOffset offset) const;
322     void test_all_clause_attached() const;
323     void test_all_clause_attached(const vector<ClOffset>& offsets) const;
324     void check_wrong_attach() const;
325     void check_watchlist(watch_subarray_const ws) const;
326     template<class T>
327     bool satisfied_cl(const T& cl) const;
328     template<typename T> bool no_duplicate_lits(const T& lits) const;
329     void check_no_duplicate_lits_anywhere() const;
330     void print_all_clauses() const;
331     template<class T> void clean_xor_no_prop(T& ps, bool& rhs);
332     template<class T> void clean_xor_vars_no_prop(T& ps, bool& rhs);
333     uint64_t count_lits(
334         const vector<ClOffset>& clause_array
335         , const bool red
336         , const bool allowFreed
337     ) const;
338 
339 protected:
340     virtual void new_var(const bool bva, const uint32_t orig_outer);
341     virtual void new_vars(const size_t n);
342     void test_reflectivity_of_renumbering() const;
343 
344     template<class T>
345     vector<T> map_back_vars_to_without_bva(const vector<T>& val) const;
346     vector<lbool> assigns;
347 
348     void save_state(SimpleOutFile& f) const;
349     void load_state(SimpleInFile& f);
350     vector<uint32_t> outerToInterMain;
351     vector<uint32_t> interToOuterMain;
352 
353 private:
354     std::atomic<bool> *must_interrupt_inter; ///<Interrupt cleanly ASAP if true
355     void enlarge_minimal_datastructs(size_t n = 1);
356     void enlarge_nonminimial_datastructs(size_t n = 1);
357     void swapVars(const uint32_t which, const int off_by = 0);
358 
359     size_t num_bva_vars = 0;
360     vector<uint32_t> outer_to_with_bva_map;
361 };
362 
363 template<class Function>
for_each_lit(const OccurClause & cl,Function func,int64_t * limit)364 void CNF::for_each_lit(
365     const OccurClause& cl
366     ,  Function func
367     , int64_t* limit
368 ) const {
369     switch(cl.ws.getType()) {
370         case CMSat::watch_binary_t:
371             *limit -= 2;
372             func(cl.lit);
373             func(cl.ws.lit2());
374             break;
375 
376         case CMSat::watch_clause_t: {
377             const Clause& clause = *cl_alloc.ptr(cl.ws.get_offset());
378             *limit -= (int64_t)clause.size();
379             for(const Lit lit: clause) {
380                 func(lit);
381             }
382             break;
383         }
384 
385         case watch_idx_t :
386             assert(false);
387             break;
388     }
389 }
390 
391 template<class Function>
for_each_lit_except_watched(const OccurClause & cl,Function func,int64_t * limit)392 void CNF::for_each_lit_except_watched(
393     const OccurClause& cl
394     , Function func
395     , int64_t* limit
396 ) const {
397     switch(cl.ws.getType()) {
398         case CMSat::watch_binary_t:
399             *limit -= 1;
400             func(cl.ws.lit2());
401             break;
402 
403         case CMSat::watch_clause_t: {
404             const Clause& clause = *cl_alloc.ptr(cl.ws.get_offset());
405             *limit -= clause.size();
406             for(const Lit lit: clause) {
407                 if (lit != cl.lit) {
408                     func(lit);
409                 }
410             }
411             break;
412         }
413 
414         case CMSat::watch_idx_t:
415             assert(false);
416             break;
417     }
418 }
419 
420 struct ClauseSizeSorter
421 {
ClauseSizeSorterClauseSizeSorter422     explicit ClauseSizeSorter(const ClauseAllocator& _cl_alloc) :
423         cl_alloc(_cl_alloc)
424     {}
425     bool operator () (const ClOffset x, const ClOffset y);
426     const ClauseAllocator& cl_alloc;
427 };
428 
redundant(const Watched & ws)429 inline bool CNF::redundant(const Watched& ws) const
430 {
431     return (   (ws.isBin() && ws.red())
432             || (ws.isClause() && cl_alloc.ptr(ws.get_offset())->red())
433     );
434 }
435 
redundant_or_removed(const Watched & ws)436 inline bool CNF::redundant_or_removed(const Watched& ws) const
437 {
438     if (ws.isBin()) {
439         return ws.red();
440     }
441 
442    assert(ws.isClause());
443    const Clause* cl = cl_alloc.ptr(ws.get_offset());
444    return cl->red() || cl->getRemoved();
445 }
446 
clean_occur_from_removed_clauses()447 inline void CNF::clean_occur_from_removed_clauses()
448 {
449     for(watch_subarray w: watches) {
450         clear_one_occur_from_removed_clauses(w);
451     }
452 }
453 
clean_occur_from_removed_clauses_only_smudged()454 inline void CNF::clean_occur_from_removed_clauses_only_smudged()
455 {
456     for(const Lit l: watches.get_smudged_list()) {
457         clear_one_occur_from_removed_clauses(watches[l]);
458     }
459     watches.clear_smudged();
460 }
461 
clean_occur_from_idx_types_only_smudged()462 inline void CNF::clean_occur_from_idx_types_only_smudged()
463 {
464     for(const Lit lit: watches.get_smudged_list()) {
465         clean_occur_from_idx(lit);
466     }
467     watches.clear_smudged();
468 }
469 
clean_occur_from_idx(const Lit lit)470 inline void CNF::clean_occur_from_idx(const Lit lit)
471 {
472     watch_subarray ws = watches[lit];
473     Watched* i = ws.begin();
474     Watched* j = ws.begin();
475     for(const Watched* end = ws.end(); i < end; i++) {
476         if (!i->isIdx()) {
477             *j++ = *i;
478         }
479     }
480     ws.shrink(i-j);
481 }
482 
clause_locked(const Clause & c,const ClOffset offset)483 inline bool CNF::clause_locked(const Clause& c, const ClOffset offset) const
484 {
485     return value(c[0]) == l_True
486         && varData[c[0].var()].reason.isClause()
487         && varData[c[0].var()].reason.get_offset() == offset;
488 }
489 
clear_one_occur_from_removed_clauses(watch_subarray w)490 inline void CNF::clear_one_occur_from_removed_clauses(watch_subarray w)
491 {
492     size_t i = 0;
493     size_t j = 0;
494     size_t end = w.size();
495     for(; i < end; i++) {
496         const Watched ws = w[i];
497         if (!ws.isClause()) {
498             w[j++] = w[i];
499             continue;
500         }
501 
502         Clause* cl = cl_alloc.ptr(ws.get_offset());
503         if (!cl->getRemoved()) {
504             w[j++] = w[i];
505         }
506     }
507     w.shrink(i-j);
508 }
509 
unmark_all_irred_clauses()510 inline void CNF::unmark_all_irred_clauses()
511 {
512     for(ClOffset offset: longIrredCls) {
513         Clause* cl = cl_alloc.ptr(offset);
514         cl->stats.marked_clause = false;
515     }
516 }
517 
unmark_all_red1_clauses()518 inline void CNF::unmark_all_red1_clauses()
519 {
520     for(ClOffset offset: longRedCls[1]) {
521         Clause* cl = cl_alloc.ptr(offset);
522         cl->stats.marked_clause = false;
523     }
524 }
525 
renumber_outer_to_inter_lits(vector<Lit> & ps)526 inline void CNF::renumber_outer_to_inter_lits(vector<Lit>& ps) const
527 {
528     for (Lit& lit: ps) {
529         const Lit origLit = lit;
530 
531         //Update variable numbering
532         assert(lit.var() < nVarsOuter());
533         lit = map_outer_to_inter(lit);
534 
535         if (conf.verbosity >= 52) {
536             cout
537             << "var-renumber updating lit "
538             << origLit
539             << " to lit "
540             << lit
541             << endl;
542         }
543     }
544 }
545 
546 template<typename T>
unsign_lits(const T & lits)547 inline vector<Lit> unsign_lits(const T& lits)
548 {
549     vector<Lit> ret(lits.size());
550     for(size_t i = 0; i < lits.size(); i++) {
551         ret[i] = lits[i].unsign();
552     }
553     return ret;
554 }
555 
check_no_removed_or_freed_cl_in_watch()556 inline void CNF::check_no_removed_or_freed_cl_in_watch() const
557 {
558     for(watch_subarray_const ws: watches) {
559         for(const Watched& w: ws) {
560             assert(!w.isIdx());
561             if (w.isBin()) {
562                 continue;
563             }
564             assert(w.isClause());
565             Clause& cl = *cl_alloc.ptr(w.get_offset());
566             assert(!cl.getRemoved());
567             assert(!cl.freed());
568         }
569     }
570 }
571 
572 template<class T>
satisfied_cl(const T & cl)573 bool CNF::satisfied_cl(const T& cl) const {
574     for(Lit lit: cl) {
575         if (value(lit) == l_True) {
576             return true;
577         }
578     }
579     return false;
580 }
581 
582 
583 template<typename T>
no_duplicate_lits(const T & lits)584 bool CNF::no_duplicate_lits(const T& lits) const
585 {
586     vector<Lit> x(lits.size());
587     for(size_t i = 0; i < x.size(); i++) {
588         x[i] = lits[i];
589     }
590     std::sort(x.begin(), x.end());
591     for(size_t i = 1; i < x.size(); i++) {
592         if (x[i-1] == x[i])
593             return false;
594     }
595     return true;
596 }
597 
check_no_duplicate_lits_anywhere()598 inline void CNF::check_no_duplicate_lits_anywhere() const
599 {
600     for(const ClOffset offs: longIrredCls) {
601         Clause * cl = cl_alloc.ptr(offs);
602         assert(no_duplicate_lits((*cl)));
603     }
604     for(const auto& l: longRedCls) {
605         for(const ClOffset offs: l) {
606             Clause * cl = cl_alloc.ptr(offs);
607             assert(no_duplicate_lits((*cl)));
608         }
609     }
610 }
611 
612 template<class T>
clean_xor_no_prop(T & ps,bool & rhs)613 void CNF::clean_xor_no_prop(T& ps, bool& rhs)
614 {
615     std::sort(ps.begin(), ps.end());
616     Lit p;
617     uint32_t i, j;
618     for (i = j = 0, p = lit_Undef; i != ps.size(); i++) {
619         assert(ps[i].sign() == false);
620 
621         if (ps[i].var() == p.var()) {
622             //added, but easily removed
623             j--;
624             p = lit_Undef;
625 
626             //Flip rhs if neccessary
627             if (value(ps[i]) != l_Undef) {
628                 rhs ^= value(ps[i]) == l_True;
629             }
630 
631         } else if (value(ps[i]) == l_Undef) {
632             //Add and remember as last one to have been added
633             ps[j++] = p = ps[i];
634 
635             assert(varData[p.var()].removed != Removed::elimed);
636         } else {
637             //modify rhs instead of adding
638             rhs ^= value(ps[i]) == l_True;
639         }
640     }
641     ps.resize(ps.size() - (i - j));
642 }
643 
644 template<class T>
clean_xor_vars_no_prop(T & ps,bool & rhs)645 void CNF::clean_xor_vars_no_prop(T& ps, bool& rhs)
646 {
647     std::sort(ps.begin(), ps.end());
648     uint32_t p;
649     uint32_t i, j;
650     for (i = j = 0, p = numeric_limits<uint32_t>::max(); i != ps.size(); i++) {
651         if (ps[i] == p) {
652             //added, but easily removed
653             j--;
654             p = numeric_limits<uint32_t>::max();
655 
656             //Flip rhs if neccessary
657             if (value(ps[i]) != l_Undef) {
658                 rhs ^= value(ps[i]) == l_True;
659             }
660 
661         } else if (value(ps[i]) == l_Undef) {
662             //Add and remember as last one to have been added
663             ps[j++] = p = ps[i];
664 
665             assert(varData[p].removed != Removed::elimed);
666         } else {
667             //modify rhs instead of adding
668             rhs ^= value(ps[i]) == l_True;
669         }
670     }
671     ps.resize(ps.size() - (i - j));
672 }
673 
674 template<class T>
map_back_vars_to_without_bva(const vector<T> & val)675 vector<T> CNF::map_back_vars_to_without_bva(const vector<T>& val) const
676 {
677     vector<T> ret;
678     assert(val.size() == nVarsOuter());
679     ret.reserve(nVarsOutside());
680     for(size_t i = 0; i < nVarsOuter(); i++) {
681         if (!varData[map_outer_to_inter(i)].is_bva) {
682             ret.push_back(val[i]);
683         }
684     }
685     assert(ret.size() == nVarsOutside());
686     return ret;
687 }
688 
689 }
690 
691 #endif //__CNF_H__
692