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