1 /*++
2 Copyright (c) 2011 Microsoft Corporation
3 
4 Module Name:
5 
6     sat_solver.cpp
7 
8 Abstract:
9 
10     SAT solver main class.
11 
12 Author:
13 
14     Leonardo de Moura (leonardo) 2011-05-21.
15 
16 Revision History:
17 
18 --*/
19 
20 
21 #include <cmath>
22 #ifndef SINGLE_THREAD
23 #include <thread>
24 #endif
25 #include "util/luby.h"
26 #include "util/trace.h"
27 #include "util/max_cliques.h"
28 #include "util/gparams.h"
29 #include "sat/sat_solver.h"
30 #include "sat/sat_integrity_checker.h"
31 #include "sat/sat_lookahead.h"
32 #include "sat/sat_ddfw.h"
33 #include "sat/sat_prob.h"
34 #include "sat/sat_anf_simplifier.h"
35 #include "sat/sat_cut_simplifier.h"
36 #if defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64)
37 # include <xmmintrin.h>
38 #endif
39 
40 #define ENABLE_TERNARY true
41 
42 namespace sat {
43 
44 
solver(params_ref const & p,reslimit & l)45     solver::solver(params_ref const & p, reslimit& l):
46         solver_core(l),
47         m_checkpoint_enabled(true),
48         m_config(p),
49         m_par(nullptr),
50         m_drat(*this),
51         m_cls_allocator_idx(false),
52         m_cleaner(*this),
53         m_simplifier(*this, p),
54         m_scc(*this, p),
55         m_asymm_branch(*this, p),
56         m_probing(*this, p),
57         m_mus(*this),
58         m_binspr(*this),
59         m_inconsistent(false),
60         m_searching(false),
61         m_conflict(justification(0)),
62         m_num_frozen(0),
63         m_activity_inc(128),
64         m_case_split_queue(m_activity),
65         m_qhead(0),
66         m_scope_lvl(0),
67         m_search_lvl(0),
68         m_fast_glue_avg(),
69         m_slow_glue_avg(),
70         m_fast_glue_backup(),
71         m_slow_glue_backup(),
72         m_trail_avg(),
73         m_params(p),
74         m_par_id(0),
75         m_par_syncing_clauses(false) {
76         init_reason_unknown();
77         updt_params(p);
78         m_best_phase_size         = 0;
79         m_conflicts_since_gc      = 0;
80         m_conflicts_since_init    = 0;
81         m_next_simplify           = 0;
82         m_num_checkpoints         = 0;
83         m_simplifications         = 0;
84         m_touch_index             = 0;
85         m_ext                     = nullptr;
86         m_cuber                   = nullptr;
87         m_local_search            = nullptr;
88         m_mc.set_solver(this);
89         mk_var(false, false);
90     }
91 
~solver()92     solver::~solver() {
93         m_ext = nullptr;
94         SASSERT(m_config.m_num_threads > 1 || check_invariant());
95         CTRACE("sat", !m_clauses.empty(), tout << "Delete clauses\n";);
96         del_clauses(m_clauses);
97         CTRACE("sat", !m_learned.empty(), tout << "Delete learned\n";);
98         del_clauses(m_learned);
99         dealloc(m_cuber);
100         m_cuber = nullptr;
101     }
102 
del_clauses(clause_vector & clauses)103     void solver::del_clauses(clause_vector& clauses) {
104         for (clause * cp : clauses)
105             dealloc_clause(cp);
106         clauses.reset();
107         ++m_stats.m_non_learned_generation;
108     }
109 
set_extension(extension * ext)110     void solver::set_extension(extension* ext) {
111         m_ext = ext;
112         if (ext) {
113             ext->set_solver(this);
114             for (unsigned i = num_user_scopes(); i-- > 0;)
115                 ext->user_push();
116             for (unsigned i = num_scopes(); i-- > 0;)
117                 ext->push();
118         }
119     }
120 
copy(solver const & src,bool copy_learned)121     void solver::copy(solver const & src, bool copy_learned) {
122         pop_to_base_level();
123         del_clauses(m_clauses);
124         del_clauses(m_learned);
125         m_watches.reset();
126         m_assignment.reset();
127         m_justification.reset();
128         m_decision.reset();
129         m_eliminated.reset();
130         m_external.reset();
131         m_var_scope.reset();
132         m_activity.reset();
133         m_mark.reset();
134         m_lit_mark.reset();
135         m_best_phase.reset();
136         m_phase.reset();
137         m_prev_phase.reset();
138         m_assigned_since_gc.reset();
139         m_last_conflict.reset();
140         m_last_propagation.reset();
141         m_participated.reset();
142         m_canceled.reset();
143         m_reasoned.reset();
144         m_case_split_queue.reset();
145         m_simplifier.reset_todos();
146         m_qhead = 0;
147         m_trail.reset();
148         m_scopes.reset();
149         mk_var(false, false);
150 
151         if (src.inconsistent()) {
152             set_conflict();
153             return;
154         }
155 
156         // create new vars
157         for (bool_var v = num_vars(); v < src.num_vars(); v++) {
158             bool ext  = src.m_external[v];
159             bool dvar = src.m_decision[v];
160             VERIFY(v == mk_var(ext, dvar));
161             if (src.was_eliminated(v)) {
162                 set_eliminated(v, true);
163             }
164             m_phase[v] = src.m_phase[v];
165             m_best_phase[v] = src.m_best_phase[v];
166             m_prev_phase[v] = src.m_prev_phase[v];
167 
168             // inherit activity:
169             m_activity[v] = src.m_activity[v];
170             m_case_split_queue.activity_changed_eh(v, false);
171         }
172 
173         //
174         // register the extension before performing assignments.
175         // the assignments may call back into the extension.
176         //
177         if (src.get_extension()) {
178             m_ext = src.get_extension()->copy(this);
179         }
180 
181         unsigned trail_sz = src.init_trail_size();
182         for (unsigned i = 0; i < trail_sz; ++i) {
183             assign_unit(src.m_trail[i]);
184         }
185 
186         // copy binary clauses
187         {
188             unsigned sz = src.m_watches.size();
189             for (unsigned l_idx = 0; l_idx < sz; ++l_idx) {
190                 literal l = ~to_literal(l_idx);
191                 if (src.was_eliminated(l.var())) continue;
192                 watch_list const & wlist = src.m_watches[l_idx];
193                 for (auto & wi : wlist) {
194                     if (!wi.is_binary_clause())
195                         continue;
196                     literal l2 = wi.get_literal();
197                     if (l.index() > l2.index() ||
198                         src.was_eliminated(l2.var()))
199                         continue;
200 
201                     watched w1(l2, wi.is_learned());
202                     watched w2(l, wi.is_learned());
203                     m_watches[(~l).index()].push_back(w1);
204                     m_watches[(~l2).index()].push_back(w2);
205                 }
206             }
207         }
208 
209         {
210             literal_vector buffer;
211             // copy clauses
212             for (clause* c : src.m_clauses) {
213                 buffer.reset();
214                 for (literal l : *c) buffer.push_back(l);
215                 mk_clause_core(buffer);
216             }
217 
218             // copy high quality lemmas
219             unsigned num_learned = 0;
220             for (clause* c : src.m_learned) {
221                 if (c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8) || copy_learned) {
222                     buffer.reset();
223                     for (literal l : *c) buffer.push_back(l);
224                     clause* c1 = mk_clause_core(buffer.size(), buffer.data(), sat::status::redundant());
225                     if (c1) {
226                         ++num_learned;
227                         c1->set_glue(c->glue());
228                         c1->set_psm(c->psm());
229                     }
230                 }
231             }
232             IF_VERBOSE(2, verbose_stream() << "(sat.copy :learned " << num_learned << ")\n";);
233         }
234         m_best_phase_size = src.m_best_phase_size;
235         if (m_best_phase_size > 0) {
236             for (bool_var v = 0; v < num_vars(); ++v) {
237                 m_best_phase[v] = src.m_best_phase[v];
238             }
239         }
240 
241         m_user_scope_literals.reset();
242         m_user_scope_literals.append(src.m_user_scope_literals);
243 
244         m_mc = src.m_mc;
245         m_stats.m_units = init_trail_size();
246     }
247 
248     // -----------------------
249     //
250     // Variable & Clause creation
251     //
252     // -----------------------
253 
reset_var(bool_var v,bool ext,bool dvar)254     void solver::reset_var(bool_var v, bool ext, bool dvar) {
255         m_watches[2*v].reset();
256         m_watches[2*v+1].reset();
257         m_assignment[2*v] = l_undef;
258         m_assignment[2*v+1] = l_undef;
259         m_justification[v] = justification(UINT_MAX);
260         m_decision[v] = dvar;
261         m_eliminated[v] = false;
262         m_external[v] = ext;
263         m_var_scope[v] = scope_lvl();
264         m_touched[v] = 0;
265         m_activity[v] = 0;
266         m_mark[v] = false;
267         m_lit_mark[2*v] = false;
268         m_lit_mark[2*v+1] = false;
269         m_phase[v] = false;
270         m_best_phase[v] = false;
271         m_prev_phase[v] = false;
272         m_assigned_since_gc[v] = false;
273         m_last_conflict[v] = 0;
274         m_last_propagation[v] = 0;
275         m_participated[v] = 0;
276         m_canceled[v] = 0;
277         m_reasoned[v] = 0;
278         m_case_split_queue.mk_var_eh(v);
279         m_simplifier.insert_elim_todo(v);
280     }
281 
mk_var(bool ext,bool dvar)282     bool_var solver::mk_var(bool ext, bool dvar) {
283         m_model_is_current = false;
284         m_stats.m_mk_var++;
285         bool_var v = m_justification.size();
286         if (!m_free_vars.empty()) {
287             v = m_free_vars.back();
288             m_free_vars.pop_back();
289             m_active_vars.push_back(v);
290             reset_var(v, ext, dvar);
291             return v;
292         }
293         m_active_vars.push_back(v);
294         m_watches.push_back(watch_list());
295         m_watches.push_back(watch_list());
296         m_assignment.push_back(l_undef);
297         m_assignment.push_back(l_undef);
298         m_justification.push_back(justification(UINT_MAX));
299         m_decision.push_back(dvar);
300         m_eliminated.push_back(false);
301         m_external.push_back(ext);
302         m_var_scope.push_back(scope_lvl());
303         m_touched.push_back(0);
304         m_activity.push_back(0);
305         m_mark.push_back(false);
306         m_lit_mark.push_back(false);
307         m_lit_mark.push_back(false);
308         m_phase.push_back(false);
309         m_best_phase.push_back(false);
310         m_prev_phase.push_back(false);
311         m_assigned_since_gc.push_back(false);
312         m_last_conflict.push_back(0);
313         m_last_propagation.push_back(0);
314         m_participated.push_back(0);
315         m_canceled.push_back(0);
316         m_reasoned.push_back(0);
317         m_case_split_queue.mk_var_eh(v);
318         m_simplifier.insert_elim_todo(v);
319         SASSERT(!was_eliminated(v));
320         return v;
321     }
322 
set_non_external(bool_var v)323     void solver::set_non_external(bool_var v) {
324         m_external[v] = false;
325     }
326 
set_external(bool_var v)327     void solver::set_external(bool_var v) {
328         m_external[v] = true;
329     }
330 
set_eliminated(bool_var v,bool f)331     void solver::set_eliminated(bool_var v, bool f) {
332         if (m_eliminated[v] == f)
333             return;
334         if (!f)
335             reset_var(v, m_external[v], m_decision[v]);
336         else if (f && m_ext)
337             m_ext->set_eliminated(v);
338         m_eliminated[v] = f;
339     }
340 
341 
mk_clause(unsigned num_lits,literal * lits,sat::status st)342     clause* solver::mk_clause(unsigned num_lits, literal * lits, sat::status st) {
343         m_model_is_current = false;
344 
345         for (unsigned i = 0; i < num_lits; i++)
346             VERIFY(!was_eliminated(lits[i]));
347 
348         DEBUG_CODE({
349                 for (unsigned i = 0; i < num_lits; i++) {
350                     CTRACE("sat", was_eliminated(lits[i]), tout << lits[i] << " was eliminated\n";);
351                     SASSERT(!was_eliminated(lits[i]));
352                 }
353         });
354 
355         if (m_user_scope_literals.empty()) {
356             return mk_clause_core(num_lits, lits, st);
357         }
358         else {
359             m_aux_literals.reset();
360             m_aux_literals.append(num_lits, lits);
361             m_aux_literals.append(m_user_scope_literals);
362             return mk_clause_core(m_aux_literals.size(), m_aux_literals.data(), st);
363         }
364     }
365 
mk_clause(literal l1,literal l2,sat::status st)366     clause* solver::mk_clause(literal l1, literal l2, sat::status st) {
367         literal ls[2] = { l1, l2 };
368         return mk_clause(2, ls, st);
369     }
370 
mk_clause(literal l1,literal l2,literal l3,sat::status st)371     clause* solver::mk_clause(literal l1, literal l2, literal l3, sat::status st) {
372         literal ls[3] = { l1, l2, l3 };
373         return mk_clause(3, ls, st);
374     }
375 
del_clause(clause & c)376     void solver::del_clause(clause& c) {
377         if (!c.is_learned()) {
378             m_stats.m_non_learned_generation++;
379         }
380         if (c.frozen()) {
381             --m_num_frozen;
382         }
383         if (!c.was_removed() && m_config.m_drat && !m_drat.is_cleaned(c)) {
384             m_drat.del(c);
385         }
386         dealloc_clause(&c);
387         if (m_searching)
388             m_stats.m_del_clause++;
389     }
390 
drat_explain_conflict()391     void solver::drat_explain_conflict() {
392         if (m_config.m_drat && m_ext) {
393             extension::scoped_drating _sd(*m_ext);
394             bool unique_max;
395             m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max);
396             resolve_conflict_for_unsat_core();
397         }
398     }
399 
drat_log_unit(literal lit,justification j)400     void solver::drat_log_unit(literal lit, justification j) {
401         if (!m_ext)
402             return;
403         extension::scoped_drating _sd(*m_ext.get());
404         if (j.get_kind() == justification::EXT_JUSTIFICATION)
405             fill_ext_antecedents(lit, j, false);
406         m_drat.add(lit, m_searching);
407     }
408 
drat_log_clause(unsigned num_lits,literal const * lits,sat::status st)409     void solver::drat_log_clause(unsigned num_lits, literal const* lits, sat::status st) {
410         m_drat.add(num_lits, lits, st);
411     }
412 
mk_clause_core(unsigned num_lits,literal * lits,sat::status st)413     clause * solver::mk_clause_core(unsigned num_lits, literal * lits, sat::status st) {
414         bool redundant = st.is_redundant();
415         TRACE("sat", tout << "mk_clause: "  << mk_lits_pp(num_lits, lits) << (redundant?" learned":" aux") << "\n";);
416         if (!redundant || !st.is_sat()) {
417             unsigned old_sz = num_lits;
418             bool keep = simplify_clause(num_lits, lits);
419             TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";);
420             if (!keep) {
421                 return nullptr; // clause is equivalent to true.
422             }
423             // if an input clause is simplified, then log the simplified version as learned
424             if (m_config.m_drat && old_sz > num_lits)
425                 drat_log_clause(num_lits, lits, st);
426 
427             ++m_stats.m_non_learned_generation;
428             if (!m_searching) {
429                 m_mc.add_clause(num_lits, lits);
430             }
431         }
432 
433 
434         switch (num_lits) {
435         case 0:
436             set_conflict();
437             return nullptr;
438         case 1:
439             if (m_config.m_drat && (!st.is_sat() || st.is_input()))
440                 drat_log_clause(num_lits, lits, st);
441             assign_unit(lits[0]);
442             return nullptr;
443         case 2:
444             mk_bin_clause(lits[0], lits[1], st);
445             if (redundant && m_par)
446                 m_par->share_clause(*this, lits[0], lits[1]);
447             return nullptr;
448         case 3:
449             if (ENABLE_TERNARY)
450                 return mk_ter_clause(lits, st);
451             Z3_fallthrough;
452         default:
453             return mk_nary_clause(num_lits, lits, st);
454         }
455     }
456 
mk_bin_clause(literal l1,literal l2,sat::status st)457     void solver::mk_bin_clause(literal l1, literal l2, sat::status st) {
458         bool redundant = st.is_redundant();
459         m_touched[l1.var()] = m_touch_index;
460         m_touched[l2.var()] = m_touch_index;
461 
462         if (redundant && find_binary_watch(get_wlist(~l1), ~l2) && value(l1) == l_undef) {
463             assign_unit(l1);
464             return;
465         }
466         if (redundant && find_binary_watch(get_wlist(~l2), ~l1) && value(l2) == l_undef) {
467             assign_unit(l2);
468             return;
469         }
470         watched* w0 = redundant ? find_binary_watch(get_wlist(~l1), l2) : nullptr;
471         if (w0) {
472             TRACE("sat", tout << "found binary " << l1 << " " << l2 << "\n";);
473             if (w0->is_learned() && !redundant) {
474                 w0->set_learned(false);
475                 w0 = find_binary_watch(get_wlist(~l2), l1);
476                 VERIFY(w0);
477                 w0->set_learned(false);
478             }
479             if (propagate_bin_clause(l1, l2) && !at_base_lvl() && !redundant)
480                 push_reinit_stack(l1, l2);
481             else if (has_variables_to_reinit(l1, l2))
482                 push_reinit_stack(l1, l2);
483             return;
484         }
485         if (m_config.m_drat)
486             m_drat.add(l1, l2, st);
487         if (propagate_bin_clause(l1, l2)) {
488             if (at_base_lvl())
489                 return;
490             push_reinit_stack(l1, l2);
491         }
492         else if (has_variables_to_reinit(l1, l2))
493             push_reinit_stack(l1, l2);
494         m_stats.m_mk_bin_clause++;
495         get_wlist(~l1).push_back(watched(l2, redundant));
496         get_wlist(~l2).push_back(watched(l1, redundant));
497     }
498 
has_variables_to_reinit(clause const & c) const499     bool solver::has_variables_to_reinit(clause const& c) const {
500         for (auto lit : c)
501             if (m_var_scope[lit.var()] > 0)
502                 return true;
503         return false;
504     }
505 
has_variables_to_reinit(literal l1,literal l2) const506     bool solver::has_variables_to_reinit(literal l1, literal l2) const {
507         if (at_base_lvl())
508             return false;
509         if (m_var_scope[l1.var()] > 0)
510             return true;
511         if (m_var_scope[l2.var()] > 0)
512             return true;
513         return false;
514     }
515 
propagate_bin_clause(literal l1,literal l2)516     bool solver::propagate_bin_clause(literal l1, literal l2) {
517         if (value(l2) == l_false) {
518             m_stats.m_bin_propagate++;
519             assign(l1, justification(lvl(l2), l2));
520             return true;
521         }
522         if (value(l1) == l_false) {
523             m_stats.m_bin_propagate++;
524             assign(l2, justification(lvl(l1), l1));
525             return true;
526         }
527         return false;
528     }
529 
push_reinit_stack(clause & c)530     void solver::push_reinit_stack(clause & c) {
531         SASSERT(!at_base_lvl());
532         TRACE("sat_reinit", tout << "adding to reinit stack: " << c << "\n";);
533         m_clauses_to_reinit.push_back(clause_wrapper(c));
534         c.set_reinit_stack(true);
535     }
536 
push_reinit_stack(literal l1,literal l2)537     void solver::push_reinit_stack(literal l1, literal l2) {
538         TRACE("sat_reinit", tout << "adding to reinit stack: " << l1 << " " << l2 << "\n";);
539         m_clauses_to_reinit.push_back(clause_wrapper(l1, l2));
540     }
541 
mk_ter_clause(literal * lits,sat::status st)542     clause * solver::mk_ter_clause(literal * lits, sat::status st) {
543         VERIFY(ENABLE_TERNARY);
544         m_stats.m_mk_ter_clause++;
545         clause * r = alloc_clause(3, lits, st.is_redundant());
546         bool reinit = attach_ter_clause(*r, st);
547         if (reinit || has_variables_to_reinit(*r)) push_reinit_stack(*r);
548         if (st.is_redundant())
549             m_learned.push_back(r);
550         else
551             m_clauses.push_back(r);
552         for (literal l : *r) {
553             m_touched[l.var()] = m_touch_index;
554         }
555         return r;
556     }
557 
attach_ter_clause(clause & c,sat::status st)558     bool solver::attach_ter_clause(clause & c, sat::status st) {
559         VERIFY(ENABLE_TERNARY);
560         bool reinit = false;
561         if (m_config.m_drat) m_drat.add(c, st);
562         TRACE("sat_verbose", tout << c << "\n";);
563         SASSERT(!c.was_removed());
564         m_watches[(~c[0]).index()].push_back(watched(c[1], c[2]));
565         m_watches[(~c[1]).index()].push_back(watched(c[0], c[2]));
566         m_watches[(~c[2]).index()].push_back(watched(c[0], c[1]));
567         if (!at_base_lvl())
568             reinit = propagate_ter_clause(c);
569         return reinit;
570     }
571 
propagate_ter_clause(clause & c)572     bool solver::propagate_ter_clause(clause& c) {
573         bool reinit = false;
574         if (value(c[1]) == l_false && value(c[2]) == l_false) {
575             m_stats.m_ter_propagate++;
576             assign(c[0], justification(std::max(lvl(c[1]), lvl(c[2])), c[1], c[2]));
577             reinit = !c.is_learned();
578         }
579         else if (value(c[0]) == l_false && value(c[2]) == l_false) {
580             m_stats.m_ter_propagate++;
581             assign(c[1], justification(std::max(lvl(c[0]), lvl(c[2])), c[0], c[2]));
582             reinit = !c.is_learned();
583         }
584         else if (value(c[0]) == l_false && value(c[1]) == l_false) {
585             m_stats.m_ter_propagate++;
586             assign(c[2], justification(std::max(lvl(c[0]), lvl(c[1])), c[0], c[1]));
587             reinit = !c.is_learned();
588         }
589         return reinit;
590     }
591 
mk_nary_clause(unsigned num_lits,literal * lits,sat::status st)592     clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, sat::status st) {
593         m_stats.m_mk_clause++;
594         clause * r = alloc_clause(num_lits, lits, st.is_redundant());
595         SASSERT(!st.is_redundant() || r->is_learned());
596         bool reinit = attach_nary_clause(*r, st.is_sat() && st.is_redundant());
597         if (reinit || has_variables_to_reinit(*r)) push_reinit_stack(*r);
598         if (st.is_redundant()) {
599             m_learned.push_back(r);
600         }
601         else {
602             m_clauses.push_back(r);
603         }
604         if (m_config.m_drat) {
605             m_drat.add(*r, st);
606         }
607         for (literal l : *r) {
608             m_touched[l.var()] = m_touch_index;
609         }
610         return r;
611     }
612 
attach_nary_clause(clause & c,bool is_asserting)613     bool solver::attach_nary_clause(clause & c, bool is_asserting) {
614         bool reinit = false;
615         clause_offset cls_off = cls_allocator().get_offset(&c);
616         if (!at_base_lvl()) {
617             if (is_asserting) {
618                 unsigned w2_idx = select_learned_watch_lit(c);
619                 std::swap(c[1], c[w2_idx]);
620             }
621             else {
622                 unsigned w1_idx = select_watch_lit(c, 0);
623                 std::swap(c[0], c[w1_idx]);
624                 unsigned w2_idx = select_watch_lit(c, 1);
625                 std::swap(c[1], c[w2_idx]);
626             }
627 
628             if (value(c[0]) == l_false) {
629                 m_stats.m_propagate++;
630                 unsigned level = lvl(c[0]);
631                 for (unsigned i = c.size(); i-- > 2; ) {
632                     level = std::max(level, lvl(c[i]));
633                 }
634                 assign(c[1], justification(level, cls_off));
635                 reinit |= !c.is_learned();
636             }
637             else if (value(c[1]) == l_false) {
638                 m_stats.m_propagate++;
639                 unsigned level = lvl(c[1]);
640                 for (unsigned i = c.size(); i-- > 2; ) {
641                     level = std::max(level, lvl(c[i]));
642                 }
643                 assign(c[0], justification(level, cls_off));
644                 reinit |= !c.is_learned();
645             }
646         }
647         unsigned some_idx = c.size() >> 1;
648         literal block_lit = c[some_idx];
649         VERIFY(!c.frozen());
650         DEBUG_CODE(for (auto const& w : m_watches[(~c[0]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off););
651         DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off););
652         SASSERT(c[0] != c[1]);
653         m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off));
654         m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off));
655         return reinit;
656     }
657 
attach_clause(clause & c,bool & reinit)658     void solver::attach_clause(clause & c, bool & reinit) {
659         SASSERT(c.size() > 2);
660         reinit = false;
661         if (ENABLE_TERNARY && c.size() == 3)
662             reinit = attach_ter_clause(c, c.is_learned() ? sat::status::redundant() : sat::status::asserted());
663         else
664             reinit = attach_nary_clause(c, c.is_learned() && !c.on_reinit_stack());
665     }
666 
set_learned(clause & c,bool redundant)667     void solver::set_learned(clause& c, bool redundant) {
668         if (c.is_learned() != redundant)
669             c.set_learned(redundant);
670     }
671 
set_learned1(literal l1,literal l2,bool redundant)672     void solver::set_learned1(literal l1, literal l2, bool redundant) {
673         for (watched& w : get_wlist(~l1)) {
674             if (w.is_binary_clause() && l2 == w.get_literal() && !w.is_learned()) {
675                 w.set_learned(redundant);
676                 break;
677             }
678         }
679     }
680 
shrink(clause & c,unsigned old_sz,unsigned new_sz)681     void solver::shrink(clause& c, unsigned old_sz, unsigned new_sz) {
682         SASSERT(new_sz > 2);
683         SASSERT(old_sz >= new_sz);
684         if (old_sz != new_sz) {
685             c.shrink(new_sz);
686             for (literal l : c) {
687                 m_touched[l.var()] = m_touch_index;
688             }
689             if (m_config.m_drat) {
690                 m_drat.add(c, status::redundant());
691                 c.restore(old_sz);
692                 m_drat.del(c);
693                 c.shrink(new_sz);
694             }
695         }
696     }
697 
memory_pressure()698     bool solver::memory_pressure() {
699         return 3*cls_allocator().get_allocation_size()/2 + memory::get_allocation_size() > memory::get_max_memory_size();
700     }
701 
702     struct solver::cmp_activity {
703         solver& s;
cmp_activitysat::solver::cmp_activity704         cmp_activity(solver& s):s(s) {}
operator ()sat::solver::cmp_activity705         bool operator()(bool_var v1, bool_var v2) const {
706             return s.m_activity[v1] > s.m_activity[v2];
707         }
708     };
709 
should_defrag()710     bool solver::should_defrag() {
711         if (m_defrag_threshold > 0) --m_defrag_threshold;
712         return m_defrag_threshold == 0 && m_config.m_gc_defrag;
713     }
714 
defrag_clauses()715     void solver::defrag_clauses() {
716         m_defrag_threshold = 2;
717         if (memory_pressure()) return;
718         pop(scope_lvl());
719         IF_VERBOSE(2, verbose_stream() << "(sat-defrag)\n");
720         clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx];
721         ptr_vector<clause> new_clauses, new_learned;
722         for (clause* c : m_clauses) c->unmark_used();
723         for (clause* c : m_learned) c->unmark_used();
724 
725         svector<bool_var> vars;
726         for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i);
727         std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this));
728         literal_vector lits;
729         for (bool_var v : vars) lits.push_back(literal(v, false)), lits.push_back(literal(v, true));
730         // walk clauses, reallocate them in an order that defragments memory and creates locality.
731         for (literal lit : lits) {
732             watch_list& wlist = m_watches[lit.index()];
733             for (watched& w : wlist) {
734                 if (w.is_clause()) {
735                     clause& c1 = get_clause(w);
736                     clause_offset offset;
737                     if (c1.was_used()) {
738                         offset = c1.get_new_offset();
739                     }
740                     else {
741                         clause* c2 = alloc.copy_clause(c1);
742                         c1.mark_used();
743                         if (c1.is_learned()) {
744                             new_learned.push_back(c2);
745                         }
746                         else {
747                             new_clauses.push_back(c2);
748                         }
749                         offset = get_offset(*c2);
750                         c1.set_new_offset(offset);
751                     }
752                     w = watched(w.get_blocked_literal(), offset);
753                 }
754             }
755         }
756 
757         // reallocate ternary clauses.
758         for (clause* c : m_clauses) {
759             if (!c->was_used()) {
760                 SASSERT(c->size() == 3);
761                 new_clauses.push_back(alloc.copy_clause(*c));
762             }
763             dealloc_clause(c);
764         }
765 
766         for (clause* c : m_learned) {
767             if (!c->was_used()) {
768                 SASSERT(c->size() == 3);
769                 new_learned.push_back(alloc.copy_clause(*c));
770             }
771             dealloc_clause(c);
772         }
773         m_clauses.swap(new_clauses);
774         m_learned.swap(new_learned);
775 
776         cls_allocator().finalize();
777         m_cls_allocator_idx = !m_cls_allocator_idx;
778 
779         reinit_assumptions();
780     }
781 
782 
set_learned(literal l1,literal l2,bool redundant)783     void solver::set_learned(literal l1, literal l2, bool redundant) {
784         set_learned1(l1, l2, redundant);
785         set_learned1(l2, l1, redundant);
786     }
787 
788     /**
789        \brief Select a watch literal starting the search at the given position.
790        This method is only used for clauses created during the search.
791 
792        I use the following rules to select a watch literal.
793 
794        1- select a literal l in idx >= starting_at such that value(l) = l_true,
795        and for all l' in idx' >= starting_at . value(l') = l_true implies lvl(l) <= lvl(l')
796 
797        The purpose of this rule is to make the clause inactive for as long as possible. A clause
798        is inactive when it contains a literal assigned to true.
799 
800        2- if there isn't a literal assigned to true, then select an unassigned literal l in idx >= starting_at
801 
802        3- if there isn't a literal l in idx >= starting_at such that value(l) = l_true or
803        value(l) = l_undef (that is, all literals at positions >= starting_at are assigned
804        to false), then peek the literal l such that for all l' starting at starting_at
805        lvl(l) >= lvl(l')
806 
807        Without rule 3, boolean propagation is incomplete, that is, it may miss possible propagations.
808 
809        \remark The method select_lemma_watch_lit is used to select the watch literal for regular learned clauses.
810     */
select_watch_lit(clause const & cls,unsigned starting_at) const811     unsigned solver::select_watch_lit(clause const & cls, unsigned starting_at) const {
812         SASSERT(cls.size() >= 2);
813         unsigned min_true_idx  = UINT_MAX;
814         unsigned max_false_idx = UINT_MAX;
815         unsigned unknown_idx   = UINT_MAX;
816         unsigned n = cls.size();
817         for (unsigned i = starting_at; i < n; i++) {
818             literal l   = cls[i];
819             switch(value(l)) {
820             case l_false:
821                 if (max_false_idx == UINT_MAX || lvl(l) > lvl(cls[max_false_idx]))
822                     max_false_idx = i;
823                 break;
824             case l_undef:
825                 unknown_idx = i;
826                 break;
827             case l_true:
828                 if (min_true_idx == UINT_MAX || lvl(l) < lvl(cls[min_true_idx]))
829                     min_true_idx = i;
830                 break;
831             }
832         }
833         if (min_true_idx != UINT_MAX)
834             return min_true_idx;
835         if (unknown_idx != UINT_MAX)
836             return unknown_idx;
837         SASSERT(max_false_idx != UINT_MAX);
838         return max_false_idx;
839     }
840 
841     /**
842        \brief The learned clauses (lemmas) produced by the SAT solver
843        have the property that the first literal will be implied by it
844        after backtracking. All other literals are assigned to (or
845        implied to be) false when the learned clause is created. The
846        first watch literal will always be the first literal.  The
847        second watch literal is computed by this method. It should be
848        the literal with the highest decision level.
849 
850        // TODO: do we really need this? strength the conflict resolution
851     */
select_learned_watch_lit(clause const & cls) const852     unsigned solver::select_learned_watch_lit(clause const & cls) const {
853         SASSERT(cls.size() >= 2);
854         unsigned max_false_idx = UINT_MAX;
855         unsigned num_lits = cls.size();
856         for (unsigned i = 1; i < num_lits; i++) {
857             literal l    = cls[i];
858             CTRACE("sat", value(l) != l_false, tout << l << ":=" << value(l););
859             SASSERT(value(l) == l_false);
860             if (max_false_idx == UINT_MAX || lvl(l) > lvl(cls[max_false_idx]))
861                 max_false_idx = i;
862         }
863         return max_false_idx;
864     }
865 
866     template<bool lvl0>
simplify_clause_core(unsigned & num_lits,literal * lits) const867     bool solver::simplify_clause_core(unsigned & num_lits, literal * lits) const {
868         std::sort(lits, lits+num_lits);
869         literal prev = null_literal;
870         unsigned i = 0;
871         unsigned j = 0;
872         for (; i < num_lits; i++) {
873             literal curr = lits[i];
874             lbool val = value(curr);
875             if (!lvl0 && lvl(curr) > 0)
876                 val = l_undef;
877             switch (val) {
878             case l_false:
879                 break; // ignore literal
880             case l_undef:
881                 if (curr == ~prev)
882                     return false; // clause is equivalent to true
883                 if (curr != prev) {
884                     prev = curr;
885                     if (i != j)
886                         std::swap(lits[j], lits[i]);
887                     j++;
888                 }
889                 break;
890             case l_true:
891                 return false; // clause is equivalent to true
892             }
893         }
894         num_lits = j;
895         return true;
896     }
897 
simplify_clause(unsigned & num_lits,literal * lits) const898     bool solver::simplify_clause(unsigned & num_lits, literal * lits) const {
899         if (at_base_lvl())
900             return simplify_clause_core<true>(num_lits, lits);
901         else
902             return simplify_clause_core<false>(num_lits, lits);
903     }
904 
detach_bin_clause(literal l1,literal l2,bool redundant)905     void solver::detach_bin_clause(literal l1, literal l2, bool redundant) {
906         get_wlist(~l1).erase(watched(l2, redundant));
907         get_wlist(~l2).erase(watched(l1, redundant));
908         if (m_config.m_drat) m_drat.del(l1, l2);
909     }
910 
detach_clause(clause & c)911     void solver::detach_clause(clause & c) {
912         if (ENABLE_TERNARY && c.size() == 3)
913             detach_ter_clause(c);
914         else
915             detach_nary_clause(c);
916     }
917 
detach_nary_clause(clause & c)918     void solver::detach_nary_clause(clause & c) {
919         clause_offset cls_off = get_offset(c);
920         erase_clause_watch(get_wlist(~c[0]), cls_off);
921         erase_clause_watch(get_wlist(~c[1]), cls_off);
922     }
923 
detach_ter_clause(clause & c)924     void solver::detach_ter_clause(clause & c) {
925         erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]);
926         erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]);
927         erase_ternary_watch(get_wlist(~c[2]), c[0], c[1]);
928     }
929 
930     // -----------------------
931     //
932     // Basic
933     //
934     // -----------------------
935 
set_conflict(justification c,literal not_l)936     void solver::set_conflict(justification c, literal not_l) {
937         if (m_inconsistent)
938             return;
939         m_inconsistent = true;
940         m_conflict = c;
941         m_not_l    = not_l;
942     }
943 
assign_core(literal l,justification j)944     void solver::assign_core(literal l, justification j) {
945         SASSERT(value(l) == l_undef);
946         TRACE("sat_assign_core", tout << l << " " << j << "\n";);
947         if (j.level() == 0) {
948             if (m_config.m_drat)
949                 drat_log_unit(l, j);
950 
951             j = justification(0); // erase justification for level 0
952         }
953         else {
954             VERIFY(!at_base_lvl());
955         }
956         m_assignment[l.index()]    = l_true;
957         m_assignment[(~l).index()] = l_false;
958         bool_var v = l.var();
959         m_justification[v]         = j;
960         m_phase[v]                 = !l.sign();
961         m_assigned_since_gc[v]     = true;
962         m_trail.push_back(l);
963 
964         switch (m_config.m_branching_heuristic) {
965         case BH_VSIDS:
966             break;
967         case BH_CHB:
968             m_last_propagation[v] = m_stats.m_conflict;
969             break;
970         }
971 
972         if (m_config.m_anti_exploration) {
973             uint64_t age = m_stats.m_conflict - m_canceled[v];
974             if (age > 0) {
975                 double decay = pow(0.95, static_cast<double>(age));
976                 set_activity(v, static_cast<unsigned>(m_activity[v] * decay));
977                 // NB. MapleSAT does not update canceled.
978                 m_canceled[v] = m_stats.m_conflict;
979             }
980         }
981 
982         if (m_config.m_propagate_prefetch) {
983 #if defined(__GNUC__) || defined(__clang__)
984             __builtin_prefetch((const char*)((m_watches[l.index()].data())));
985 #else
986     #if !defined(_M_ARM) && !defined(_M_ARM64)
987             _mm_prefetch((const char*)((m_watches[l.index()].data())), _MM_HINT_T1);
988     #endif
989 #endif
990         }
991 
992         SASSERT(!l.sign() || !m_phase[v]);
993         SASSERT(l.sign()  || m_phase[v]);
994         SASSERT(!l.sign() || value(v) == l_false);
995         SASSERT(l.sign()  || value(v) == l_true);
996         SASSERT(value(l) == l_true);
997         SASSERT(value(~l) == l_false);
998     }
999 
status(clause const & c) const1000     lbool solver::status(clause const & c) const {
1001         bool found_undef = false;
1002         for (literal lit : c) {
1003             switch (value(lit)) {
1004             case l_true:
1005                 return l_true;
1006             case l_undef:
1007                 found_undef = true;
1008                 break;
1009             default:
1010                 break;
1011             }
1012         }
1013         return found_undef ? l_undef : l_false;
1014     }
1015 
1016     // -----------------------
1017     //
1018     // Propagation
1019     //
1020     // -----------------------
1021 
propagate_core(bool update)1022     bool solver::propagate_core(bool update) {
1023         while (m_qhead < m_trail.size() && !m_inconsistent) {
1024             do {
1025                 checkpoint();
1026                 m_cleaner.dec();
1027                 literal l = m_trail[m_qhead];
1028                 m_qhead++;
1029                 if (!propagate_literal(l, update))
1030                     return false;
1031             } while (m_qhead < m_trail.size());
1032 
1033             if (m_ext && (!is_probing() || at_base_lvl()))
1034                 m_ext->unit_propagate();
1035         }
1036         if (m_inconsistent)
1037             return false;
1038 
1039         SASSERT(m_qhead == m_trail.size());
1040         SASSERT(!m_inconsistent);
1041         return true;
1042     }
1043 
propagate(bool update)1044     bool solver::propagate(bool update) {
1045         unsigned qhead = m_qhead;
1046         bool r = propagate_core(update);
1047         if (m_config.m_branching_heuristic == BH_CHB) {
1048             update_chb_activity(r, qhead);
1049         }
1050         CASSERT("sat_propagate", check_invariant());
1051         CASSERT("sat_missed_prop", check_missed_propagation());
1052         return r;
1053     }
1054 
propagate_literal(literal l,bool update)1055     bool solver::propagate_literal(literal l, bool update) {
1056         literal l1, l2;
1057         lbool val1, val2;
1058         bool keep;
1059         unsigned curr_level = lvl(l);
1060         TRACE("sat_propagate", tout << "propagating: " << l << "@" << curr_level << " " << m_justification[l.var()] << "\n"; );
1061 
1062         literal not_l = ~l;
1063         SASSERT(value(l) == l_true);
1064         SASSERT(value(not_l) == l_false);
1065         watch_list& wlist = m_watches[l.index()];
1066         m_asymm_branch.dec(wlist.size());
1067         m_probing.dec(wlist.size());
1068         watch_list::iterator it = wlist.begin();
1069         watch_list::iterator it2 = it;
1070         watch_list::iterator end = wlist.end();
1071 #define CONFLICT_CLEANUP() {                    \
1072                 for (; it != end; ++it, ++it2)  \
1073                     *it2 = *it;                 \
1074                 wlist.set_end(it2);             \
1075             }
1076         for (; it != end; ++it) {
1077             switch (it->get_kind()) {
1078             case watched::BINARY:
1079                 l1 = it->get_literal();
1080                 switch (value(l1)) {
1081                 case l_false:
1082                     CONFLICT_CLEANUP();
1083                     set_conflict(justification(curr_level, not_l), ~l1);
1084                     return false;
1085                 case l_undef:
1086                     m_stats.m_bin_propagate++;
1087                     assign_core(l1, justification(curr_level, not_l));
1088                     break;
1089                 case l_true:
1090                     break; // skip
1091                 }
1092                 *it2 = *it;
1093                 it2++;
1094                 break;
1095             case watched::TERNARY:
1096                 l1 = it->get_literal1();
1097                 l2 = it->get_literal2();
1098                 val1 = value(l1);
1099                 val2 = value(l2);
1100                 if (val1 == l_false && val2 == l_undef) {
1101                     m_stats.m_ter_propagate++;
1102                     assign_core(l2, justification(std::max(curr_level, lvl(l1)), l1, not_l));
1103                 }
1104                 else if (val1 == l_undef && val2 == l_false) {
1105                     m_stats.m_ter_propagate++;
1106                     assign_core(l1, justification(std::max(curr_level, lvl(l2)), l2, not_l));
1107                 }
1108                 else if (val1 == l_false && val2 == l_false) {
1109                     CONFLICT_CLEANUP();
1110                     set_conflict(justification(std::max(curr_level, lvl(l1)), l1, not_l), ~l2);
1111                     return false;
1112                 }
1113                 *it2 = *it;
1114                 it2++;
1115                 break;
1116             case watched::CLAUSE: {
1117                 if (value(it->get_blocked_literal()) == l_true) {
1118                     TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n";
1119                     tout << get_clause(it) << "\n";);
1120                     *it2 = *it;
1121                     it2++;
1122                     break;
1123                 }
1124                 clause_offset cls_off = it->get_clause_offset();
1125                 clause& c = get_clause(cls_off);
1126                 TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";);
1127                 if (c[0] == not_l)
1128                     std::swap(c[0], c[1]);
1129                 CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";);
1130                 if (c.was_removed() || c.size() == 1 || c[1] != not_l) {
1131                     // Remark: this method may be invoked when the watch lists are not in a consistent state,
1132                     // and may contain dead/removed clauses, or clauses with removed literals.
1133                     // See: method propagate_unit at sat_simplifier.cpp
1134                     // So, we must check whether the clause was marked for deletion, or
1135                     // c[1] != not_l
1136                     *it2 = *it;
1137                     it2++;
1138                     break;
1139                 }
1140                 if (value(c[0]) == l_true) {
1141                     it2->set_clause(c[0], cls_off);
1142                     it2++;
1143                     break;
1144                 }
1145                 VERIFY(c[1] == not_l);
1146                 literal* l_it = c.begin() + 2;
1147                 literal* l_end = c.end();
1148                 unsigned assign_level = curr_level;
1149                 unsigned max_index = 1;
1150                 for (; l_it != l_end; ++l_it) {
1151                     if (value(*l_it) != l_false) {
1152                         c[1] = *l_it;
1153                         *l_it = not_l;
1154                         DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off););
1155                         m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off));
1156                         goto end_clause_case;
1157                     }
1158                 }
1159                 SASSERT(value(c[0]) == l_false || value(c[0]) == l_undef);
1160                 if (assign_level != scope_lvl()) {
1161                     for (unsigned i = 2; i < c.size(); ++i) {
1162                         unsigned level = lvl(c[i]);
1163                         if (level > assign_level) {
1164                             assign_level = level;
1165                             max_index = i;
1166                         }
1167                     }
1168                     IF_VERBOSE(20, verbose_stream() << "lower assignment level " << assign_level << " scope: " << scope_lvl() << "\n");
1169                 }
1170 
1171                 if (value(c[0]) == l_false) {
1172                     assign_level = std::max(assign_level, lvl(c[0]));
1173                     c.mark_used();
1174                     CONFLICT_CLEANUP();
1175                     set_conflict(justification(assign_level, cls_off));
1176                     return false;
1177                 }
1178                 else {
1179                     if (max_index != 1) {
1180                         IF_VERBOSE(20, verbose_stream() << "swap watch for: " << c[1] << " " << c[max_index] << "\n");
1181                         std::swap(c[1], c[max_index]);
1182                         m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off));
1183                     }
1184                     else {
1185                         *it2 = *it;
1186                         it2++;
1187                     }
1188                     m_stats.m_propagate++;
1189                     c.mark_used();
1190                     assign_core(c[0], justification(assign_level, cls_off));
1191                     if (update && c.is_learned() && c.glue() > 2) {
1192                         unsigned glue;
1193                         if (num_diff_levels_below(c.size(), c.begin(), c.glue() - 1, glue)) {
1194                             c.set_glue(glue);
1195                         }
1196                     }
1197                 }
1198             end_clause_case:
1199                 break;
1200             }
1201             case watched::EXT_CONSTRAINT:
1202                 SASSERT(m_ext);
1203                 keep = m_ext->propagated(l, it->get_ext_constraint_idx());
1204                 if (m_inconsistent) {
1205                     if (!keep) {
1206                         ++it;
1207                     }
1208                     CONFLICT_CLEANUP();
1209                     return false;
1210                 }
1211                 if (keep) {
1212                     *it2 = *it;
1213                     it2++;
1214                 }
1215                 break;
1216             default:
1217                 UNREACHABLE();
1218                 break;
1219             }
1220         }
1221         wlist.set_end(it2);
1222         if (m_ext && m_external[l.var()] && (!is_probing() || at_base_lvl()))
1223             m_ext->asserted(l);
1224 
1225         return true;
1226     }
1227 
display_lookahead_scores(std::ostream & out)1228     void solver::display_lookahead_scores(std::ostream& out) {
1229         lookahead lh(*this);
1230         lh.display_lookahead_scores(out);
1231     }
1232 
cube(bool_var_vector & vars,literal_vector & lits,unsigned backtrack_level)1233     lbool solver::cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level) {
1234         bool is_first = !m_cuber;
1235         if (is_first) {
1236             m_cuber = alloc(lookahead, *this);
1237         }
1238         lbool result = m_cuber->cube(vars, lits, backtrack_level);
1239         m_cuber->update_cube_statistics(m_aux_stats);
1240         switch (result) {
1241         case l_false:
1242             dealloc(m_cuber);
1243             m_cuber = nullptr;
1244             if (is_first) {
1245                 pop_to_base_level();
1246                 set_conflict();
1247             }
1248             break;
1249         case l_true: {
1250             lits.reset();
1251             pop_to_base_level();
1252             model const& mdl = m_cuber->get_model();
1253             for (bool_var v = 0; v < mdl.size(); ++v) {
1254                 if (value(v) != l_undef) {
1255                     continue;
1256                 }
1257                 literal l(v, false);
1258                 if (mdl[v] != l_true) l.neg();
1259                 if (inconsistent())
1260                     return l_undef;
1261                 push();
1262                 assign_core(l, justification(scope_lvl()));
1263                 propagate(false);
1264             }
1265             mk_model();
1266             break;
1267         }
1268         default:
1269             break;
1270         }
1271         return result;
1272     }
1273 
1274 
1275     // -----------------------
1276     //
1277     // Search
1278     //
1279     // -----------------------
check(unsigned num_lits,literal const * lits)1280     lbool solver::check(unsigned num_lits, literal const* lits) {
1281         init_reason_unknown();
1282         pop_to_base_level();
1283         m_stats.m_units = init_trail_size();
1284         IF_VERBOSE(2, verbose_stream() << "(sat.solver)\n";);
1285         SASSERT(at_base_lvl());
1286 
1287         if (m_config.m_ddfw_search) {
1288             m_cleaner(true);
1289             return do_ddfw_search(num_lits, lits);
1290         }
1291         if (m_config.m_prob_search) {
1292             m_cleaner(true);
1293             return do_prob_search(num_lits, lits);
1294         }
1295         if (m_config.m_local_search) {
1296             m_cleaner(true);
1297             return do_local_search(num_lits, lits);
1298         }
1299         if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0 ||
1300              m_config.m_ddfw_threads > 0) && !m_par && !m_ext) {
1301             SASSERT(scope_lvl() == 0);
1302             return check_par(num_lits, lits);
1303         }
1304         flet<bool> _searching(m_searching, true);
1305         m_clone = nullptr;
1306         if (m_mc.empty() && gparams::get_ref().get_bool("model_validate", false)) {
1307 
1308             m_clone = alloc(solver, m_no_drat_params, m_rlimit);
1309             m_clone->copy(*this);
1310             m_clone->set_extension(nullptr);
1311         }
1312         try {
1313             init_search();
1314             if (check_inconsistent()) return l_false;
1315             propagate(false);
1316             if (check_inconsistent()) return l_false;
1317             init_assumptions(num_lits, lits);
1318             propagate(false);
1319             if (check_inconsistent()) return l_false;
1320             if (m_config.m_force_cleanup) do_cleanup(true);
1321             TRACE("sat", display(tout););
1322 
1323             if (m_config.m_gc_burst) {
1324                 // force gc
1325                 m_conflicts_since_gc = m_gc_threshold + 1;
1326                 do_gc();
1327             }
1328 
1329             if (m_config.m_enable_pre_simplify) {
1330                 do_simplify();
1331                 if (check_inconsistent()) return l_false;
1332             }
1333 
1334             if (m_config.m_max_conflicts == 0) {
1335                 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";);
1336                 TRACE("sat", display(tout); m_mc.display(tout););
1337                 return l_undef;
1338             }
1339 
1340             log_stats();
1341             if (m_config.m_max_conflicts > 0 && m_config.m_burst_search > 0) {
1342                 m_restart_threshold = m_config.m_burst_search;
1343                 lbool r = bounded_search();
1344                 log_stats();
1345                 if (r != l_undef)
1346                     return r;
1347 
1348                 pop_reinit(scope_lvl());
1349                 m_conflicts_since_restart = 0;
1350                 m_restart_threshold = m_config.m_restart_initial;
1351             }
1352 
1353             lbool is_sat = search();
1354             log_stats();
1355             return is_sat;
1356         }
1357         catch (const abort_solver &) {
1358             m_reason_unknown = "sat.giveup";
1359             IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort giveup\")\n";);
1360             return l_undef;
1361         }
1362     }
1363 
should_cancel()1364     bool solver::should_cancel() {
1365         if (limit_reached() || memory_exceeded()) {
1366             return true;
1367         }
1368         if (m_config.m_restart_max <= m_restarts) {
1369             m_reason_unknown = "sat.max.restarts";
1370             IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";);
1371             return true;
1372         }
1373         if (m_config.m_inprocess_max <= m_simplifications) {
1374             m_reason_unknown = "sat.max.inprocess";
1375             IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-inprocess\")\n";);
1376             return true;
1377         }
1378         if (reached_max_conflicts()) {
1379             return true;
1380         }
1381         return false;
1382     }
1383 
1384     enum par_exception_kind {
1385         DEFAULT_EX,
1386         ERROR_EX
1387     };
1388 
invoke_local_search(unsigned num_lits,literal const * lits)1389     lbool solver::invoke_local_search(unsigned num_lits, literal const* lits) {
1390         literal_vector _lits(num_lits, lits);
1391         for (literal lit : m_user_scope_literals) _lits.push_back(~lit);
1392         struct scoped_ls {
1393             solver& s;
1394             scoped_ls(solver& s): s(s) {}
1395             ~scoped_ls() {
1396                 dealloc(s.m_local_search);
1397                 s.m_local_search = nullptr;
1398             }
1399         };
1400         scoped_ls _ls(*this);
1401         if (inconsistent())
1402             return l_false;
1403         scoped_limits scoped_rl(rlimit());
1404         SASSERT(m_local_search);
1405         m_local_search->add(*this);
1406         m_local_search->updt_params(m_params);
1407         scoped_rl.push_child(&(m_local_search->rlimit()));
1408         lbool r = m_local_search->check(_lits.size(), _lits.data(), nullptr);
1409         if (r == l_true) {
1410             m_model = m_local_search->get_model();
1411             m_model_is_current = true;
1412         }
1413         return r;
1414     }
1415 
do_local_search(unsigned num_lits,literal const * lits)1416     lbool solver::do_local_search(unsigned num_lits, literal const* lits) {
1417         SASSERT(!m_local_search);
1418         m_local_search = alloc(local_search);
1419         return invoke_local_search(num_lits, lits);
1420     }
1421 
do_ddfw_search(unsigned num_lits,literal const * lits)1422     lbool solver::do_ddfw_search(unsigned num_lits, literal const* lits) {
1423         if (m_ext) return l_undef;
1424         SASSERT(!m_local_search);
1425         m_local_search = alloc(ddfw);
1426         return invoke_local_search(num_lits, lits);
1427     }
1428 
do_prob_search(unsigned num_lits,literal const * lits)1429     lbool solver::do_prob_search(unsigned num_lits, literal const* lits) {
1430         if (m_ext) return l_undef;
1431         if (num_lits > 0 || !m_user_scope_literals.empty()) return l_undef;
1432         SASSERT(!m_local_search);
1433         m_local_search = alloc(prob);
1434         return invoke_local_search(num_lits, lits);
1435     }
1436 
1437 #ifdef SINGLE_THREAD
check_par(unsigned num_lits,literal const * lits)1438     lbool solver::check_par(unsigned num_lits, literal const* lits) {
1439         return l_undef;
1440     }
1441 #else
check_par(unsigned num_lits,literal const * lits)1442     lbool solver::check_par(unsigned num_lits, literal const* lits) {
1443         if (!rlimit().inc()) {
1444             return l_undef;
1445         }
1446         if (m_ext)
1447             return l_undef;
1448 
1449         scoped_ptr_vector<i_local_search> ls;
1450         scoped_ptr_vector<solver> uw;
1451         int num_extra_solvers = m_config.m_num_threads - 1;
1452         int num_local_search  = static_cast<int>(m_config.m_local_search_threads);
1453         int num_ddfw      = m_ext ? 0 : static_cast<int>(m_config.m_ddfw_threads);
1454         int num_threads = num_extra_solvers + 1 + num_local_search + num_ddfw;
1455         for (int i = 0; i < num_local_search; ++i) {
1456             local_search* l = alloc(local_search);
1457             l->updt_params(m_params);
1458             l->add(*this);
1459             l->set_seed(m_config.m_random_seed + i);
1460             ls.push_back(l);
1461         }
1462 
1463         vector<reslimit> lims(num_ddfw);
1464         // set up ddfw search
1465         for (int i = 0; i < num_ddfw; ++i) {
1466             ddfw* d = alloc(ddfw);
1467             d->updt_params(m_params);
1468             d->set_seed(m_config.m_random_seed + i);
1469             d->add(*this);
1470             ls.push_back(d);
1471         }
1472         int local_search_offset = num_extra_solvers;
1473         int main_solver_offset = num_extra_solvers + num_local_search + num_ddfw;
1474 
1475 #define IS_AUX_SOLVER(i)   (0 <= i && i < num_extra_solvers)
1476 #define IS_LOCAL_SEARCH(i) (local_search_offset <= i && i < main_solver_offset)
1477 #define IS_MAIN_SOLVER(i)  (i == main_solver_offset)
1478 
1479         sat::parallel par(*this);
1480         par.reserve(num_threads, 1 << 12);
1481         par.init_solvers(*this, num_extra_solvers);
1482         for (unsigned i = 0; i < ls.size(); ++i) {
1483             par.push_child(ls[i]->rlimit());
1484         }
1485         for (reslimit& rl : lims) {
1486             par.push_child(rl);
1487         }
1488         for (unsigned i = 0; i < uw.size(); ++i) {
1489             uw[i]->set_par(&par, 0);
1490         }
1491         int finished_id = -1;
1492         std::string        ex_msg;
1493         par_exception_kind ex_kind = DEFAULT_EX;
1494         unsigned error_code = 0;
1495         lbool result = l_undef;
1496         bool canceled = false;
1497         std::mutex mux;
1498 
1499         auto worker_thread = [&](int i) {
1500             try {
1501                 lbool r = l_undef;
1502                 if (IS_AUX_SOLVER(i)) {
1503                     r = par.get_solver(i).check(num_lits, lits);
1504                 }
1505                 else if (IS_LOCAL_SEARCH(i)) {
1506                     r = ls[i-local_search_offset]->check(num_lits, lits, &par);
1507                 }
1508                 else {
1509                     r = check(num_lits, lits);
1510                 }
1511                 bool first = false;
1512                 {
1513                     std::lock_guard<std::mutex> lock(mux);
1514                     if (finished_id == -1) {
1515                         finished_id = i;
1516                         first = true;
1517                         result = r;
1518                     }
1519                 }
1520                 if (first) {
1521                     for (unsigned j = 0; j < ls.size(); ++j) {
1522                         ls[j]->rlimit().cancel();
1523                     }
1524                     for (auto& rl : lims) {
1525                         rl.cancel();
1526                     }
1527                     for (int j = 0; j < num_extra_solvers; ++j) {
1528                         if (i != j) {
1529                             par.cancel_solver(j);
1530                         }
1531                     }
1532                     if (!IS_MAIN_SOLVER(i)) {
1533                         canceled = !rlimit().inc();
1534                         if (!canceled) {
1535                             rlimit().cancel();
1536                         }
1537                     }
1538                 }
1539             }
1540             catch (z3_error & err) {
1541                 error_code = err.error_code();
1542                 ex_kind = ERROR_EX;
1543             }
1544             catch (z3_exception & ex) {
1545                 ex_msg = ex.msg();
1546                 ex_kind = DEFAULT_EX;
1547             }
1548         };
1549 
1550         if (!rlimit().inc()) {
1551             set_par(nullptr, 0);
1552             return l_undef;
1553         }
1554 
1555         vector<std::thread> threads(num_threads);
1556         for (int i = 0; i < num_threads; ++i) {
1557             threads[i] = std::thread([&, i]() { worker_thread(i); });
1558         }
1559         for (auto & th : threads) {
1560             th.join();
1561         }
1562 
1563         if (IS_AUX_SOLVER(finished_id)) {
1564             m_stats = par.get_solver(finished_id).m_stats;
1565         }
1566         if (result == l_true && IS_AUX_SOLVER(finished_id)) {
1567             set_model(par.get_solver(finished_id).get_model(), true);
1568         }
1569         else if (result == l_false && IS_AUX_SOLVER(finished_id)) {
1570             m_core.reset();
1571             m_core.append(par.get_solver(finished_id).get_core());
1572         }
1573         if (result == l_true && IS_LOCAL_SEARCH(finished_id)) {
1574             set_model(ls[finished_id - local_search_offset]->get_model(), true);
1575         }
1576         if (!canceled) {
1577             rlimit().reset_cancel();
1578         }
1579         set_par(nullptr, 0);
1580         ls.reset();
1581         uw.reset();
1582         if (finished_id == -1) {
1583             switch (ex_kind) {
1584             case ERROR_EX: throw z3_error(error_code);
1585             default: throw default_exception(std::move(ex_msg));
1586             }
1587         }
1588         return result;
1589 
1590     }
1591 #endif
1592 
1593     /*
1594       \brief import lemmas/units from parallel sat solvers.
1595      */
exchange_par()1596     void solver::exchange_par() {
1597         if (m_par && at_base_lvl() && m_config.m_num_threads > 1) m_par->get_clauses(*this);
1598         if (m_par && at_base_lvl() && m_config.m_num_threads > 1) {
1599             // SASSERT(scope_lvl() == search_lvl());
1600             // TBD: import also dependencies of assumptions.
1601             unsigned sz = init_trail_size();
1602             unsigned num_in = 0, num_out = 0;
1603             literal_vector in, out;
1604             for (unsigned i = m_par_limit_out; i < sz; ++i) {
1605                 literal lit = m_trail[i];
1606                 if (lit.var() < m_par_num_vars) {
1607                     ++num_out;
1608                     out.push_back(lit);
1609                 }
1610             }
1611             m_par_limit_out = sz;
1612             m_par->exchange(*this, out, m_par_limit_in, in);
1613             for (unsigned i = 0; !inconsistent() && i < in.size(); ++i) {
1614                 literal lit = in[i];
1615                 SASSERT(lit.var() < m_par_num_vars);
1616                 if (lvl(lit.var()) != 0 || value(lit) != l_true) {
1617                     ++num_in;
1618                     assign_unit(lit);
1619                 }
1620             }
1621             if (num_in > 0 || num_out > 0) {
1622                 IF_VERBOSE(2, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";);
1623             }
1624         }
1625     }
1626 
set_par(parallel * p,unsigned id)1627     void solver::set_par(parallel* p, unsigned id) {
1628         m_par = p;
1629         m_par_num_vars = num_vars();
1630         m_par_limit_in = 0;
1631         m_par_limit_out = 0;
1632         m_par_id = id;
1633         m_par_syncing_clauses = false;
1634     }
1635 
next_var()1636     bool_var solver::next_var() {
1637         bool_var next;
1638 
1639         if (m_rand() < static_cast<int>(m_config.m_random_freq * random_gen::max_value())) {
1640             if (num_vars() == 0)
1641                 return null_bool_var;
1642             next = m_rand() % num_vars();
1643             TRACE("random_split", tout << "next: " << next << " value(next): " << value(next) << "\n";);
1644             if (value(next) == l_undef && !was_eliminated(next))
1645                 return next;
1646         }
1647 
1648         while (!m_case_split_queue.empty()) {
1649             if (m_config.m_anti_exploration) {
1650                 next = m_case_split_queue.min_var();
1651                 auto age = m_stats.m_conflict - m_canceled[next];
1652                 while (age > 0) {
1653                     set_activity(next, static_cast<unsigned>(m_activity[next] * pow(0.95, static_cast<double>(age))));
1654                     m_canceled[next] = m_stats.m_conflict;
1655                     next = m_case_split_queue.min_var();
1656                     age = m_stats.m_conflict - m_canceled[next];
1657                 }
1658             }
1659             next = m_case_split_queue.next_var();
1660             if (value(next) == l_undef && !was_eliminated(next))
1661                 return next;
1662         }
1663 
1664         return null_bool_var;
1665     }
1666 
decide()1667     bool solver::decide() {
1668         bool_var next = next_var();
1669         if (next == null_bool_var)
1670             return false;
1671         push();
1672         m_stats.m_decision++;
1673         lbool lphase = m_ext ? m_ext->get_phase(next) : l_undef;
1674         bool phase = lphase == l_true;
1675 
1676         if (lphase == l_undef) {
1677             switch (m_config.m_phase) {
1678             case PS_ALWAYS_TRUE:
1679                 phase = true;
1680                 break;
1681             case PS_ALWAYS_FALSE:
1682                 phase = false;
1683                 break;
1684             case PS_BASIC_CACHING:
1685                 phase = m_phase[next];
1686                 break;
1687             case PS_FROZEN:
1688                 phase = m_best_phase[next];
1689                 break;
1690             case PS_SAT_CACHING:
1691                 if (m_search_state == s_unsat) {
1692                     phase = m_phase[next];
1693                 }
1694                 else {
1695                     phase = m_best_phase[next];
1696                 }
1697                 break;
1698             case PS_RANDOM:
1699                 phase = (m_rand() % 2) == 0;
1700                 break;
1701             default:
1702                 UNREACHABLE();
1703                 phase = false;
1704                 break;
1705             }
1706         }
1707 
1708         literal next_lit(next, !phase);
1709         TRACE("sat_decide", tout << scope_lvl() << ": next-case-split: " << next_lit << "\n";);
1710         assign_scoped(next_lit);
1711         return true;
1712     }
1713 
bounded_search()1714     lbool solver::bounded_search() {
1715         flet<bool> _disable_simplify(m_simplify_enabled, false);
1716         flet<bool> _restart_enabled(m_restart_enabled, false);
1717         return search();
1718     }
1719 
basic_search()1720     lbool solver::basic_search() {
1721         lbool is_sat = l_undef;
1722         while (is_sat == l_undef && !should_cancel()) {
1723             if (inconsistent()) is_sat = resolve_conflict_core();
1724             else if (should_propagate()) propagate(true);
1725             else if (do_cleanup(false)) continue;
1726             else if (should_gc()) do_gc();
1727             else if (should_rephase()) do_rephase();
1728             else if (should_restart()) { if (!m_restart_enabled) return l_undef; do_restart(!m_config.m_restart_fast); }
1729             else if (should_simplify()) do_simplify();
1730             else if (!decide()) is_sat = final_check();
1731         }
1732         return is_sat;
1733     }
1734 
search()1735     lbool solver::search() {
1736         if (!m_ext || !m_ext->tracking_assumptions())
1737             return basic_search();
1738         while (true) {
1739             pop_to_base_level();
1740             reinit_assumptions();
1741             lbool r = basic_search();
1742             if (r != l_false)
1743                 return r;
1744             if (!m_ext->should_research(m_core))
1745                 return r;
1746         }
1747     }
1748 
should_propagate() const1749     bool solver::should_propagate() const {
1750         return !inconsistent() && m_qhead < m_trail.size();
1751     }
1752 
final_check()1753     lbool solver::final_check() {
1754         if (m_ext) {
1755             switch (m_ext->check()) {
1756             case check_result::CR_DONE:
1757                 mk_model();
1758                 return l_true;
1759             case check_result::CR_CONTINUE:
1760                 break;
1761             case check_result::CR_GIVEUP:
1762                 throw abort_solver();
1763             }
1764             return l_undef;
1765         }
1766         else {
1767             mk_model();
1768             return l_true;
1769         }
1770     }
1771 
1772 
check_inconsistent()1773     bool solver::check_inconsistent() {
1774         if (inconsistent()) {
1775             if (tracking_assumptions() && at_search_lvl())
1776                 resolve_conflict();
1777             else if (m_config.m_drat && at_base_lvl())
1778                 resolve_conflict();
1779             return true;
1780         }
1781         else {
1782             return false;
1783         }
1784     }
1785 
1786 
init_assumptions(unsigned num_lits,literal const * lits)1787     void solver::init_assumptions(unsigned num_lits, literal const* lits) {
1788         if (num_lits == 0 && m_user_scope_literals.empty()) {
1789             return;
1790         }
1791 
1792         SASSERT(at_base_lvl());
1793         reset_assumptions();
1794         push();
1795 
1796         propagate(false);
1797         if (inconsistent()) {
1798             return;
1799         }
1800 
1801         TRACE("sat",
1802               tout << literal_vector(num_lits, lits) << "\n";
1803               if (!m_user_scope_literals.empty()) {
1804                   tout << "user literals: " << m_user_scope_literals << "\n";
1805               }
1806               m_mc.display(tout);
1807               );
1808 
1809         for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) {
1810             literal nlit = ~m_user_scope_literals[i];
1811             assign_scoped(nlit);
1812         }
1813 
1814         for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) {
1815             literal lit = lits[i];
1816             set_external(lit.var());
1817             SASSERT(is_external(lit.var()));
1818             add_assumption(lit);
1819             assign_scoped(lit);
1820         }
1821 
1822         m_search_lvl = scope_lvl();
1823         SASSERT(m_search_lvl == 1);
1824     }
1825 
update_min_core()1826     void solver::update_min_core() {
1827         if (!m_min_core_valid || m_core.size() < m_min_core.size()) {
1828             m_min_core.reset();
1829             m_min_core.append(m_core);
1830             m_min_core_valid = true;
1831         }
1832     }
1833 
reset_assumptions()1834     void solver::reset_assumptions() {
1835         m_assumptions.reset();
1836         m_assumption_set.reset();
1837         m_ext_assumption_set.reset();
1838     }
1839 
add_assumption(literal lit)1840     void solver::add_assumption(literal lit) {
1841         m_assumption_set.insert(lit);
1842         m_assumptions.push_back(lit);
1843         set_external(lit.var());
1844     }
1845 
reassert_min_core()1846     void solver::reassert_min_core() {
1847         SASSERT(m_min_core_valid);
1848         pop_to_base_level();
1849         push();
1850         reset_assumptions();
1851         TRACE("sat", tout << "reassert: " << m_min_core << "\n";);
1852         for (literal lit : m_min_core) {
1853             SASSERT(is_external(lit.var()));
1854             add_assumption(lit);
1855             assign_scoped(lit);
1856         }
1857         propagate(false);
1858         SASSERT(inconsistent());
1859     }
1860 
reinit_assumptions()1861     void solver::reinit_assumptions() {
1862         if (tracking_assumptions() && at_base_lvl() && !inconsistent()) {
1863             TRACE("sat", tout << "assumptions: " << m_assumptions << " user scopes: " << m_user_scope_literals << "\n";);
1864             if (!propagate(false)) return;
1865             push();
1866             for (literal lit : m_user_scope_literals) {
1867                 if (inconsistent()) break;
1868                 assign_scoped(~lit);
1869             }
1870             for (literal lit : m_assumptions) {
1871                 if (inconsistent()) break;
1872                 assign_scoped(lit);
1873             }
1874             init_ext_assumptions();
1875 
1876             if (!inconsistent())
1877                 propagate(false);
1878             TRACE("sat",
1879                   tout << "consistent: " << !inconsistent() << "\n";
1880                   for (literal a : m_assumptions) {
1881                       index_set s;
1882                       if (m_antecedents.find(a.var(), s)) {
1883                           tout << a << ": "; display_index_set(tout, s) << "\n";
1884                       }
1885                   }
1886                   for (literal lit : m_user_scope_literals) {
1887                       tout << "user " << lit << "\n";
1888                   }
1889                   );
1890         }
1891     }
1892 
init_ext_assumptions()1893     void solver::init_ext_assumptions() {
1894         if (m_ext && m_ext->tracking_assumptions()) {
1895             m_ext_assumption_set.reset();
1896             if (!inconsistent())
1897                 m_ext->add_assumptions(m_ext_assumption_set);
1898         }
1899     }
1900 
tracking_assumptions() const1901     bool solver::tracking_assumptions() const {
1902         return !m_assumptions.empty() || !m_user_scope_literals.empty() || (m_ext && m_ext->tracking_assumptions());
1903     }
1904 
is_assumption(literal l) const1905     bool solver::is_assumption(literal l) const {
1906         return tracking_assumptions() && (m_assumption_set.contains(l) || m_ext_assumption_set.contains(l));
1907     }
1908 
set_activity(bool_var v,unsigned new_act)1909     void solver::set_activity(bool_var v, unsigned new_act) {
1910         unsigned old_act = m_activity[v];
1911         m_activity[v] = new_act;
1912         if (!was_eliminated(v) && value(v) == l_undef && new_act != old_act) {
1913             m_case_split_queue.activity_changed_eh(v, new_act > old_act);
1914         }
1915     }
1916 
is_assumption(bool_var v) const1917     bool solver::is_assumption(bool_var v) const {
1918         return is_assumption(literal(v, false)) || is_assumption(literal(v, true));
1919     }
1920 
init_search()1921     void solver::init_search() {
1922         m_model_is_current        = false;
1923         m_phase_counter           = 0;
1924         m_search_state            = s_unsat;
1925         m_search_unsat_conflicts  = m_config.m_search_unsat_conflicts;
1926         m_search_sat_conflicts    = m_config.m_search_sat_conflicts;
1927         m_search_next_toggle      = m_search_unsat_conflicts;
1928         m_best_phase_size         = 0;
1929         m_rephase_lim             = 0;
1930         m_rephase_inc             = 0;
1931         m_reorder_lim             = m_config.m_reorder_base;
1932         m_reorder_inc             = 0;
1933         m_conflicts_since_restart = 0;
1934         m_force_conflict_analysis = false;
1935         m_restart_threshold       = m_config.m_restart_initial;
1936         m_luby_idx                = 1;
1937         m_gc_threshold            = m_config.m_gc_initial;
1938         m_defrag_threshold        = 2;
1939         m_restarts                = 0;
1940         m_last_position_log       = 0;
1941         m_restart_logs            = 0;
1942         m_simplifications         = 0;
1943         m_conflicts_since_init    = 0;
1944         m_next_simplify           = m_config.m_simplify_delay;
1945         m_min_d_tk                = 1.0;
1946         m_search_lvl              = 0;
1947         if (m_learned.size() <= 2*m_clauses.size())
1948             m_conflicts_since_gc      = 0;
1949         m_restart_next_out        = 0;
1950         m_asymm_branch.init_search();
1951         m_stopwatch.reset();
1952         m_stopwatch.start();
1953         m_core.reset();
1954         m_min_core_valid = false;
1955         m_min_core.reset();
1956         m_simplifier.init_search();
1957         m_mc.init_search(*this);
1958         if (m_ext)
1959             m_ext->init_search();
1960         TRACE("sat", display(tout););
1961     }
1962 
should_simplify() const1963     bool solver::should_simplify() const {
1964         return m_conflicts_since_init >= m_next_simplify && m_simplify_enabled;
1965     }
1966     /**
1967        \brief Apply all simplifications.
1968     */
do_simplify()1969     void solver::do_simplify() {
1970         if (!should_simplify()) {
1971             return;
1972         }
1973         log_stats();
1974         m_simplifications++;
1975 
1976         TRACE("sat", tout << "simplify\n";);
1977 
1978         pop(scope_lvl());
1979         struct report {
1980             solver&   s;
1981             stopwatch m_watch;
1982             report(solver& s):s(s) {
1983                 m_watch.start();
1984                 s.log_stats();
1985                 IF_VERBOSE(2, verbose_stream() << "(sat.simplify :simplifications " << s.m_simplifications << ")\n";);
1986             }
1987             ~report() {
1988                 m_watch.stop();
1989                 s.log_stats();
1990             }
1991         };
1992         report _rprt(*this);
1993         SASSERT(at_base_lvl());
1994 
1995         m_cleaner(m_config.m_force_cleanup);
1996         CASSERT("sat_simplify_bug", check_invariant());
1997 
1998         m_scc();
1999         CASSERT("sat_simplify_bug", check_invariant());
2000 
2001         if (m_ext) {
2002             m_ext->pre_simplify();
2003         }
2004 
2005         m_simplifier(false);
2006 
2007         CASSERT("sat_simplify_bug", check_invariant());
2008         CASSERT("sat_missed_prop", check_missed_propagation());
2009         if (!m_learned.empty()) {
2010             m_simplifier(true);
2011             CASSERT("sat_missed_prop", check_missed_propagation());
2012             CASSERT("sat_simplify_bug", check_invariant());
2013         }
2014         sort_watch_lits();
2015         CASSERT("sat_simplify_bug", check_invariant());
2016 
2017         m_probing();
2018         CASSERT("sat_missed_prop", check_missed_propagation());
2019         CASSERT("sat_simplify_bug", check_invariant());
2020         m_asymm_branch(false);
2021 
2022         CASSERT("sat_missed_prop", check_missed_propagation());
2023         CASSERT("sat_simplify_bug", check_invariant());
2024         if (m_ext) {
2025             m_ext->clauses_modifed();
2026             m_ext->simplify();
2027         }
2028         if (m_config.m_lookahead_simplify && !m_ext) {
2029             lookahead lh(*this);
2030             lh.simplify(true);
2031             lh.collect_statistics(m_aux_stats);
2032         }
2033 
2034         reinit_assumptions();
2035         if (inconsistent()) return;
2036 
2037         if (m_next_simplify == 0) {
2038             m_next_simplify = m_config.m_next_simplify1;
2039         }
2040         else {
2041             m_next_simplify = static_cast<unsigned>(m_conflicts_since_init * m_config.m_simplify_mult2);
2042             if (m_next_simplify > m_conflicts_since_init + m_config.m_simplify_max)
2043                 m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max;
2044         }
2045 
2046         if (m_par) {
2047             m_par->from_solver(*this);
2048             if (m_par->to_solver(*this)) {
2049                 m_activity_inc = 128;
2050             }
2051         }
2052 
2053         if (m_config.m_binspr && !inconsistent()) {
2054             m_binspr();
2055         }
2056 
2057         if (m_config.m_anf_simplify && m_simplifications > m_config.m_anf_delay && !inconsistent()) {
2058             anf_simplifier anf(*this);
2059             anf_simplifier::config cfg;
2060             cfg.m_enable_exlin = m_config.m_anf_exlin;
2061             anf();
2062             anf.collect_statistics(m_aux_stats);
2063             // TBD: throttle anf_delay based on yield
2064         }
2065 
2066         if (m_cut_simplifier && m_simplifications > m_config.m_cut_delay && !inconsistent()) {
2067             (*m_cut_simplifier)();
2068         }
2069 
2070         if (m_config.m_inprocess_out.is_non_empty_string()) {
2071             std::ofstream fout(m_config.m_inprocess_out.str());
2072             if (fout) {
2073                 display_dimacs(fout);
2074             }
2075             throw solver_exception("output generated");
2076         }
2077     }
2078 
set_root(literal l,literal r)2079     bool solver::set_root(literal l, literal r) {
2080         return !m_ext || m_ext->set_root(l, r);
2081     }
2082 
flush_roots()2083     void solver::flush_roots() {
2084         if (m_ext) m_ext->flush_roots();
2085     }
2086 
sort_watch_lits()2087     void solver::sort_watch_lits() {
2088         for (watch_list & wlist : m_watches) {
2089             std::stable_sort(wlist.begin(), wlist.end(), watched_lt());
2090         }
2091     }
2092 
set_model(model const & mdl,bool is_current)2093     void solver::set_model(model const& mdl, bool is_current) {
2094         m_model.reset();
2095         m_model.append(mdl);
2096         m_model_is_current = is_current;
2097     }
2098 
mk_model()2099     void solver::mk_model() {
2100         m_model.reset();
2101         m_model_is_current = true;
2102         unsigned num = num_vars();
2103         m_model.resize(num, l_undef);
2104         for (bool_var v = 0; v < num; v++) {
2105             if (!was_eliminated(v)) {
2106                 m_model[v] = value(v);
2107                 m_phase[v] = value(v) == l_true;
2108                 m_best_phase[v] = value(v) == l_true;
2109             }
2110         }
2111         TRACE("sat_mc_bug", m_mc.display(tout););
2112 
2113 #if 0
2114         IF_VERBOSE(2, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";);
2115         for (auto p : big::s_del_bin) {
2116             if (value(p.first) != l_true && value(p.second) != l_true) {
2117                 IF_VERBOSE(2, verbose_stream() << "binary violation: " << p.first << " " << p.second << "\n");
2118             }
2119         }
2120 #endif
2121 
2122         if (m_clone) {
2123             IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";);
2124             if (!check_clauses(m_model)) {
2125                 throw solver_exception("check model failed");
2126             }
2127         }
2128 
2129         if (m_config.m_drat) {
2130             m_drat.check_model(m_model);
2131         }
2132 
2133         m_mc(m_model);
2134 
2135         if (m_clone && !check_clauses(m_model)) {
2136             IF_VERBOSE(1, verbose_stream() << "failure checking clauses on transformed model\n";);
2137             IF_VERBOSE(10, m_mc.display(verbose_stream()));
2138             IF_VERBOSE(1, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";);
2139 
2140             throw solver_exception("check model failed");
2141         }
2142 
2143         TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
2144 
2145         if (m_clone) {
2146             IF_VERBOSE(1, verbose_stream() << "\"checking model (on original set of clauses)\"\n";);
2147             if (!m_clone->check_model(m_model)) {
2148                 IF_VERBOSE(1, m_mc.display(verbose_stream()));
2149                 IF_VERBOSE(1, display_units(verbose_stream()));
2150                 throw solver_exception("check model failed (for cloned solver)");
2151             }
2152         }
2153     }
2154 
check_clauses(model const & m) const2155     bool solver::check_clauses(model const& m) const {
2156         bool ok = true;
2157         for (clause const* cp : m_clauses) {
2158             clause const & c = *cp;
2159             if (!c.satisfied_by(m)) {
2160                 IF_VERBOSE(1, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";);
2161                 TRACE("sat", tout << "failed: " << c << "\n";
2162                       tout << "assumptions: " << m_assumptions << "\n";
2163                       tout << "trail: " << m_trail << "\n";
2164                       tout << "model: " << m << "\n";
2165                       m_mc.display(tout);
2166                       );
2167                 for (literal l : c) {
2168                     if (was_eliminated(l.var())) IF_VERBOSE(1, verbose_stream() << "eliminated: " << l << "\n";);
2169                 }
2170                 ok = false;
2171             }
2172         }
2173         unsigned l_idx = 0;
2174         for (watch_list const& wlist : m_watches) {
2175             literal l = ~to_literal(l_idx);
2176             if (value_at(l, m) != l_true) {
2177                 for (watched const& w : wlist) {
2178                     if (!w.is_binary_non_learned_clause())
2179                         continue;
2180                     literal l2 = w.get_literal();
2181                     if (l.index() > l2.index())
2182                         continue;
2183                     if (value_at(l2, m) != l_true) {
2184                         IF_VERBOSE(1, verbose_stream() << "failed binary: " << l << " := " << value_at(l, m) << " " << l2 <<  " := " << value_at(l2, m) << "\n");
2185                         IF_VERBOSE(1, verbose_stream() << "elim l1: " << was_eliminated(l.var()) << " elim l2: " << was_eliminated(l2) << "\n");
2186                         TRACE("sat", m_mc.display(tout << "failed binary: " << l << " " << l2 << "\n"););
2187                         ok = false;
2188                     }
2189                 }
2190             }
2191             ++l_idx;
2192         }
2193         for (literal l : m_assumptions) {
2194             if (value_at(l, m) != l_true) {
2195                 VERIFY(is_external(l.var()));
2196                 IF_VERBOSE(1, verbose_stream() << "assumption: " << l << " does not model check " << value_at(l, m) << "\n";);
2197                 TRACE("sat",
2198                       tout << l << " does not model check\n";
2199                       tout << "trail: " << m_trail << "\n";
2200                       tout << "model: " << m << "\n";
2201                       m_mc.display(tout);
2202                       );
2203                 ok = false;
2204             }
2205         }
2206         if (m_ext && !m_ext->check_model(m)) {
2207             ok = false;
2208         }
2209         return ok;
2210     }
2211 
check_model(model const & m) const2212     bool solver::check_model(model const & m) const {
2213         bool ok = check_clauses(m);
2214         if (ok && !m_mc.check_model(m)) {
2215             ok = false;
2216             TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout););
2217             IF_VERBOSE(0, verbose_stream() << "model check failed\n");
2218         }
2219         return ok;
2220     }
2221 
should_restart() const2222     bool solver::should_restart() const {
2223         if (m_conflicts_since_restart <= m_restart_threshold) return false;
2224         if (scope_lvl() < 2 + search_lvl()) return false;
2225         if (m_case_split_queue.empty()) return false;
2226         if (m_config.m_restart != RS_EMA) return true;
2227         return
2228             m_fast_glue_avg + search_lvl() <= scope_lvl() &&
2229             m_config.m_restart_margin * m_slow_glue_avg <= m_fast_glue_avg;
2230     }
2231 
log_stats()2232     void solver::log_stats() {
2233         m_restart_logs++;
2234 
2235         std::stringstream strm;
2236         strm << "(sat.stats " << std::setw(6) << m_stats.m_conflict << " "
2237              << std::setw(6) << m_stats.m_decision << " "
2238              << std::setw(4) << m_stats.m_restart
2239              << mk_stat(*this)
2240              << " " << std::setw(6) << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";
2241         std::string str(strm.str());
2242         svector<size_t> nums;
2243         for (size_t i = 0; i < str.size(); ++i) {
2244             while (i < str.size() && str[i] != ' ') ++i;
2245             while (i < str.size() && str[i] == ' ') ++i;
2246             // position of first character after space
2247             if (i < str.size()) {
2248                 nums.push_back(i);
2249             }
2250         }
2251         bool same = m_last_positions.size() == nums.size();
2252         size_t diff = 0;
2253         for (unsigned i = 0; i < nums.size() && same; ++i) {
2254             if (m_last_positions[i] > nums[i]) diff += m_last_positions[i] - nums[i];
2255             if (m_last_positions[i] < nums[i]) diff += nums[i] - m_last_positions[i];
2256         }
2257         if (m_last_positions.empty() ||
2258             m_restart_logs >= 20 + m_last_position_log ||
2259             (m_restart_logs >= 6 + m_last_position_log && (!same || diff > 3))) {
2260             m_last_position_log = m_restart_logs;
2261             //           conflicts          restarts          learned            gc               time
2262             //                     decisions         clauses            units          memory
2263             int adjust[9] = { -3,      -3,      -3,      -1,      -3,      -2,   -1,     -2,       -1 };
2264             char const* tag[9]  = { ":conflicts ", ":decisions ", ":restarts ", ":clauses/bin ", ":learned/bin ", ":units ", ":gc ", ":memory ", ":time" };
2265             std::stringstream l1, l2;
2266             l1 << "(sat.stats ";
2267             l2 << "(sat.stats ";
2268             size_t p1 = 11, p2 = 11;
2269             SASSERT(nums.size() == 9);
2270             for (unsigned i = 0; i < 9 && i < nums.size(); ++i) {
2271                 size_t p = nums[i];
2272                 if (i & 0x1) {
2273                     // odd positions
2274                     for (; p2 < p + adjust[i]; ++p2) l2 << " ";
2275                     p2 += strlen(tag[i]);
2276                     l2 << tag[i];
2277                 }
2278                 else {
2279                     // even positions
2280                     for (; p1 < p + adjust[i]; ++p1) l1 << " ";
2281                     p1 += strlen(tag[i]);
2282                     l1 << tag[i];
2283                 }
2284             }
2285             for (; p1 + 2 < str.size(); ++p1) l1 << " ";
2286             for (; p2 + 2 < str.size(); ++p2) l2 << " ";
2287             l1 << ")\n";
2288             l2 << ")\n";
2289             IF_VERBOSE(1, verbose_stream() << l1.str() << l2.str());
2290             m_last_positions.reset();
2291             m_last_positions.append(nums);
2292         }
2293         IF_VERBOSE(1, verbose_stream() << str);
2294     }
2295 
do_restart(bool to_base)2296     void solver::do_restart(bool to_base) {
2297         m_stats.m_restart++;
2298         m_restarts++;
2299         if (m_conflicts_since_init >= m_restart_next_out && get_verbosity_level() >= 1) {
2300             if (0 == m_restart_next_out) {
2301                 m_restart_next_out = 1;
2302             }
2303             else {
2304                 m_restart_next_out = std::min(m_conflicts_since_init + 50000, (3*m_restart_next_out)/2 + 1);
2305             }
2306             log_stats();
2307         }
2308         TRACE("sat", tout << "restart " << restart_level(to_base) << "\n";);
2309         IF_VERBOSE(30, display_status(verbose_stream()););
2310         TRACE("sat", tout << "restart " << restart_level(to_base) << "\n";);
2311         pop_reinit(restart_level(to_base));
2312         set_next_restart();
2313     }
2314 
restart_level(bool to_base)2315     unsigned solver::restart_level(bool to_base) {
2316         SASSERT(!m_case_split_queue.empty());
2317         if (to_base || scope_lvl() == search_lvl())
2318             return scope_lvl() - search_lvl();
2319         else {
2320             bool_var next = m_case_split_queue.min_var();
2321 
2322             // Implementations of Marijn's idea of reusing the
2323             // trail when the next decision literal has lower precedence.
2324             // pop trail from top
2325 #if 0
2326             unsigned n = 0;
2327             do {
2328                 bool_var prev = scope_literal(scope_lvl() - n - 1).var();
2329                 if (m_case_split_queue.more_active(prev, next)) break;
2330                 ++n;
2331             }
2332             while (n < scope_lvl() - search_lvl());
2333             return n;
2334 #endif
2335             // pop trail from bottom
2336             unsigned n = search_lvl();
2337             for (; n < scope_lvl() && m_case_split_queue.more_active(scope_literal(n).var(), next); ++n) {
2338             }
2339             return n - search_lvl();
2340         }
2341     }
2342 
update_activity(bool_var v,double p)2343     void solver::update_activity(bool_var v, double p) {
2344         unsigned new_act = (unsigned) (num_vars() * m_config.m_activity_scale *  p);
2345         set_activity(v, new_act);
2346     }
2347 
set_next_restart()2348     void solver::set_next_restart() {
2349         m_conflicts_since_restart = 0;
2350         switch (m_config.m_restart) {
2351         case RS_GEOMETRIC:
2352             m_restart_threshold = static_cast<unsigned>(m_restart_threshold * m_config.m_restart_factor);
2353             break;
2354         case RS_LUBY:
2355             m_luby_idx++;
2356             m_restart_threshold = m_config.m_restart_initial * get_luby(m_luby_idx);
2357             break;
2358         case RS_EMA:
2359             m_restart_threshold = m_config.m_restart_initial;
2360             break;
2361         case RS_STATIC:
2362             break;
2363         default:
2364             UNREACHABLE();
2365             break;
2366         }
2367         CASSERT("sat_restart", check_invariant());
2368     }
2369 
2370 
2371     // -----------------------
2372     //
2373     // Conflict resolution
2374     //
2375     // -----------------------
2376 
resolve_conflict()2377     bool solver::resolve_conflict() {
2378         while (true) {
2379             lbool r = resolve_conflict_core();
2380             CASSERT("sat_check_marks", check_marks());
2381             // after pop, clauses are reinitialized, this may trigger another conflict.
2382             if (r == l_false)
2383                 return false;
2384             if (!inconsistent())
2385                 return true;
2386         }
2387     }
2388 
2389 
resolve_conflict_core()2390     lbool solver::resolve_conflict_core() {
2391         m_conflicts_since_init++;
2392         m_conflicts_since_restart++;
2393         m_conflicts_since_gc++;
2394         m_stats.m_conflict++;
2395         if (m_step_size > m_config.m_step_size_min) {
2396             m_step_size -= m_config.m_step_size_dec;
2397         }
2398 
2399         bool unique_max;
2400         m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max);
2401         justification js = m_conflict;
2402 
2403         if (m_conflict_lvl <= 1 && tracking_assumptions()) {
2404             TRACE("sat", tout << "unsat core\n";);
2405             resolve_conflict_for_unsat_core();
2406             return l_false;
2407         }
2408 
2409         if (m_conflict_lvl == 0) {
2410             drat_explain_conflict();
2411             if (m_config.m_drat)
2412                 drat_log_clause(0, nullptr, sat::status::redundant());
2413             TRACE("sat", tout << "conflict level is 0\n";);
2414             return l_false;
2415         }
2416 
2417         // force_conflict_analysis is used instead of relying on normal propagation to assign m_not_l
2418         // at the backtracking level. This is the case where the external theories miss propagations
2419         // that only get triggered after decisions.
2420 
2421         if (allow_backtracking() && unique_max && !m_force_conflict_analysis) {
2422             TRACE("sat", tout << "unique max " << js << " " << m_not_l << "\n";);
2423             pop_reinit(m_scope_lvl - m_conflict_lvl + 1);
2424             m_force_conflict_analysis = true;
2425             ++m_stats.m_backtracks;
2426             return l_undef;
2427         }
2428         m_force_conflict_analysis = false;
2429 
2430         updt_phase_of_vars();
2431 
2432         if (m_ext) {
2433             switch (m_ext->resolve_conflict()) {
2434             case l_true:
2435                 learn_lemma_and_backjump();
2436                 return l_undef;
2437             case l_undef:
2438                 break;
2439             case l_false:
2440                 // backjumping was taken care of internally.
2441                 return l_undef;
2442             }
2443         }
2444 
2445         m_lemma.reset();
2446 
2447         unsigned idx = skip_literals_above_conflict_level();
2448 
2449         // save space for first uip
2450         m_lemma.push_back(null_literal);
2451 
2452         TRACE("sat_conflict_detail",
2453               tout << "resolve: " << m_not_l << " "
2454               << " js: " << js
2455               << " idx: " << idx
2456               << " trail: " << m_trail.size()
2457               << " @" << m_conflict_lvl << "\n";);
2458 
2459         unsigned num_marks = 0;
2460         literal consequent = null_literal;
2461         if (m_not_l != null_literal) {
2462             TRACE("sat_conflict_detail", tout << "not_l: " << m_not_l << "\n";);
2463             process_antecedent(m_not_l, num_marks);
2464             consequent = ~m_not_l;
2465         }
2466 
2467         do {
2468             TRACE("sat_conflict_detail", tout << "processing consequent: " << consequent << " @" << (consequent==null_literal?m_conflict_lvl:lvl(consequent)) << "\n";
2469                   tout << "num_marks: " << num_marks << "\n";
2470                   display_justification(tout, js) << "\n";);
2471 
2472             switch (js.get_kind()) {
2473             case justification::NONE:
2474                 break;
2475             case justification::BINARY:
2476                 process_antecedent(~(js.get_literal()), num_marks);
2477                 break;
2478             case justification::TERNARY:
2479                 process_antecedent(~(js.get_literal1()), num_marks);
2480                 process_antecedent(~(js.get_literal2()), num_marks);
2481                 break;
2482             case justification::CLAUSE: {
2483                 clause & c = get_clause(js);
2484                 unsigned i = 0;
2485                 if (consequent != null_literal) {
2486                     SASSERT(c[0] == consequent || c[1] == consequent);
2487                     if (c[0] == consequent) {
2488                         i = 1;
2489                     }
2490                     else {
2491                         process_antecedent(~c[0], num_marks);
2492                         i = 2;
2493                     }
2494                 }
2495                 unsigned sz = c.size();
2496                 for (; i < sz; i++)
2497                     process_antecedent(~c[i], num_marks);
2498                 break;
2499             }
2500             case justification::EXT_JUSTIFICATION: {
2501                 fill_ext_antecedents(consequent, js, false);
2502                 TRACE("sat", tout << "ext antecedents: " << m_ext_antecedents << "\n";);
2503                 for (literal l : m_ext_antecedents)
2504                     process_antecedent(l, num_marks);
2505 
2506 #if 0
2507                 if (m_ext_antecedents.size() <= 1) {
2508                     for (literal& l : m_ext_antecedents)
2509                         l.neg();
2510                     m_ext_antecedents.push_back(consequent);
2511                     mk_clause(m_ext_antecedents.size(), m_ext_antecedents.c_ptr(), sat::status::redundant());
2512                 }
2513 #endif
2514                 break;
2515             }
2516             default:
2517                 UNREACHABLE();
2518                 break;
2519             }
2520 
2521             bool_var c_var;
2522             while (true) {
2523                 consequent = m_trail[idx];
2524                 c_var = consequent.var();
2525                 if (is_marked(c_var)) {
2526                     if (lvl(c_var) == m_conflict_lvl) {
2527                         break;
2528                     }
2529                     SASSERT(lvl(c_var) < m_conflict_lvl);
2530                 }
2531                 CTRACE("sat", idx == 0,
2532                        for (literal lit : m_trail)
2533                            if (is_marked(lit.var()))
2534                                tout << "missed " << lit << "@" << lvl(lit) << "\n";);
2535                 CTRACE("sat", idx == 0, display(tout););
2536                 if (idx == 0)
2537                     IF_VERBOSE(0, verbose_stream() << "num-conflicts: " << m_stats.m_conflict << "\n");
2538                 VERIFY(idx > 0);
2539                 idx--;
2540             }
2541             SASSERT(lvl(consequent) == m_conflict_lvl);
2542             js             = m_justification[c_var];
2543             idx--;
2544             num_marks--;
2545             reset_mark(c_var);
2546 
2547             TRACE("sat", display_justification(tout << consequent << " ", js) << "\n";);
2548         }
2549         while (num_marks > 0);
2550 
2551         m_lemma[0] = ~consequent;
2552         learn_lemma_and_backjump();
2553 
2554         return l_undef;
2555     }
2556 
learn_lemma_and_backjump()2557     void solver::learn_lemma_and_backjump() {
2558         TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
2559 
2560         if (m_lemma.empty()) {
2561             pop_reinit(m_scope_lvl);
2562             mk_clause_core(0, nullptr, sat::status::redundant());
2563             return;
2564         }
2565 
2566         if (m_config.m_minimize_lemmas) {
2567             minimize_lemma();
2568             reset_lemma_var_marks();
2569             if (m_config.m_dyn_sub_res)
2570                 dyn_sub_res();
2571             TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";);
2572         }
2573         else {
2574             reset_lemma_var_marks();
2575         }
2576 
2577         unsigned backtrack_lvl = lvl(m_lemma[0]);
2578         unsigned backjump_lvl  = 0;
2579         for (unsigned i = m_lemma.size(); i-- > 1;) {
2580             unsigned level = lvl(m_lemma[i]);
2581             backjump_lvl = std::max(level, backjump_lvl);
2582         }
2583         // with scope tracking and chronological backtracking,
2584         // consequent may not be at highest decision level.
2585         if (backtrack_lvl < backjump_lvl) {
2586             backtrack_lvl = backjump_lvl;
2587             for (unsigned i = m_lemma.size(); i-- > 1;) {
2588                 if (lvl(m_lemma[i]) == backjump_lvl) {
2589                     TRACE("sat", tout << "swap " << m_lemma[0] << "@" << lvl(m_lemma[0]) << m_lemma[1] << "@" << backjump_lvl << "\n";);
2590                     std::swap(m_lemma[i], m_lemma[0]);
2591                     break;
2592                 }
2593             }
2594         }
2595 
2596         unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.data());
2597         m_fast_glue_avg.update(glue);
2598         m_slow_glue_avg.update(glue);
2599 
2600         // compute whether to use backtracking or backjumping
2601         unsigned num_scopes = m_scope_lvl - backjump_lvl;
2602 
2603         if (use_backjumping(num_scopes)) {
2604             ++m_stats.m_backjumps;
2605             pop_reinit(num_scopes);
2606         }
2607         else {
2608             TRACE("sat", tout << "backtrack " << (m_scope_lvl - backtrack_lvl + 1) << " scopes\n";);
2609             ++m_stats.m_backtracks;
2610             pop_reinit(m_scope_lvl - backtrack_lvl + 1);
2611         }
2612         clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.data(), sat::status::redundant());
2613         if (lemma) {
2614             lemma->set_glue(glue);
2615         }
2616         if (m_par && lemma) {
2617             m_par->share_clause(*this, *lemma);
2618         }
2619         m_lemma.reset();
2620         TRACE("sat_conflict_detail", tout << "consistent " << (!m_inconsistent) << " scopes: " << scope_lvl() << " backtrack: " << backtrack_lvl << " backjump: " << backjump_lvl << "\n";);
2621         decay_activity();
2622         updt_phase_counters();
2623     }
2624 
use_backjumping(unsigned num_scopes) const2625     bool solver::use_backjumping(unsigned num_scopes) const {
2626         return
2627             num_scopes > 0 &&
2628             (num_scopes <= m_config.m_backtrack_scopes || !allow_backtracking());
2629     }
2630 
allow_backtracking() const2631     bool solver::allow_backtracking() const {
2632         return m_conflicts_since_init > m_config.m_backtrack_init_conflicts;
2633     }
2634 
process_antecedent_for_unsat_core(literal antecedent)2635     void solver::process_antecedent_for_unsat_core(literal antecedent) {
2636         bool_var var     = antecedent.var();
2637         SASSERT(var < num_vars());
2638         TRACE("sat", tout << antecedent << " " << (is_marked(var)?"+":"-") << "\n";);
2639         if (!is_marked(var)) {
2640             mark(var);
2641             m_unmark.push_back(var);
2642             if (is_assumption(antecedent)) {
2643                 m_core.push_back(antecedent);
2644             }
2645         }
2646     }
2647 
process_consequent_for_unsat_core(literal consequent,justification const & js)2648     void solver::process_consequent_for_unsat_core(literal consequent, justification const& js) {
2649         TRACE("sat", tout << "processing consequent: ";
2650               if (consequent == null_literal) tout << "null\n";
2651               else tout << consequent << "\n";
2652               display_justification(tout << "js kind: ", js) << "\n";);
2653         switch (js.get_kind()) {
2654         case justification::NONE:
2655             break;
2656         case justification::BINARY:
2657             SASSERT(consequent != null_literal);
2658             process_antecedent_for_unsat_core(~(js.get_literal()));
2659             break;
2660         case justification::TERNARY:
2661             SASSERT(consequent != null_literal);
2662             process_antecedent_for_unsat_core(~(js.get_literal1()));
2663             process_antecedent_for_unsat_core(~(js.get_literal2()));
2664             break;
2665         case justification::CLAUSE: {
2666             clause & c = get_clause(js);
2667             unsigned i = 0;
2668             if (consequent != null_literal) {
2669                 SASSERT(c[0] == consequent || c[1] == consequent);
2670                 if (c[0] == consequent) {
2671                     i = 1;
2672                 }
2673                 else {
2674                     process_antecedent_for_unsat_core(~c[0]);
2675                     i = 2;
2676                 }
2677             }
2678             unsigned sz = c.size();
2679             for (; i < sz; i++)
2680                 process_antecedent_for_unsat_core(~c[i]);
2681             break;
2682         }
2683         case justification::EXT_JUSTIFICATION: {
2684             fill_ext_antecedents(consequent, js, false);
2685             for (literal l : m_ext_antecedents) {
2686                 process_antecedent_for_unsat_core(l);
2687             }
2688             break;
2689         }
2690         default:
2691             UNREACHABLE();
2692             break;
2693         }
2694     }
2695 
resolve_conflict_for_unsat_core()2696     void solver::resolve_conflict_for_unsat_core() {
2697         TRACE("sat_verbose", display(tout);
2698               unsigned level = 0;
2699               for (literal l : m_trail) {
2700                   if (level != lvl(l)) {
2701                       level = lvl(l);
2702                       tout << level << ": ";
2703                   }
2704                   tout << l;
2705                   if (m_mark[l.var()]) {
2706                       tout << "*";
2707                   }
2708                   tout << " ";
2709               }
2710               tout << "\n";
2711               tout << "conflict level: " << m_conflict_lvl << "\n";
2712               );
2713 
2714         m_core.reset();
2715         if (!m_config.m_drat && m_conflict_lvl == 0) {
2716             return;
2717         }
2718         SASSERT(m_unmark.empty());
2719         DEBUG_CODE({
2720                 for (literal lit : m_trail) {
2721                     SASSERT(!is_marked(lit.var()));
2722                 }});
2723 
2724         unsigned old_size = m_unmark.size();
2725         int idx = skip_literals_above_conflict_level();
2726 
2727         literal consequent = m_not_l;
2728         if (m_not_l != null_literal) {
2729             justification js = m_justification[m_not_l.var()];
2730             TRACE("sat", tout << "not_l: " << m_not_l << "\n";
2731                   display_justification(tout, js) << "\n";);
2732 
2733             process_antecedent_for_unsat_core(m_not_l);
2734             if (is_assumption(~m_not_l)) {
2735                 m_core.push_back(~m_not_l);
2736             }
2737             else {
2738                 process_consequent_for_unsat_core(m_not_l, js);
2739             }
2740             consequent = ~m_not_l;
2741         }
2742 
2743         justification js = m_conflict;
2744 
2745         int init_sz = init_trail_size();
2746         while (true) {
2747             process_consequent_for_unsat_core(consequent, js);
2748             while (idx >= init_sz) {
2749                 consequent = m_trail[idx];
2750                 if (is_marked(consequent.var()) && lvl(consequent) == m_conflict_lvl)
2751                     break;
2752                 idx--;
2753             }
2754             if (idx < init_sz) {
2755                 break;
2756             }
2757             SASSERT(lvl(consequent) == m_conflict_lvl);
2758             js = m_justification[consequent.var()];
2759             idx--;
2760         }
2761         reset_unmark(old_size);
2762         if (m_core.size() > 1) {
2763             unsigned j = 0;
2764             for (unsigned i = 0; i < m_core.size(); ++i) {
2765                 if (lvl(m_core[i]) > 0) m_core[j++] = m_core[i];
2766             }
2767             m_core.shrink(j);
2768         }
2769 
2770         if (m_config.m_core_minimize) {
2771             if (m_min_core_valid && m_min_core.size() < m_core.size()) {
2772                 IF_VERBOSE(2, verbose_stream() << "(sat.updating core " << m_min_core.size() << " " << m_core.size() << ")\n";);
2773                 m_core.reset();
2774                 m_core.append(m_min_core);
2775             }
2776             // TBD:
2777             // apply optional clause minimization by detecting subsumed literals.
2778             // initial experiment suggests it has no effect.
2779             m_mus(); // ignore return value on cancelation.
2780             set_model(m_mus.get_model(), !m_mus.get_model().empty());
2781             IF_VERBOSE(2, verbose_stream() << "(sat.core: " << m_core << ")\n";);
2782         }
2783     }
2784 
2785 
get_max_lvl(literal not_l,justification js,bool & unique_max)2786     unsigned solver::get_max_lvl(literal not_l, justification js, bool& unique_max) {
2787         unique_max = true;
2788         unsigned level = 0;
2789 
2790         if (not_l != null_literal) {
2791             level = lvl(not_l);
2792         }
2793 
2794         switch (js.get_kind()) {
2795         case justification::NONE:
2796             level = std::max(level, js.level());
2797             return level;
2798         case justification::BINARY:
2799             level = update_max_level(js.get_literal(), level, unique_max);
2800             return level;
2801         case justification::TERNARY:
2802             level = update_max_level(js.get_literal1(), level, unique_max);
2803             level = update_max_level(js.get_literal2(), level, unique_max);
2804             return level;
2805         case justification::CLAUSE:
2806             for (literal l : get_clause(js))
2807                 level = update_max_level(l, level, unique_max);
2808             return level;
2809         case justification::EXT_JUSTIFICATION:
2810             if (not_l != null_literal)
2811                 not_l.neg();
2812             fill_ext_antecedents(not_l, js, true);
2813             for (literal l : m_ext_antecedents)
2814                 level = update_max_level(l, level, unique_max);
2815             return level;
2816         default:
2817             UNREACHABLE();
2818             return 0;
2819         }
2820     }
2821 
2822     /**
2823        \brief Skip literals from levels above m_conflict_lvl.
2824        It returns an index idx such that lvl(m_trail[idx]) <= m_conflict_lvl, and
2825        for all idx' > idx, lvl(m_trail[idx']) > m_conflict_lvl
2826     */
skip_literals_above_conflict_level()2827     unsigned solver::skip_literals_above_conflict_level() {
2828         unsigned idx = m_trail.size();
2829         if (idx == 0) {
2830             return idx;
2831         }
2832         idx--;
2833         // skip literals from levels above the conflict level
2834         while (lvl(m_trail[idx]) > m_conflict_lvl) {
2835             SASSERT(idx > 0);
2836             idx--;
2837         }
2838         return idx;
2839     }
2840 
process_antecedent(literal antecedent,unsigned & num_marks)2841     void solver::process_antecedent(literal antecedent, unsigned & num_marks) {
2842         bool_var var     = antecedent.var();
2843         unsigned var_lvl = lvl(var);
2844         SASSERT(var < num_vars());
2845         TRACE("sat_verbose", tout << "process " << var << "@" << var_lvl << " marked " << is_marked(var) << " conflict " << m_conflict_lvl << "\n";);
2846         if (!is_marked(var) && var_lvl > 0) {
2847             mark(var);
2848             switch (m_config.m_branching_heuristic) {
2849             case BH_VSIDS:
2850                 inc_activity(var);
2851                 break;
2852             case BH_CHB:
2853                 m_last_conflict[var] = m_stats.m_conflict;
2854                 break;
2855             default:
2856                 break;
2857             }
2858             if (var_lvl == m_conflict_lvl)
2859                 num_marks++;
2860             else
2861                 m_lemma.push_back(~antecedent);
2862         }
2863     }
2864 
2865 
2866     /**
2867        \brief js is an external justification. Collect its antecedents and store at m_ext_antecedents.
2868     */
fill_ext_antecedents(literal consequent,justification js,bool probing)2869     void solver::fill_ext_antecedents(literal consequent, justification js, bool probing) {
2870         SASSERT(js.is_ext_justification());
2871         SASSERT(m_ext);
2872         auto idx = js.get_ext_justification_idx();
2873         m_ext_antecedents.reset();
2874         m_ext->get_antecedents(consequent, idx, m_ext_antecedents, probing);
2875     }
2876 
is_two_phase() const2877     bool solver::is_two_phase() const {
2878         return m_config.m_phase == PS_SAT_CACHING;
2879     }
2880 
is_sat_phase() const2881     bool solver::is_sat_phase() const {
2882         return is_two_phase() && m_search_state == s_sat;
2883     }
2884 
updt_phase_of_vars()2885     void solver::updt_phase_of_vars() {
2886         if (m_config.m_phase == PS_FROZEN)
2887             return;
2888         unsigned from_lvl = m_conflict_lvl;
2889         unsigned head = from_lvl == 0 ? 0 : m_scopes[from_lvl - 1].m_trail_lim;
2890         unsigned sz   = m_trail.size();
2891         for (unsigned i = head; i < sz; i++) {
2892             bool_var v = m_trail[i].var();
2893             TRACE("forget_phase", tout << "forgetting phase of v" << v << "\n";);
2894             m_phase[v] = m_rand() % 2 == 0;
2895         }
2896         if (is_sat_phase() && head >= m_best_phase_size) {
2897             m_best_phase_size = head;
2898             IF_VERBOSE(12, verbose_stream() << "sticky trail: " << head << "\n");
2899             for (unsigned i = 0; i < head; ++i) {
2900                 bool_var v = m_trail[i].var();
2901                 m_best_phase[v] = m_phase[v];
2902             }
2903         }
2904     }
2905 
should_toggle_search_state()2906     bool solver::should_toggle_search_state() {
2907         if (m_search_state == s_unsat) {
2908             m_trail_avg.update(m_trail.size());
2909         }
2910         return
2911             (m_phase_counter >= m_search_next_toggle) &&
2912             (m_search_state == s_sat || m_trail.size() > 0.50*m_trail_avg);
2913     }
2914 
do_toggle_search_state()2915     void solver::do_toggle_search_state() {
2916 
2917         if (is_two_phase()) {
2918             m_best_phase_size = 0;
2919             std::swap(m_fast_glue_backup, m_fast_glue_avg);
2920             std::swap(m_slow_glue_backup, m_slow_glue_avg);
2921             if (m_search_state == s_sat) {
2922                 m_search_unsat_conflicts += m_config.m_search_unsat_conflicts;
2923             }
2924             else {
2925                 m_search_sat_conflicts += m_config.m_search_sat_conflicts;
2926             }
2927         }
2928 
2929         if (m_search_state == s_unsat) {
2930             m_search_state = s_sat;
2931             m_search_next_toggle = m_search_sat_conflicts;
2932         }
2933         else {
2934             m_search_state = s_unsat;
2935             m_search_next_toggle = m_search_unsat_conflicts;
2936         }
2937 
2938         m_phase_counter = 0;
2939     }
2940 
should_rephase()2941     bool solver::should_rephase() {
2942         return m_conflicts_since_init > m_rephase_lim;
2943     }
2944 
do_rephase()2945     void solver::do_rephase() {
2946         switch (m_config.m_phase) {
2947         case PS_ALWAYS_TRUE:
2948             for (auto& p : m_phase) p = true;
2949             break;
2950         case PS_ALWAYS_FALSE:
2951             for (auto& p : m_phase) p = false;
2952             break;
2953         case PS_FROZEN:
2954             break;
2955         case PS_BASIC_CACHING:
2956             switch (m_rephase_lim % 4) {
2957             case 0:
2958                 for (auto& p : m_phase) p = (m_rand() % 2) == 0;
2959                 break;
2960             case 1:
2961                 for (auto& p : m_phase) p = false;
2962                 break;
2963             case 2:
2964                 for (auto& p : m_phase) p = !p;
2965                 break;
2966             default:
2967                 break;
2968             }
2969             break;
2970         case PS_SAT_CACHING:
2971             if (m_search_state == s_sat) {
2972                 for (unsigned i = 0; i < m_phase.size(); ++i) {
2973                     m_phase[i] = m_best_phase[i];
2974                 }
2975             }
2976             break;
2977         case PS_RANDOM:
2978             for (auto& p : m_phase) p = (m_rand() % 2) == 0;
2979             break;
2980         default:
2981             UNREACHABLE();
2982             break;
2983         }
2984         m_rephase_inc += m_config.m_rephase_base;
2985         m_rephase_lim += m_rephase_inc;
2986     }
2987 
should_reorder()2988     bool solver::should_reorder() {
2989         return m_conflicts_since_init > m_reorder_lim;
2990     }
2991 
do_reorder()2992     void solver::do_reorder() {
2993         IF_VERBOSE(1, verbose_stream() << "(reorder)\n");
2994         m_activity_inc = 128;
2995         svector<bool_var> vars;
2996         for (bool_var v = num_vars(); v-- > 0; ) {
2997             if (!was_eliminated(v) && value(v) == l_undef) {
2998                 vars.push_back(v);
2999             }
3000         }
3001 #if 1
3002         //
3003         //   exp(logits[i]) / sum(exp(logits))
3004         // =
3005         //   exp(log(exp(logits[i]) / sum(exp(logits))))
3006         // =
3007         //   exp(log(exp(logits[i])) - log(sum(exp(logits))))
3008         // =
3009         //   exp(logits[i] - lse)
3010         svector<double> logits(vars.size(), 0.0);
3011         double itau = m_config.m_reorder_itau;
3012         double lse = 0;
3013         double mid = m_rand.max_value()/2;
3014         double max = 0;
3015         for (double& f : logits) {
3016             f = itau * (m_rand() - mid)/mid;
3017             if (f > max) max = f;
3018         }
3019         for (double f : logits) {
3020             lse += log(f - max);
3021         }
3022         lse = max + exp(lse);
3023 
3024         for (unsigned i = 0; i < vars.size(); ++i) {
3025             update_activity(vars[i], exp(logits[i] - lse));
3026         }
3027 #else
3028         shuffle(vars.size(), vars.c_ptr(), m_rand);
3029         for (bool_var v : vars) {
3030             update_activity(v, m_rand(10)/10.0);
3031         }
3032 #endif
3033         m_reorder_inc += m_config.m_reorder_base;
3034         m_reorder_lim += m_reorder_inc;
3035     }
3036 
updt_phase_counters()3037     void solver::updt_phase_counters() {
3038         m_phase_counter++;
3039         if (should_toggle_search_state()) {
3040             do_toggle_search_state();
3041         }
3042     }
3043 
3044     /**
3045        \brief Return the number of different levels in lits.
3046        All literals in lits must be assigned.
3047     */
num_diff_levels(unsigned num,literal const * lits)3048     unsigned solver::num_diff_levels(unsigned num, literal const * lits) {
3049         m_diff_levels.reserve(scope_lvl() + 1, false);
3050         unsigned r = 0;
3051         for (unsigned i = 0; i < num; i++) {
3052             SASSERT(value(lits[i]) != l_undef);
3053             unsigned lit_lvl = lvl(lits[i]);
3054             if (!m_diff_levels[lit_lvl]) {
3055                 m_diff_levels[lit_lvl] = true;
3056                 r++;
3057             }
3058         }
3059         // reset m_diff_levels.
3060         for (unsigned i = 0; i < num; i++)
3061             m_diff_levels[lvl(lits[i])] = false;
3062         return r;
3063     }
3064 
num_diff_levels_below(unsigned num,literal const * lits,unsigned max_glue,unsigned & glue)3065     bool solver::num_diff_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue) {
3066         m_diff_levels.reserve(scope_lvl() + 1, false);
3067         glue = 0;
3068         unsigned i = 0;
3069         for (; i < num && glue < max_glue; i++) {
3070             SASSERT(value(lits[i]) != l_undef);
3071             unsigned lit_lvl = lvl(lits[i]);
3072             if (!m_diff_levels[lit_lvl]) {
3073                 m_diff_levels[lit_lvl] = true;
3074                 glue++;
3075             }
3076         }
3077         // reset m_diff_levels.
3078         for (; i-- > 0; )
3079             m_diff_levels[lvl(lits[i])] = false;
3080         return glue < max_glue;
3081     }
3082 
num_diff_false_levels_below(unsigned num,literal const * lits,unsigned max_glue,unsigned & glue)3083     bool solver::num_diff_false_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue) {
3084         m_diff_levels.reserve(scope_lvl() + 1, false);
3085         glue = 0;
3086         unsigned i = 0;
3087         for (; i < num && glue < max_glue; i++) {
3088             if (value(lits[i]) == l_false) {
3089                 unsigned lit_lvl = lvl(lits[i]);
3090                 if (!m_diff_levels[lit_lvl]) {
3091                     m_diff_levels[lit_lvl] = true;
3092                     glue++;
3093                 }
3094             }
3095         }
3096         // reset m_diff_levels.
3097         for (; i-- > 0;) {
3098             literal lit = lits[i];
3099             if (value(lit) == l_false) {
3100                 VERIFY(lvl(lit) < m_diff_levels.size());
3101                 m_diff_levels[lvl(lit)] = false;
3102             }
3103         }
3104         return glue < max_glue;
3105     }
3106 
3107 
3108     /**
3109        \brief Process an antecedent for lemma minimization.
3110     */
process_antecedent_for_minimization(literal antecedent)3111     bool solver::process_antecedent_for_minimization(literal antecedent) {
3112         bool_var var = antecedent.var();
3113         unsigned var_lvl = lvl(var);
3114         if (!is_marked(var) && var_lvl > 0) {
3115             if (m_lvl_set.may_contain(var_lvl)) {
3116                 mark(var);
3117                 m_unmark.push_back(var);
3118                 m_lemma_min_stack.push_back(antecedent);
3119             }
3120             else {
3121                 return false;
3122             }
3123         }
3124         return true;
3125     }
3126 
3127     /**
3128        \brief Return true if lit is implied by other marked literals
3129        and/or literals assigned at the base level.
3130        The set lvl_set is used as an optimization.
3131        The idea is to stop the recursive search with a failure
3132        as soon as we find a literal assigned in a level that is not in lvl_set.
3133     */
implied_by_marked(literal lit)3134     bool solver::implied_by_marked(literal lit) {
3135         m_lemma_min_stack.reset();  // avoid recursive function
3136         m_lemma_min_stack.push_back(lit);
3137         unsigned old_size = m_unmark.size();
3138 
3139         while (!m_lemma_min_stack.empty()) {
3140             lit = m_lemma_min_stack.back();
3141             bool_var var = lit.var();
3142             m_lemma_min_stack.pop_back();
3143             justification const& js   = m_justification[var];
3144             switch(js.get_kind()) {
3145             case justification::NONE:
3146                 // it is a decision variable from a previous scope level
3147                 if (lvl(var) > 0) {
3148                     reset_unmark(old_size);
3149                     return false;
3150                 }
3151                 break;
3152             case justification::BINARY:
3153                 if (!process_antecedent_for_minimization(~(js.get_literal()))) {
3154                     reset_unmark(old_size);
3155                     return false;
3156                 }
3157                 break;
3158             case justification::TERNARY:
3159                 if (!process_antecedent_for_minimization(~(js.get_literal1())) ||
3160                     !process_antecedent_for_minimization(~(js.get_literal2()))) {
3161                     reset_unmark(old_size);
3162                     return false;
3163                 }
3164                 break;
3165             case justification::CLAUSE: {
3166                 clause & c = get_clause(js);
3167                 unsigned i   = 0;
3168                 if (c[0].var() == var) {
3169                     i = 1;
3170                 }
3171                 else {
3172                     SASSERT(c[1].var() == var);
3173                     if (!process_antecedent_for_minimization(~c[0])) {
3174                         reset_unmark(old_size);
3175                         return false;
3176                     }
3177                     i = 2;
3178                 }
3179                 unsigned sz = c.size();
3180                 for (; i < sz; i++) {
3181                     if (!process_antecedent_for_minimization(~c[i])) {
3182                         reset_unmark(old_size);
3183                         return false;
3184                     }
3185                 }
3186                 break;
3187             }
3188             case justification::EXT_JUSTIFICATION: {
3189                 literal consequent(var, value(var) == l_false);
3190                 fill_ext_antecedents(consequent, js, false);
3191                 for (literal l : m_ext_antecedents) {
3192                     if (!process_antecedent_for_minimization(l)) {
3193                         reset_unmark(old_size);
3194                         return false;
3195                     }
3196                 }
3197                 break;
3198             }
3199             default:
3200                 UNREACHABLE();
3201                 break;
3202             }
3203             TRACE("sat_conflict",
3204                   display_justification(tout << var << " ",js) << "\n";);
3205         }
3206         return true;
3207     }
3208 
3209     /**
3210        \brief Restore the size of m_unmark to old_size, and
3211        unmark variables at positions [old_size, m_unmark.size()).
3212     */
reset_unmark(unsigned old_size)3213     void solver::reset_unmark(unsigned old_size) {
3214         unsigned curr_size = m_unmark.size();
3215         for(unsigned i = old_size; i < curr_size; i++)
3216             reset_mark(m_unmark[i]);
3217         m_unmark.shrink(old_size);
3218     }
3219 
3220     /**
3221        \brief Store the levels of the literals at m_lemma in the
3222        approximated set m_lvl_set.
3223     */
updt_lemma_lvl_set()3224     void solver::updt_lemma_lvl_set() {
3225         m_lvl_set.reset();
3226         for (literal l : m_lemma)
3227             m_lvl_set.insert(lvl(l));
3228     }
3229 
3230     /**
3231        \brief Minimize lemma using binary resolution
3232     */
minimize_lemma_binres()3233     bool solver::minimize_lemma_binres() {
3234         SASSERT(!m_lemma.empty());
3235         SASSERT(m_unmark.empty());
3236         unsigned sz   = m_lemma.size();
3237         unsigned num_reduced = 0;
3238         for (unsigned i = 1; i < sz; ++i) {
3239             mark_lit(m_lemma[i]);
3240         }
3241         watch_list const& wlist = get_wlist(m_lemma[0]);
3242         for (watched const& w : wlist) {
3243             if (w.is_binary_clause() && is_marked_lit(w.get_literal())) {
3244                 unmark_lit(~w.get_literal());
3245                 num_reduced++;
3246             }
3247         }
3248         if (num_reduced > 0) {
3249             unsigned j = 1;
3250             for (unsigned i = 1; i < sz; ++i) {
3251                 if (is_marked_lit(m_lemma[i])) {
3252                     m_lemma[j++] = m_lemma[i];
3253                     unmark_lit(m_lemma[i]);
3254                 }
3255             }
3256             m_lemma.shrink(j);
3257         }
3258 
3259         return num_reduced > 0;
3260     }
3261 
3262     /**
3263        \brief Minimize the number of literals in m_lemma. The main idea is to remove
3264        literals that are implied by other literals in m_lemma and/or literals
3265        assigned at level 0.
3266     */
minimize_lemma()3267     bool solver::minimize_lemma() {
3268         SASSERT(!m_lemma.empty());
3269         SASSERT(m_unmark.empty());
3270         updt_lemma_lvl_set();
3271 
3272         unsigned sz   = m_lemma.size();
3273         unsigned i    = 1; // the first literal is the FUIP
3274         unsigned j    = 1;
3275         for (; i < sz; i++) {
3276             literal l = m_lemma[i];
3277             if (implied_by_marked(l)) {
3278                 m_unmark.push_back(l.var());
3279             }
3280             else {
3281                 m_lemma[j++] = m_lemma[i];
3282             }
3283         }
3284 
3285         reset_unmark(0);
3286         m_lemma.shrink(j);
3287         m_stats.m_minimized_lits += sz - j;
3288         return j < sz;
3289     }
3290 
3291     /**
3292        \brief Reset the mark of the variables in the current lemma.
3293     */
reset_lemma_var_marks()3294     void solver::reset_lemma_var_marks() {
3295         if (m_config.m_branching_heuristic == BH_VSIDS) {
3296             update_lrb_reasoned();
3297         }
3298         literal_vector::iterator it  = m_lemma.begin();
3299         literal_vector::iterator end = m_lemma.end();
3300         SASSERT(!is_marked((*it).var()));
3301         ++it;
3302         for(; it != end; ++it) {
3303             bool_var var = (*it).var();
3304             reset_mark(var);
3305         }
3306     }
3307 
update_lrb_reasoned()3308     void solver::update_lrb_reasoned() {
3309         unsigned sz = m_lemma.size();
3310         SASSERT(!is_marked(m_lemma[0].var()));
3311         mark(m_lemma[0].var());
3312         for (unsigned i = m_lemma.size(); i-- > 0; ) {
3313             justification js = m_justification[m_lemma[i].var()];
3314             switch (js.get_kind()) {
3315             case justification::NONE:
3316                 break;
3317             case justification::BINARY:
3318                 update_lrb_reasoned(js.get_literal());
3319                 break;
3320             case justification::TERNARY:
3321                 update_lrb_reasoned(js.get_literal1());
3322                 update_lrb_reasoned(js.get_literal2());
3323                 break;
3324             case justification::CLAUSE: {
3325                 clause & c = get_clause(js);
3326                 for (literal l : c) {
3327                     update_lrb_reasoned(l);
3328                 }
3329                 break;
3330             }
3331             case justification::EXT_JUSTIFICATION: {
3332                 fill_ext_antecedents(~m_lemma[i], js, true);
3333                 for (literal l : m_ext_antecedents) {
3334                     update_lrb_reasoned(l);
3335                 }
3336                 break;
3337             }
3338             }
3339         }
3340         reset_mark(m_lemma[0].var());
3341         for (unsigned i = m_lemma.size(); i-- > sz; ) {
3342             reset_mark(m_lemma[i].var());
3343         }
3344         m_lemma.shrink(sz);
3345     }
3346 
update_lrb_reasoned(literal lit)3347     void solver::update_lrb_reasoned(literal lit) {
3348         bool_var v = lit.var();
3349         if (!is_marked(v)) {
3350             mark(v);
3351             m_reasoned[v]++;
3352             inc_activity(v);
3353             m_lemma.push_back(lit);
3354         }
3355     }
3356 
3357     /**
3358        \brief Apply dynamic subsumption resolution to new lemma.
3359        Only binary and ternary clauses are used.
3360     */
dyn_sub_res()3361     bool solver::dyn_sub_res() {
3362         unsigned sz = m_lemma.size();
3363         for (unsigned i = 0; i < sz; i++) {
3364             mark_lit(m_lemma[i]);
3365         }
3366 
3367         literal l0 = m_lemma[0];
3368         // l0 is the FUIP, and we never remove the FUIP.
3369         //
3370         // In the following loop, we use unmark_lit(l) to remove a
3371         // literal from m_lemma.
3372 
3373         for (unsigned i = 0; i < sz; i++) {
3374             literal l = m_lemma[i];
3375             if (!is_marked_lit(l))
3376                 continue; // literal was eliminated
3377             // first use watch lists
3378             watch_list const & wlist = get_wlist(~l);
3379             for (watched const& w : wlist) {
3380                 // In this for-loop, the conditions l0 != ~l2 and l0 != ~l3
3381                 // are not really needed if the solver does not miss unit propagations.
3382                 // However, we add them anyway because we don't want to rely on this
3383                 // property of the propagator.
3384                 // For example, if this property is relaxed in the future, then the code
3385                 // without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP
3386                 if (w.is_binary_clause()) {
3387                     literal l2 = w.get_literal();
3388                     if (is_marked_lit(~l2) && l0 != ~l2) {
3389                         // eliminate ~l2 from lemma because we have the clause l \/ l2
3390                         unmark_lit(~l2);
3391                     }
3392                 }
3393                 else if (w.is_ternary_clause()) {
3394                     literal l2 = w.get_literal1();
3395                     literal l3 = w.get_literal2();
3396                     if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) {
3397                         // eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3
3398                         unmark_lit(~l3);
3399                     }
3400                     else if (is_marked_lit(~l2) && is_marked_lit(l3) && l0 != ~l2) {
3401                         // eliminate ~l2 from lemma because we have the clause l \/ l2 \/ l3
3402                         unmark_lit(~l2);
3403                     }
3404                 }
3405                 else {
3406                     // May miss some binary/ternary clauses, but that is ok.
3407                     // I sort the watch lists at every simplification round.
3408                     break;
3409                 }
3410             }
3411             // try to use cached implication if available
3412             literal_vector * implied_lits = m_probing.cached_implied_lits(~l);
3413             if (implied_lits) {
3414                 for (literal l2 : *implied_lits) {
3415                     // Here, we must check l0 != ~l2.
3416                     // l \/ l2 is an implied binary clause.
3417                     // However, it may have been deduced using a lemma that has been deleted.
3418                     // For example, consider the following sequence of events:
3419                     //
3420                     // 1. Initial clause database:
3421                     //
3422                     //    l  \/ ~p1
3423                     //    p1 \/ ~p2
3424                     //    p2 \/ ~p3
3425                     //    p3 \/ ~p4
3426                     //    q1  \/ q2  \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
3427                     //    q1  \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
3428                     //    ~q1 \/ q2  \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
3429                     //    ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
3430                     //    ...
3431                     //
3432                     // 2. Now suppose we learned the lemma
3433                     //
3434                     //    p1 \/ p2 \/ p3 \/ p4 \/ l2   (*)
3435                     //
3436                     // 3. Probing is executed and we notice hat (~l => l2) when we assign l to false.
3437                     //    That is, l \/ l2 is an implied clause. Note that probing does not add
3438                     //    this clause to the clause database (there are too many).
3439                     //
3440                     // 4. Lemma (*) is deleted (garbage collected).
3441                     //
3442                     // 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP,
3443                     //    but l2 is not since the lemma (*) was deleted.
3444                     //
3445                     //    Probing module still "knows" that l \/ l2 is valid binary clause
3446                     //
3447                     // 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l.
3448                     //    If we remove l0 != ~l2 may try to delete the FUIP.
3449                     if (is_marked_lit(~l2) && l0 != ~l2) {
3450                         // eliminate ~l2 from lemma because we have the clause l \/ l2
3451                         unmark_lit(~l2);
3452                     }
3453                 }
3454             }
3455         }
3456 
3457         // can't eliminat FUIP
3458         SASSERT(is_marked_lit(m_lemma[0]));
3459 
3460         unsigned j = 0;
3461         for (unsigned i = 0; i < sz; i++) {
3462             literal l = m_lemma[i];
3463             if (is_marked_lit(l)) {
3464                 unmark_lit(l);
3465                 m_lemma[j] = l;
3466                 j++;
3467             }
3468         }
3469 
3470         m_stats.m_dyn_sub_res += sz - j;
3471 
3472         SASSERT(j >= 1);
3473         m_lemma.shrink(j);
3474         return j < sz;
3475     }
3476 
3477 
3478     // -----------------------
3479     //
3480     // Backtracking
3481     //
3482     // -----------------------
push()3483     void solver::push() {
3484         SASSERT(!inconsistent());
3485         TRACE("sat_verbose", tout << "q:" << m_qhead << " trail: " << m_trail.size() << "\n";);
3486         SASSERT(m_qhead == m_trail.size());
3487         m_scopes.push_back(scope());
3488         scope & s = m_scopes.back();
3489         m_scope_lvl++;
3490         s.m_trail_lim = m_trail.size();
3491         s.m_clauses_to_reinit_lim = m_clauses_to_reinit.size();
3492         s.m_inconsistent = m_inconsistent;
3493         if (m_ext) {
3494             m_vars_lim.push(m_active_vars.size());
3495             m_ext->push();
3496         }
3497     }
3498 
pop_reinit(unsigned num_scopes)3499     void solver::pop_reinit(unsigned num_scopes) {
3500         pop(num_scopes);
3501         exchange_par();
3502         reinit_assumptions();
3503         m_stats.m_units = init_trail_size();
3504     }
3505 
pop_vars(unsigned num_scopes)3506     void solver::pop_vars(unsigned num_scopes) {
3507         //integrity_checker check(*this);
3508         //check.check_reinit_stack();
3509         m_vars_to_reinit.reset();
3510         unsigned old_num_vars = m_vars_lim.pop(num_scopes);
3511         if (old_num_vars == m_active_vars.size())
3512             return;
3513         unsigned free_vars_head = m_free_vars.size();
3514         unsigned sz = m_active_vars.size(), j = old_num_vars;
3515         unsigned new_lvl = m_scopes.size() - num_scopes;
3516 
3517         gc_reinit_stack(num_scopes);
3518 
3519         // check.check_reinit_stack();
3520         init_visited();
3521         unsigned old_sz = m_scopes[new_lvl].m_clauses_to_reinit_lim;
3522         for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; ) {
3523             clause_wrapper const& cw = m_clauses_to_reinit[i];
3524             for (unsigned j = cw.size(); j-- > 0; )
3525                 mark_visited(cw[j].var());
3526         }
3527         for (literal lit : m_lemma)
3528             mark_visited(lit.var());
3529 
3530         auto is_active = [&](bool_var v) {
3531             return value(v) != l_undef && lvl(v) <= new_lvl;
3532         };
3533 
3534         for (unsigned i = old_num_vars; i < sz; ++i) {
3535             bool_var v = m_active_vars[i];
3536             if (is_visited(v) || is_active(v)) {
3537                 m_vars_to_reinit.push_back(v);
3538                 m_active_vars[j++] = v;
3539                 m_var_scope[v] = new_lvl;
3540             }
3541             else {
3542                 set_eliminated(v, true);
3543                 if (!is_external(v) || true) {
3544                     m_free_vars.push_back(v);
3545                 }
3546             }
3547         }
3548         m_active_vars.shrink(j);
3549 
3550         auto cleanup_watch = [&](literal lit) {
3551             for (auto const& w : get_wlist(lit)) {
3552                 IF_VERBOSE(0, verbose_stream() << "cleanup: " << lit << " " << w.is_binary_clause() << "\n");
3553             }
3554         };
3555         for (unsigned i = m_free_vars.size(); i-- > free_vars_head; ) {
3556             bool_var v = m_free_vars[i];
3557             cleanup_watch(literal(v, false));
3558             cleanup_watch(literal(v, true));
3559 
3560         }
3561         TRACE("sat",
3562             tout << "clauses to reinit: " << (m_clauses_to_reinit.size() - old_sz) << "\n";
3563             tout << "new level:         " << new_lvl << "\n";
3564             tout << "vars to reinit:    " << m_vars_to_reinit << "\n";
3565             tout << "free vars:         " << bool_var_vector(m_free_vars.size() - free_vars_head, m_free_vars.data() + free_vars_head) << "\n";
3566             for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; )
3567                 tout << "reinit:           " << m_clauses_to_reinit[i] << "\n";
3568             display(tout););
3569     }
3570 
shrink_vars(unsigned v)3571     void solver::shrink_vars(unsigned v) {
3572         unsigned j = 0;
3573         for (bool_var w : m_free_vars)
3574             if (w < v)
3575                 m_free_vars[j++] = w;
3576         m_free_vars.shrink(j);
3577 
3578         for (bool_var w = m_justification.size(); w-- > v;) {
3579             m_case_split_queue.del_var_eh(w);
3580             m_probing.reset_cache(literal(w, true));
3581             m_probing.reset_cache(literal(w, false));
3582         }
3583         m_watches.shrink(2*v);
3584         m_assignment.shrink(2*v);
3585         m_justification.shrink(v);
3586         m_decision.shrink(v);
3587         m_eliminated.shrink(v);
3588         m_external.shrink(v);
3589         m_var_scope.shrink(v);
3590         m_touched.shrink(v);
3591         m_activity.shrink(v);
3592         m_mark.shrink(v);
3593         m_lit_mark.shrink(2*v);
3594         m_phase.shrink(v);
3595         m_best_phase.shrink(v);
3596         m_prev_phase.shrink(v);
3597         m_assigned_since_gc.shrink(v);
3598         m_simplifier.reset_todos();
3599     }
3600 
pop(unsigned num_scopes)3601     void solver::pop(unsigned num_scopes) {
3602         if (num_scopes == 0)
3603             return;
3604         unsigned free_vars_head = m_free_vars.size();
3605         if (m_ext) {
3606             pop_vars(num_scopes);
3607             m_ext->pop(num_scopes);
3608         }
3609         SASSERT(num_scopes <= scope_lvl());
3610         unsigned new_lvl = scope_lvl() - num_scopes;
3611         scope & s        = m_scopes[new_lvl];
3612         m_inconsistent   = false; // TBD: use model seems to make this redundant: s.m_inconsistent;
3613         unassign_vars(s.m_trail_lim, new_lvl);
3614         for (unsigned i = m_free_vars.size(); i-- > free_vars_head; )
3615             m_case_split_queue.del_var_eh(m_free_vars[i]);
3616         m_scope_lvl -= num_scopes;
3617         reinit_clauses(s.m_clauses_to_reinit_lim);
3618         m_scopes.shrink(new_lvl);
3619         if (m_ext)
3620             m_ext->pop_reinit();
3621     }
3622 
unassign_vars(unsigned old_sz,unsigned new_lvl)3623     void solver::unassign_vars(unsigned old_sz, unsigned new_lvl) {
3624         SASSERT(old_sz <= m_trail.size());
3625         SASSERT(m_replay_assign.empty());
3626         for (unsigned i = m_trail.size(); i-- > old_sz; ) {
3627             literal l  = m_trail[i];
3628             bool_var v = l.var();
3629             if (lvl(v) <= new_lvl) {
3630                 m_replay_assign.push_back(l);
3631                 continue;
3632             }
3633             m_assignment[l.index()]    = l_undef;
3634             m_assignment[(~l).index()] = l_undef;
3635             SASSERT(value(v) == l_undef);
3636             m_case_split_queue.unassign_var_eh(v);
3637             if (m_config.m_anti_exploration) {
3638                 m_canceled[v] = m_stats.m_conflict;
3639             }
3640         }
3641         m_trail.shrink(old_sz);
3642         m_qhead = m_trail.size();
3643         if (!m_replay_assign.empty()) IF_VERBOSE(20, verbose_stream() << "replay assign: " << m_replay_assign.size() << "\n");
3644         CTRACE("sat", !m_replay_assign.empty(), tout << "replay-assign: " << m_replay_assign << "\n";);
3645         for (unsigned i = m_replay_assign.size(); i-- > 0; ) {
3646             literal lit = m_replay_assign[i];
3647             m_trail.push_back(lit);
3648         }
3649 
3650         m_replay_assign.reset();
3651     }
3652 
reinit_clauses(unsigned old_sz)3653     void solver::reinit_clauses(unsigned old_sz) {
3654         unsigned sz = m_clauses_to_reinit.size();
3655         SASSERT(old_sz <= sz);
3656         unsigned j = old_sz;
3657         for (unsigned i = old_sz; i < sz; i++) {
3658             clause_wrapper cw = m_clauses_to_reinit[i];
3659             bool reinit = false;
3660             if (cw.is_binary()) {
3661                 if (propagate_bin_clause(cw[0], cw[1]) && !at_base_lvl())
3662                     m_clauses_to_reinit[j++] = cw;
3663                 else if (has_variables_to_reinit(cw[0], cw[1]))
3664                     m_clauses_to_reinit[j++] = cw;
3665             }
3666             else {
3667                 clause & c = *(cw.get_clause());
3668                 if (ENABLE_TERNARY && c.size() == 3) {
3669                     if (!at_base_lvl() && propagate_ter_clause(c))
3670                         m_clauses_to_reinit[j++] = cw;
3671                     else if (has_variables_to_reinit(c))
3672                         m_clauses_to_reinit[j++] = cw;
3673                     else
3674                         c.set_reinit_stack(false);
3675                     continue;
3676                 }
3677                 detach_clause(c);
3678                 attach_clause(c, reinit);
3679                 if (!at_base_lvl() && reinit)
3680                     // clause propagated literal, must keep it in the reinit stack.
3681                     m_clauses_to_reinit[j++] = cw;
3682                 else if (has_variables_to_reinit(c))
3683                     m_clauses_to_reinit[j++] = cw;
3684                 else
3685                     c.set_reinit_stack(false);
3686             }
3687         }
3688         m_clauses_to_reinit.shrink(j);
3689     }
3690 
3691     //
3692     // All new clauses that are added to the solver
3693     // are relative to the user-scope literals.
3694     //
3695 
user_push()3696     void solver::user_push() {
3697         pop_to_base_level();
3698         m_free_var_freeze.push_back(m_free_vars);
3699         m_free_vars.reset(); // resetting free_vars forces new variables to be assigned above new_v
3700         bool_var new_v = mk_var(true, false);
3701         literal lit = literal(new_v, false);
3702         m_user_scope_literals.push_back(lit);
3703         m_cut_simplifier = nullptr; // for simplicity, wipe it out
3704         if (m_ext)
3705             m_ext->user_push();
3706         TRACE("sat", tout << "user_push: " << lit << "\n";);
3707     }
3708 
user_pop(unsigned num_scopes)3709     void solver::user_pop(unsigned num_scopes) {
3710         unsigned old_sz = m_user_scope_literals.size() - num_scopes;
3711         bool_var max_var = m_user_scope_literals[old_sz].var();
3712         m_user_scope_literals.shrink(old_sz);
3713 
3714         pop_to_base_level();
3715         if (m_ext)
3716             m_ext->user_pop(num_scopes);
3717 
3718         gc_vars(max_var);
3719         TRACE("sat", display(tout););
3720 
3721         m_qhead = 0;
3722         unsigned j = 0;
3723         for (bool_var v : m_free_vars)
3724             if (v < max_var)
3725                 m_free_vars[j++] = v;
3726         m_free_vars.shrink(j);
3727         m_free_vars.append(m_free_var_freeze[old_sz]);
3728         m_free_var_freeze.shrink(old_sz);
3729         scoped_suspend_rlimit _sp(m_rlimit);
3730         propagate(false);
3731     }
3732 
pop_to_base_level()3733     void solver::pop_to_base_level() {
3734         reset_assumptions();
3735         pop(scope_lvl());
3736     }
3737 
3738     // -----------------------
3739     //
3740     // Misc
3741     //
3742     // -----------------------
3743 
updt_params(params_ref const & p)3744     void solver::updt_params(params_ref const & p) {
3745         m_params.append(p);
3746         m_config.updt_params(p);
3747         m_simplifier.updt_params(p);
3748         m_asymm_branch.updt_params(p);
3749         m_probing.updt_params(p);
3750         m_scc.updt_params(p);
3751         m_rand.set_seed(m_config.m_random_seed);
3752         m_step_size = m_config.m_step_size_init;
3753         m_drat.updt_config();
3754         m_fast_glue_avg.set_alpha(m_config.m_fast_glue_avg);
3755         m_slow_glue_avg.set_alpha(m_config.m_slow_glue_avg);
3756         m_fast_glue_backup.set_alpha(m_config.m_fast_glue_avg);
3757         m_slow_glue_backup.set_alpha(m_config.m_slow_glue_avg);
3758         m_trail_avg.set_alpha(m_config.m_slow_glue_avg);
3759 
3760         if (m_config.m_cut_simplify && !m_cut_simplifier && m_user_scope_literals.empty()) {
3761             m_cut_simplifier = alloc(cut_simplifier, *this);
3762         }
3763     }
3764 
collect_param_descrs(param_descrs & d)3765     void solver::collect_param_descrs(param_descrs & d) {
3766         config::collect_param_descrs(d);
3767         simplifier::collect_param_descrs(d);
3768         asymm_branch::collect_param_descrs(d);
3769         probing::collect_param_descrs(d);
3770         scc::collect_param_descrs(d);
3771     }
3772 
collect_statistics(statistics & st) const3773     void solver::collect_statistics(statistics & st) const {
3774         m_stats.collect_statistics(st);
3775         m_cleaner.collect_statistics(st);
3776         m_simplifier.collect_statistics(st);
3777         m_scc.collect_statistics(st);
3778         m_asymm_branch.collect_statistics(st);
3779         m_probing.collect_statistics(st);
3780         if (m_ext) m_ext->collect_statistics(st);
3781         if (m_local_search) m_local_search->collect_statistics(st);
3782         if (m_cut_simplifier) m_cut_simplifier->collect_statistics(st);
3783         st.copy(m_aux_stats);
3784     }
3785 
reset_statistics()3786     void solver::reset_statistics() {
3787         m_stats.reset();
3788         m_cleaner.reset_statistics();
3789         m_simplifier.reset_statistics();
3790         m_asymm_branch.reset_statistics();
3791         m_probing.reset_statistics();
3792         m_aux_stats.reset();
3793     }
3794 
3795     // -----------------------
3796     //
3797     // Activity related stuff
3798     //
3799     // -----------------------
3800 
rescale_activity()3801     void solver::rescale_activity() {
3802         SASSERT(m_config.m_branching_heuristic == BH_VSIDS);
3803         for (unsigned& act : m_activity) {
3804             act >>= 14;
3805         }
3806         m_activity_inc >>= 14;
3807     }
3808 
update_chb_activity(bool is_sat,unsigned qhead)3809     void solver::update_chb_activity(bool is_sat, unsigned qhead) {
3810         SASSERT(m_config.m_branching_heuristic == BH_CHB);
3811         double multiplier = m_config.m_reward_offset * (is_sat ? m_config.m_reward_multiplier : 1.0);
3812         for (unsigned i = qhead; i < m_trail.size(); ++i) {
3813             auto v = m_trail[i].var();
3814             auto d = m_stats.m_conflict - m_last_conflict[v] + 1;
3815             if (d == 0) d = 1;
3816             auto reward = multiplier / d;
3817             auto activity = m_activity[v];
3818             set_activity(v, static_cast<unsigned>(m_step_size * reward + ((1.0 - m_step_size) * activity)));
3819         }
3820     }
3821 
move_to_front(bool_var b)3822     void solver::move_to_front(bool_var b) {
3823         if (b >= num_vars())
3824             return;
3825         bool_var next = m_case_split_queue.min_var();
3826         auto next_act = m_activity[next];
3827         set_activity(b, next_act + 1);
3828     }
3829 
3830     // -----------------------
3831     //
3832     // Iterators
3833     //
3834     // -----------------------
collect_bin_clauses(svector<bin_clause> & r,bool redundant,bool learned_only) const3835     void solver::collect_bin_clauses(svector<bin_clause> & r, bool redundant, bool learned_only) const {
3836         SASSERT(redundant || !learned_only);
3837         unsigned sz = m_watches.size();
3838         for (unsigned l_idx = 0; l_idx < sz; l_idx++) {
3839             literal l = to_literal(l_idx);
3840             l.neg();
3841             for (watched const& w : m_watches[l_idx]) {
3842                 if (!w.is_binary_clause())
3843                     continue;
3844                 if (!redundant && w.is_learned())
3845                     continue;
3846                 else if (redundant && learned_only && !w.is_learned())
3847                     continue;
3848                 literal l2 = w.get_literal();
3849                 if (l.index() > l2.index())
3850                     continue;
3851                 TRACE("cleanup_bug", tout << "collected: " << l << " " << l2 << "\n";);
3852                 r.push_back(bin_clause(l, l2));
3853             }
3854         }
3855     }
3856 
3857     // -----------------------
3858     //
3859     // Debugging
3860     //
3861     // -----------------------
check_invariant() const3862     bool solver::check_invariant() const {
3863         if (!m_rlimit.inc()) return true;
3864         integrity_checker checker(*this);
3865         VERIFY(checker());
3866         VERIFY(!m_ext || m_ext->validate());
3867         return true;
3868     }
3869 
check_marks() const3870     bool solver::check_marks() const {
3871         for (bool_var v = 0; v < num_vars(); v++) {
3872             SASSERT(!is_marked(v));
3873         }
3874         return true;
3875     }
3876 
display_model(std::ostream & out) const3877     std::ostream& solver::display_model(std::ostream& out) const {
3878         unsigned num = num_vars();
3879         for (bool_var v = 0; v < num; v++) {
3880             out << v << ": " << m_model[v] << "\n";
3881         }
3882         return out;
3883 }
3884 
display_binary(std::ostream & out) const3885     void solver::display_binary(std::ostream & out) const {
3886         unsigned sz = m_watches.size();
3887         for (unsigned l_idx = 0; l_idx < sz; l_idx++) {
3888             literal l = to_literal(l_idx);
3889             l.neg();
3890             for (watched const& w : m_watches[l_idx]) {
3891                 if (!w.is_binary_clause())
3892                     continue;
3893                 literal l2 = w.get_literal();
3894                 if (l.index() > l2.index())
3895                     continue;
3896                 out << "(" << l << " " << l2 << ")";
3897                 if (w.is_learned()) out << "*";
3898                 out << "\n";
3899             }
3900         }
3901     }
3902 
display_units(std::ostream & out) const3903     void solver::display_units(std::ostream & out) const {
3904         unsigned level = 0;
3905         for (literal lit : m_trail) {
3906             if (lvl(lit) > level) {
3907                 level = lvl(lit);
3908                 out << level << ": ";
3909             }
3910             else {
3911                 out << "    ";
3912             }
3913             out << lit << " ";
3914             if (lvl(lit) < level) {
3915                 out << "@" << lvl(lit) << " ";
3916             }
3917             display_justification(out, m_justification[lit.var()]) << "\n";
3918         }
3919     }
3920 
display(std::ostream & out) const3921     void solver::display(std::ostream & out) const {
3922         out << "(sat\n";
3923         display_units(out);
3924         display_binary(out);
3925         out << m_clauses << m_learned;
3926         if (m_ext) {
3927             m_ext->display(out);
3928         }
3929         out << ")\n";
3930     }
3931 
display_justification(std::ostream & out,justification const & js) const3932     std::ostream& solver::display_justification(std::ostream & out, justification const& js) const {
3933         switch (js.get_kind()) {
3934         case justification::NONE:
3935             out << "none @" << js.level();
3936             break;
3937         case justification::BINARY:
3938             out << "binary " << js.get_literal() << "@" << lvl(js.get_literal());
3939             break;
3940         case justification::TERNARY:
3941             out << "ternary " << js.get_literal1() << "@" << lvl(js.get_literal1()) << " ";
3942             out << js.get_literal2() << "@" << lvl(js.get_literal2());
3943             break;
3944         case justification::CLAUSE: {
3945             out << "(";
3946             bool first = true;
3947             for (literal l : get_clause(js)) {
3948                 if (first) first = false; else out << " ";
3949                 out << l << "@" << lvl(l);
3950             }
3951             out << ")";
3952             break;
3953         }
3954         case justification::EXT_JUSTIFICATION:
3955             if (m_ext)
3956                 m_ext->display_justification(out << "ext ", js.get_ext_justification_idx());
3957             break;
3958         default:
3959             break;
3960         }
3961         return out;
3962     }
3963 
3964 
num_clauses() const3965     unsigned solver::num_clauses() const {
3966         unsigned num_cls = m_trail.size(); // units;
3967         unsigned l_idx = 0;
3968         for (auto const& wl : m_watches) {
3969             literal l = ~to_literal(l_idx++);
3970             for (auto const& w : wl) {
3971                 if (w.is_binary_clause() && l.index() < w.get_literal().index())
3972                     num_cls++;
3973             }
3974         }
3975         return num_cls + m_clauses.size() + m_learned.size();
3976     }
3977 
num_binary(unsigned & given,unsigned & redundant) const3978     void solver::num_binary(unsigned& given, unsigned& redundant) const {
3979         given = redundant = 0;
3980         unsigned l_idx = 0;
3981         for (auto const& wl : m_watches) {
3982             literal l = ~to_literal(l_idx++);
3983             for (auto const& w : wl) {
3984                 if (w.is_binary_clause() && l.index() < w.get_literal().index()) {
3985                     if (w.is_learned()) ++redundant; else ++given;
3986                 }
3987             }
3988         }
3989     }
3990 
display_dimacs(std::ostream & out) const3991     void solver::display_dimacs(std::ostream & out) const {
3992         out << "p cnf " << num_vars() << " " << num_clauses() << "\n";
3993         for (literal lit : m_trail) {
3994             out << dimacs_lit(lit) << " 0\n";
3995         }
3996         unsigned l_idx = 0;
3997         for (auto const& wlist : m_watches) {
3998             literal l = ~to_literal(l_idx++);
3999             for (auto const& w : wlist) {
4000                 if (w.is_binary_clause() && l.index() < w.get_literal().index())
4001                     out << dimacs_lit(l) << " " << dimacs_lit(w.get_literal()) << " 0\n";
4002             }
4003         }
4004         clause_vector const * vs[2] = { &m_clauses, &m_learned };
4005         for (unsigned i = 0; i < 2; i++) {
4006             clause_vector const & cs = *(vs[i]);
4007             for (auto cp : cs) {
4008                 for (literal l : *cp) {
4009                     out << dimacs_lit(l) << " ";
4010                 }
4011                 out << "0\n";
4012             }
4013         }
4014     }
4015 
display_wcnf(std::ostream & out,unsigned sz,literal const * lits,unsigned const * weights) const4016     void solver::display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const {
4017         unsigned max_weight = 0;
4018         for (unsigned i = 0; i < sz; ++i)
4019             max_weight += weights[i];
4020         ++max_weight;
4021 
4022         if (m_ext)
4023             throw default_exception("wcnf is only supported for pure CNF problems");
4024 
4025         out << "p wcnf " << num_vars() << " " << num_clauses() + sz << " " << max_weight << "\n";
4026         out << "c soft " << sz << "\n";
4027 
4028         for (literal lit : m_trail)
4029             out << max_weight << " " << dimacs_lit(lit) << " 0\n";
4030         unsigned l_idx = 0;
4031         for (watch_list const& wlist : m_watches) {
4032             literal l = ~to_literal(l_idx);
4033             for (watched const& w : wlist) {
4034                 if (w.is_binary_clause() && l.index() < w.get_literal().index())
4035                     out << max_weight << " " << dimacs_lit(l) << " " << dimacs_lit(w.get_literal()) << " 0\n";
4036             }
4037             ++l_idx;
4038         }
4039         clause_vector const * vs[2] = { &m_clauses, &m_learned };
4040         for (unsigned i = 0; i < 2; i++) {
4041             clause_vector const & cs = *(vs[i]);
4042             for (clause const* cp : cs) {
4043                 clause const & c = *cp;
4044                 out << max_weight << " ";
4045                 for (literal l : c)
4046                     out << dimacs_lit(l) << " ";
4047                 out << "0\n";
4048             }
4049         }
4050         for (unsigned i = 0; i < sz; ++i) {
4051             out << weights[i] << " " << lits[i] << " 0\n";
4052         }
4053         out.flush();
4054     }
4055 
display_watches(std::ostream & out,literal lit) const4056     void solver::display_watches(std::ostream & out, literal lit) const {
4057         display_watch_list(out << lit << ": ", get_wlist(lit)) << "\n";
4058     }
4059 
display_watches(std::ostream & out) const4060     void solver::display_watches(std::ostream & out) const {
4061         unsigned l_idx = 0;
4062         for (watch_list const& wlist : m_watches) {
4063             literal l = to_literal(l_idx++);
4064             if (!wlist.empty())
4065                 display_watch_list(out << l << ": ", wlist) << "\n";
4066         }
4067     }
4068 
display_watch_list(std::ostream & out,watch_list const & wl) const4069     std::ostream& solver::display_watch_list(std::ostream& out, watch_list const& wl) const {
4070         return sat::display_watch_list(out, cls_allocator(), wl, m_ext.get());
4071     }
4072 
display_assignment(std::ostream & out) const4073     void solver::display_assignment(std::ostream & out) const {
4074         out << m_trail << "\n";
4075     }
4076 
4077     /**
4078        \brief Return true, if c is a clause containing one unassigned literal.
4079     */
is_unit(clause const & c) const4080     bool solver::is_unit(clause const & c) const {
4081         bool found_undef = false;
4082         for (literal l : c) {
4083             switch (value(l)) {
4084             case l_undef:
4085                 if (found_undef)
4086                     return false;
4087                 found_undef = true;
4088                 break;
4089             case l_true:
4090                 return false;
4091             case l_false:
4092                 break;
4093             }
4094         }
4095         return found_undef;
4096     }
4097 
4098     /**
4099        \brief Return true, if all literals in c are assigned to false.
4100     */
is_empty(clause const & c) const4101     bool solver::is_empty(clause const & c) const {
4102         for (literal lit : c)
4103             if (value(lit) != l_false)
4104                 return false;
4105         return true;
4106     }
4107 
check_missed_propagation(clause_vector const & cs) const4108     bool solver::check_missed_propagation(clause_vector const & cs) const {
4109         for (clause* cp : cs) {
4110             clause const & c = *cp;
4111             if (c.frozen())
4112                 continue;
4113             if (is_empty(c) || is_unit(c)) {
4114                 TRACE("sat_missed_prop", tout << "missed_propagation: " << c << "\n";
4115                       for (literal l : c) tout << l << ": " << value(l) << "\n";);
4116                 UNREACHABLE();
4117             }
4118             SASSERT(!is_empty(c));
4119             SASSERT(!is_unit(c));
4120         }
4121         return true;
4122     }
4123 
check_missed_propagation() const4124     bool solver::check_missed_propagation() const {
4125         if (inconsistent())
4126             return true;
4127         return check_missed_propagation(m_clauses) && check_missed_propagation(m_learned);
4128     }
4129 
4130     // -----------------------
4131     //
4132     // Simplification
4133     //
4134     // -----------------------
do_cleanup(bool force)4135     bool solver::do_cleanup(bool force) {
4136         if (m_conflicts_since_init == 0 && !force)
4137             return false;
4138         if (at_base_lvl() && !inconsistent() && m_cleaner(force)) {
4139             if (m_ext)
4140                 m_ext->clauses_modifed();
4141             return true;
4142         }
4143         return false;
4144     }
4145 
simplify(bool redundant)4146     void solver::simplify(bool redundant) {
4147         if (!at_base_lvl() || inconsistent())
4148             return;
4149         m_simplifier(redundant);
4150         m_simplifier.finalize();
4151         if (m_ext)
4152             m_ext->clauses_modifed();
4153     }
4154 
scc_bin()4155     unsigned solver::scc_bin() {
4156         if (!at_base_lvl() || inconsistent())
4157             return 0;
4158         unsigned r = m_scc();
4159         if (r > 0 && m_ext)
4160             m_ext->clauses_modifed();
4161         return r;
4162     }
4163 
4164     // -----------------------
4165     //
4166     // Extraction of mutexes
4167     //
4168     // -----------------------
4169 
4170     struct neg_literal {
negatesat::neg_literal4171         unsigned negate(unsigned idx) {
4172             return (~to_literal(idx)).index();
4173         }
4174     };
4175 
find_mutexes(literal_vector const & lits,vector<literal_vector> & mutexes)4176     lbool solver::find_mutexes(literal_vector const& lits, vector<literal_vector> & mutexes) {
4177         max_cliques<neg_literal> mc;
4178         m_user_bin_clauses.reset();
4179         m_binary_clause_graph.reset();
4180         collect_bin_clauses(m_user_bin_clauses, true, false);
4181         hashtable<literal_pair, pair_hash<literal_hash, literal_hash>, default_eq<literal_pair> > seen_bc;
4182         for (auto const& b : m_user_bin_clauses) {
4183             literal l1 = b.first;
4184             literal l2 = b.second;
4185             literal_pair p(l1, l2);
4186             if (!seen_bc.contains(p)) {
4187                 seen_bc.insert(p);
4188                 mc.add_edge(l1.index(), l2.index());
4189             }
4190         }
4191         vector<unsigned_vector> _mutexes;
4192         literal_vector _lits(lits);
4193         if (m_ext) {
4194             // m_ext->find_mutexes(_lits, mutexes);
4195         }
4196         unsigned_vector ps;
4197         for (literal lit : _lits) {
4198             ps.push_back(lit.index());
4199         }
4200         mc.cliques(ps, _mutexes);
4201         for (auto const& mux : _mutexes) {
4202             literal_vector clique;
4203             for (auto const& idx : mux) {
4204                 clique.push_back(to_literal(idx));
4205             }
4206             mutexes.push_back(clique);
4207         }
4208         return l_true;
4209     }
4210 
4211     // -----------------------
4212     //
4213     // Consequence generation.
4214     //
4215     // -----------------------
4216 
prune_unfixed(sat::literal_vector & lambda,sat::model const & m)4217     static void prune_unfixed(sat::literal_vector& lambda, sat::model const& m) {
4218         for (unsigned i = 0; i < lambda.size(); ++i) {
4219             if ((m[lambda[i].var()] == l_false) != lambda[i].sign()) {
4220                 lambda[i] = lambda.back();
4221                 lambda.pop_back();
4222                 --i;
4223             }
4224         }
4225     }
4226 
4227     // Algorithm 7: Corebased Algorithm with Chunking
4228 
back_remove(sat::literal_vector & lits,sat::literal l)4229     static void back_remove(sat::literal_vector& lits, sat::literal l) {
4230         for (unsigned i = lits.size(); i > 0; ) {
4231             --i;
4232             if (lits[i] == l) {
4233                 lits[i] = lits.back();
4234                 lits.pop_back();
4235                 return;
4236             }
4237         }
4238         UNREACHABLE();
4239     }
4240 
brute_force_consequences(sat::solver & s,sat::literal_vector const & asms,sat::literal_vector const & gamma,vector<sat::literal_vector> & conseq)4241     static void brute_force_consequences(sat::solver& s, sat::literal_vector const& asms, sat::literal_vector const& gamma, vector<sat::literal_vector>& conseq) {
4242         for (literal lit : gamma) {
4243             sat::literal_vector asms1(asms);
4244             asms1.push_back(~lit);
4245             lbool r = s.check(asms1.size(), asms1.data());
4246             if (r == l_false) {
4247                 conseq.push_back(s.get_core());
4248             }
4249         }
4250     }
4251 
core_chunking(sat::solver & s,model const & m,sat::bool_var_vector const & vars,sat::literal_vector const & asms,vector<sat::literal_vector> & conseq,unsigned K)4252     static lbool core_chunking(sat::solver& s, model const& m, sat::bool_var_vector const& vars, sat::literal_vector const& asms, vector<sat::literal_vector>& conseq, unsigned K) {
4253         sat::literal_vector lambda;
4254         for (bool_var v : vars) {
4255             lambda.push_back(sat::literal(v, m[v] == l_false));
4256         }
4257         while (!lambda.empty()) {
4258             IF_VERBOSE(1, verbose_stream() << "(sat-backbone-core " << lambda.size() << " " << conseq.size() << ")\n";);
4259             unsigned k = std::min(K, lambda.size());
4260             sat::literal_vector gamma, omegaN;
4261             for (unsigned i = 0; i < k; ++i) {
4262                 sat::literal l = lambda[lambda.size() - i - 1];
4263                 gamma.push_back(l);
4264                 omegaN.push_back(~l);
4265             }
4266             while (true) {
4267                 sat::literal_vector asms1(asms);
4268                 asms1.append(omegaN);
4269                 lbool r = s.check(asms1.size(), asms1.data());
4270                 if (r == l_true) {
4271                     IF_VERBOSE(1, verbose_stream() << "(sat) " << omegaN << "\n";);
4272                     prune_unfixed(lambda, s.get_model());
4273                     break;
4274                 }
4275                 sat::literal_vector const& core = s.get_core();
4276                 sat::literal_vector occurs;
4277                 IF_VERBOSE(1, verbose_stream() << "(core " << core.size() << ")\n";);
4278                 for (unsigned i = 0; i < omegaN.size(); ++i) {
4279                     if (core.contains(omegaN[i])) {
4280                         occurs.push_back(omegaN[i]);
4281                     }
4282                 }
4283                 if (occurs.size() == 1) {
4284                     sat::literal lit = occurs.back();
4285                     sat::literal nlit = ~lit;
4286                     conseq.push_back(core);
4287                     back_remove(lambda, ~lit);
4288                     back_remove(gamma, ~lit);
4289                     s.mk_clause(1, &nlit);
4290                 }
4291                 for (unsigned i = 0; i < omegaN.size(); ++i) {
4292                     if (occurs.contains(omegaN[i])) {
4293                         omegaN[i] = omegaN.back();
4294                         omegaN.pop_back();
4295                         --i;
4296                     }
4297                 }
4298                 if (omegaN.empty() && occurs.size() > 1) {
4299                     brute_force_consequences(s, asms, gamma, conseq);
4300                     for (unsigned i = 0; i < gamma.size(); ++i) {
4301                         back_remove(lambda, gamma[i]);
4302                     }
4303                     break;
4304                 }
4305             }
4306         }
4307         return l_true;
4308     }
4309 
4310 
get_consequences(literal_vector const & asms,bool_var_vector const & vars,vector<literal_vector> & conseq)4311     lbool solver::get_consequences(literal_vector const& asms, bool_var_vector const& vars, vector<literal_vector>& conseq) {
4312         literal_vector lits;
4313         lbool is_sat = l_true;
4314 
4315         if (m_config.m_restart_max != UINT_MAX && !m_model_is_current) {
4316             return get_bounded_consequences(asms, vars, conseq);
4317         }
4318         if (!m_model_is_current) {
4319             is_sat = check(asms.size(), asms.data());
4320         }
4321         if (is_sat != l_true) {
4322             return is_sat;
4323         }
4324         model mdl = get_model();
4325         for (unsigned i = 0; i < vars.size(); ++i) {
4326             bool_var v = vars[i];
4327             switch (get_model()[v]) {
4328             case l_true: lits.push_back(literal(v, false)); break;
4329             case l_false: lits.push_back(literal(v, true)); break;
4330             default: break;
4331             }
4332         }
4333 
4334         if (false && asms.empty()) {
4335             is_sat = core_chunking(*this, mdl, vars, asms, conseq, 100);
4336         }
4337         else {
4338             is_sat = get_consequences(asms, lits, conseq);
4339         }
4340         set_model(mdl, !mdl.empty());
4341         return is_sat;
4342     }
4343 
fixup_consequence_core()4344     void solver::fixup_consequence_core() {
4345         index_set s;
4346         TRACE("sat", tout << m_core << "\n";);
4347         for (unsigned i = 0; i < m_core.size(); ++i) {
4348             TRACE("sat", tout << m_core[i] << ": "; display_index_set(tout, m_antecedents.find(m_core[i].var())) << "\n";);
4349             s |= m_antecedents.find(m_core[i].var());
4350         }
4351         m_core.reset();
4352         for (unsigned idx : s) {
4353             m_core.push_back(to_literal(idx));
4354         }
4355         TRACE("sat", tout << m_core << "\n";);
4356     }
4357 
reached_max_conflicts()4358     bool solver::reached_max_conflicts() {
4359         if (m_config.m_max_conflicts == 0 || m_conflicts_since_init > m_config.m_max_conflicts) {
4360             if (m_reason_unknown != "sat.max.conflicts") {
4361                 m_reason_unknown = "sat.max.conflicts";
4362                 IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";);
4363             }
4364             return !inconsistent();
4365         }
4366         return false;
4367     }
4368 
4369 
get_bounded_consequences(literal_vector const & asms,bool_var_vector const & vars,vector<literal_vector> & conseq)4370     lbool solver::get_bounded_consequences(literal_vector const& asms, bool_var_vector const& vars, vector<literal_vector>& conseq) {
4371         bool_var_set unfixed_vars;
4372         unsigned num_units = 0, num_iterations = 0;
4373         for (bool_var v : vars) {
4374             unfixed_vars.insert(v);
4375         }
4376         TRACE("sat", tout << asms << "\n";);
4377         m_antecedents.reset();
4378         pop_to_base_level();
4379         if (inconsistent()) return l_false;
4380         flet<bool> _searching(m_searching, true);
4381         init_search();
4382         propagate(false);
4383         if (inconsistent()) return l_false;
4384         if (asms.empty()) {
4385             bool_var v = mk_var(true, false);
4386             literal lit(v, false);
4387             init_assumptions(1, &lit);
4388         }
4389         else {
4390             init_assumptions(asms.size(), asms.data());
4391         }
4392         propagate(false);
4393         if (check_inconsistent()) return l_false;
4394 
4395         extract_fixed_consequences(num_units, asms, unfixed_vars, conseq);
4396 
4397         do_simplify();
4398         if (check_inconsistent()) {
4399             fixup_consequence_core();
4400             return l_false;
4401         }
4402 
4403         while (true) {
4404             ++num_iterations;
4405             SASSERT(!inconsistent());
4406 
4407             lbool r = bounded_search();
4408             if (r != l_undef) {
4409                 fixup_consequence_core();
4410                 return r;
4411             }
4412 
4413             extract_fixed_consequences(num_units, asms, unfixed_vars, conseq);
4414 
4415             do_restart(true);
4416             do_simplify();
4417             if (check_inconsistent()) {
4418                 fixup_consequence_core();
4419                 return l_false;
4420             }
4421             do_gc();
4422 
4423             if (should_cancel()) {
4424                 return l_undef;
4425             }
4426         }
4427     }
4428 
get_consequences(literal_vector const & asms,literal_vector const & lits,vector<literal_vector> & conseq)4429     lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector<literal_vector>& conseq) {
4430         TRACE("sat", tout << asms << "\n";);
4431         m_antecedents.reset();
4432         literal_set unfixed_lits(lits), assumptions(asms);
4433         bool_var_set unfixed_vars;
4434         for (literal lit : lits) {
4435             unfixed_vars.insert(lit.var());
4436         }
4437 
4438         pop_to_base_level();
4439         if (inconsistent()) return l_false;
4440         init_search();
4441         propagate(false);
4442         if (inconsistent()) return l_false;
4443         if (asms.empty()) {
4444             bool_var v = mk_var(true, false);
4445             literal lit(v, false);
4446             init_assumptions(1, &lit);
4447         }
4448         else {
4449             init_assumptions(asms.size(), asms.data());
4450         }
4451         propagate(false);
4452         if (check_inconsistent()) return l_false;
4453         SASSERT(search_lvl() == 1);
4454 
4455         unsigned num_iterations = 0;
4456         extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq);
4457         update_unfixed_literals(unfixed_lits, unfixed_vars);
4458         while (!unfixed_lits.empty()) {
4459             if (scope_lvl() > search_lvl()) {
4460                 pop(scope_lvl() - search_lvl());
4461             }
4462             propagate(false);
4463             ++num_iterations;
4464             checkpoint();
4465             unsigned num_resolves = 0;
4466             unsigned num_fixed = 0;
4467             unsigned num_assigned = 0;
4468             lbool is_sat = l_true;
4469             for (literal lit : unfixed_lits) {
4470                 if (value(lit) != l_undef) {
4471                     ++num_fixed;
4472                     if (lvl(lit) <= 1 && value(lit) == l_true) {
4473                         extract_fixed_consequences(lit, assumptions, unfixed_vars, conseq);
4474                     }
4475                     continue;
4476                 }
4477                 push();
4478                 ++num_assigned;
4479                 assign_scoped(~lit);
4480                 propagate(false);
4481                 while (inconsistent()) {
4482                     if (!resolve_conflict()) {
4483                         TRACE("sat", display(tout << "inconsistent\n"););
4484                         m_inconsistent = false;
4485                         is_sat = l_undef;
4486                         break;
4487                     }
4488                     propagate(false);
4489                     ++num_resolves;
4490                 }
4491             }
4492 
4493             extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq);
4494 
4495             if (is_sat == l_true) {
4496                 if (scope_lvl() == search_lvl() && num_resolves > 0) {
4497                     IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences backjump)\n";);
4498                     is_sat = l_undef;
4499                 }
4500                 else {
4501                     is_sat = bounded_search();
4502                     if (is_sat == l_undef) {
4503                         do_restart(true);
4504                         propagate(false);
4505                     }
4506                     extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq);
4507                 }
4508             }
4509             if (is_sat == l_false) {
4510                 TRACE("sat", tout << "unsat\n";);
4511                 m_inconsistent = false;
4512             }
4513             if (is_sat == l_true) {
4514                 delete_unfixed(unfixed_lits, unfixed_vars);
4515             }
4516             update_unfixed_literals(unfixed_lits, unfixed_vars);
4517             IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences"
4518                        << " iterations: " << num_iterations
4519                        << " variables: " << unfixed_lits.size()
4520                        << " fixed: " << conseq.size()
4521                        << " status: " << is_sat
4522                        << " pre-assigned: " << num_fixed
4523                        << " unfixed: " << lits.size() - conseq.size() - unfixed_lits.size()
4524                        << ")\n";);
4525 
4526             if (!unfixed_lits.empty() && m_config.m_restart_max <= num_iterations) {
4527                 return l_undef;
4528             }
4529         }
4530         return l_true;
4531     }
4532 
delete_unfixed(literal_set & unfixed_lits,bool_var_set & unfixed_vars)4533     void solver::delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars) {
4534         literal_set to_keep;
4535         for (literal lit : unfixed_lits) {
4536             if (value(lit) == l_true) {
4537                 to_keep.insert(lit);
4538             }
4539             else {
4540                 unfixed_vars.remove(lit.var());
4541             }
4542         }
4543         unfixed_lits = to_keep;
4544     }
4545 
update_unfixed_literals(literal_set & unfixed_lits,bool_var_set & unfixed_vars)4546     void solver::update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars) {
4547         literal_vector to_delete;
4548         for (literal lit : unfixed_lits) {
4549             if (!unfixed_vars.contains(lit.var())) {
4550                 to_delete.push_back(lit);
4551             }
4552         }
4553         for (unsigned i = 0; i < to_delete.size(); ++i) {
4554             unfixed_lits.remove(to_delete[i]);
4555         }
4556     }
4557 
4558 
extract_fixed_consequences(unsigned & start,literal_set const & assumptions,bool_var_set & unfixed,vector<literal_vector> & conseq)4559     void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector<literal_vector>& conseq) {
4560         SASSERT(!inconsistent());
4561         unsigned sz = m_trail.size();
4562         for (unsigned i = start; i < sz && lvl(m_trail[i]) <= 1; ++i) {
4563             extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq);
4564         }
4565         start = sz;
4566     }
4567 
extract_fixed_consequences(literal_set const & unfixed_lits,literal_set const & assumptions,bool_var_set & unfixed_vars,vector<literal_vector> & conseq)4568     void solver::extract_fixed_consequences(literal_set const& unfixed_lits, literal_set const& assumptions, bool_var_set& unfixed_vars, vector<literal_vector>& conseq) {
4569         for (literal lit: unfixed_lits) {
4570             TRACE("sat", tout << "extract: " << lit << " " << value(lit) << " " << lvl(lit) << "\n";);
4571 
4572             if (lvl(lit) <= 1 && value(lit) == l_true) {
4573                 extract_fixed_consequences(lit, assumptions, unfixed_vars, conseq);
4574             }
4575         }
4576     }
4577 
check_domain(literal lit,literal lit2)4578     bool solver::check_domain(literal lit, literal lit2) {
4579         if (!m_antecedents.contains(lit2.var())) {
4580             SASSERT(value(lit2) == l_true);
4581             SASSERT(m_todo_antecedents.empty() || m_todo_antecedents.back() != lit2);
4582             m_todo_antecedents.push_back(lit2);
4583             return false;
4584         }
4585         else {
4586             return true;
4587         }
4588     }
4589 
extract_assumptions(literal lit,index_set & s)4590     bool solver::extract_assumptions(literal lit, index_set& s) {
4591         justification js = m_justification[lit.var()];
4592         TRACE("sat", tout << lit << " " << js << "\n";);
4593         bool all_found = true;
4594         switch (js.get_kind()) {
4595         case justification::NONE:
4596             break;
4597         case justification::BINARY:
4598             if (!check_domain(lit, ~js.get_literal())) return false;
4599             s |= m_antecedents.find(js.get_literal().var());
4600             break;
4601         case justification::TERNARY:
4602             if (!check_domain(lit, ~js.get_literal1()) ||
4603                 !check_domain(lit, ~js.get_literal2())) return false;
4604             s |= m_antecedents.find(js.get_literal1().var());
4605             s |= m_antecedents.find(js.get_literal2().var());
4606             break;
4607         case justification::CLAUSE: {
4608             clause & c = get_clause(js);
4609             for (literal l : c) {
4610                 if (l != lit) {
4611                     if (check_domain(lit, ~l) && all_found) {
4612                         s |= m_antecedents.find(l.var());
4613                     }
4614                     else {
4615                         all_found = false;
4616                     }
4617                 }
4618             }
4619             break;
4620         }
4621         case justification::EXT_JUSTIFICATION: {
4622             fill_ext_antecedents(lit, js, true);
4623             for (literal l : m_ext_antecedents) {
4624                 if (check_domain(lit, l) && all_found) {
4625                     s |= m_antecedents.find(l.var());
4626                 }
4627                 else {
4628                     all_found = false;
4629                 }
4630             }
4631             break;
4632         }
4633         default:
4634             UNREACHABLE();
4635             break;
4636         }
4637         TRACE("sat", display_index_set(tout << lit << ": " , s) << "\n";);
4638         return all_found;
4639     }
4640 
display_index_set(std::ostream & out,index_set const & s) const4641     std::ostream& solver::display_index_set(std::ostream& out, index_set const& s) const {
4642         for (unsigned idx : s) {
4643             out << to_literal(idx) << " ";
4644         }
4645         return out;
4646     }
4647 
4648 
extract_fixed_consequences1(literal lit,literal_set const & assumptions,bool_var_set & unfixed,vector<literal_vector> & conseq)4649     bool solver::extract_fixed_consequences1(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector<literal_vector>& conseq) {
4650         index_set s;
4651         if (m_antecedents.contains(lit.var())) {
4652             return true;
4653         }
4654         if (assumptions.contains(lit)) {
4655             s.insert(lit.index());
4656         }
4657         else {
4658             if (!extract_assumptions(lit, s)) {
4659                 SASSERT(!m_todo_antecedents.empty());
4660                 return false;
4661             }
4662             add_assumption(lit);
4663         }
4664         m_antecedents.insert(lit.var(), s);
4665         if (unfixed.contains(lit.var())) {
4666             literal_vector cons;
4667             cons.push_back(lit);
4668             for (unsigned idx : s) {
4669                 cons.push_back(to_literal(idx));
4670             }
4671             unfixed.remove(lit.var());
4672             conseq.push_back(cons);
4673         }
4674         return true;
4675     }
4676 
extract_fixed_consequences(literal lit,literal_set const & assumptions,bool_var_set & unfixed,vector<literal_vector> & conseq)4677     void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector<literal_vector>& conseq) {
4678         SASSERT(m_todo_antecedents.empty());
4679         m_todo_antecedents.push_back(lit);
4680         while (!m_todo_antecedents.empty()) {
4681             if (extract_fixed_consequences1(m_todo_antecedents.back(), assumptions, unfixed, conseq)) {
4682                 m_todo_antecedents.pop_back();
4683             }
4684         }
4685     }
4686 
4687     // -----------------------
4688     //
4689     // Statistics
4690     //
4691     // -----------------------
4692 
display_status(std::ostream & out) const4693     void solver::display_status(std::ostream & out) const {
4694         unsigned num_bin = 0;
4695         unsigned num_ext = 0;
4696         unsigned num_lits = 0;
4697         unsigned l_idx = 0;
4698         for (watch_list const& wlist : m_watches) {
4699             literal l = ~to_literal(l_idx++);
4700             for (watched const& w : wlist) {
4701                 switch (w.get_kind()) {
4702                 case watched::BINARY:
4703                     if (l.index() < w.get_literal().index()) {
4704                         num_lits += 2;
4705                         num_bin++;
4706                     }
4707                     break;
4708                 case watched::EXT_CONSTRAINT:
4709                     num_ext++;
4710                     break;
4711                 default:
4712                     break;
4713                 }
4714             }
4715         }
4716         unsigned num_elim = 0;
4717         for (bool_var v = 0; v < num_vars(); v++) {
4718             if (m_eliminated[v])
4719                 num_elim++;
4720         }
4721         unsigned num_ter  = 0;
4722         unsigned num_cls  = 0;
4723         clause_vector const * vs[2] = { &m_clauses, &m_learned };
4724         for (unsigned i = 0; i < 2; i++) {
4725             clause_vector const & cs = *(vs[i]);
4726             for (clause* cp : cs) {
4727                 clause & c = *cp;
4728                 if (ENABLE_TERNARY && c.size() == 3)
4729                     num_ter++;
4730                 else
4731                     num_cls++;
4732                 num_lits += c.size();
4733             }
4734         }
4735         unsigned total_cls = num_cls + num_ter + num_bin;
4736         double mem = static_cast<double>(memory::get_allocation_size())/static_cast<double>(1024*1024);
4737         out << "(sat-status\n";
4738         out << "  :inconsistent    " << (m_inconsistent ? "true" : "false") << "\n";
4739         out << "  :vars            " << num_vars() << "\n";
4740         out << "  :elim-vars       " << num_elim << "\n";
4741         out << "  :lits            " << num_lits << "\n";
4742         out << "  :assigned        " << m_trail.size() << "\n";
4743         out << "  :binary-clauses  " << num_bin << "\n";
4744         out << "  :ternary-clauses " << num_ter << "\n";
4745         out << "  :clauses         " << num_cls << "\n";
4746         out << "  :del-clause      " << m_stats.m_del_clause << "\n";
4747         out << "  :avg-clause-size " << (total_cls == 0 ? 0.0 : static_cast<double>(num_lits) / static_cast<double>(total_cls)) << "\n";
4748         out << "  :memory          " << std::fixed << std::setprecision(2) << mem << ")" << std::endl;
4749     }
4750 
collect_statistics(statistics & st) const4751     void stats::collect_statistics(statistics & st) const {
4752         st.update("sat mk clause 2ary", m_mk_bin_clause);
4753         st.update("sat mk clause 3ary", m_mk_ter_clause);
4754         st.update("sat mk clause nary", m_mk_clause);
4755         st.update("sat mk var", m_mk_var);
4756         st.update("sat gc clause", m_gc_clause);
4757         st.update("sat del clause", m_del_clause);
4758         st.update("sat conflicts", m_conflict);
4759         st.update("sat decisions", m_decision);
4760         st.update("sat propagations 2ary", m_bin_propagate);
4761         st.update("sat propagations 3ary", m_ter_propagate);
4762         st.update("sat propagations nary", m_propagate);
4763         st.update("sat restarts", m_restart);
4764         st.update("sat minimized lits", m_minimized_lits);
4765         st.update("sat subs resolution dyn", m_dyn_sub_res);
4766         st.update("sat blocked correction sets", m_blocked_corr_sets);
4767         st.update("sat units", m_units);
4768         st.update("sat elim bool vars res", m_elim_var_res);
4769         st.update("sat elim bool vars bdd", m_elim_var_bdd);
4770         st.update("sat backjumps", m_backjumps);
4771         st.update("sat backtracks", m_backtracks);
4772     }
4773 
reset()4774     void stats::reset() {
4775         memset(this, 0, sizeof(*this));
4776     }
4777 
display(std::ostream & out) const4778     void mk_stat::display(std::ostream & out) const {
4779         unsigned given, redundant;
4780         m_solver.num_binary(given, redundant);
4781         out << " " << std::setw(5) << m_solver.m_clauses.size() + given << "/" << given;
4782         out << " " << std::setw(5) << (m_solver.m_learned.size() + redundant - m_solver.m_num_frozen) << "/" << redundant;
4783         out << " " << std::setw(3)  << m_solver.init_trail_size();
4784         out << " " << std::setw(7)  << m_solver.m_stats.m_gc_clause << " ";
4785         out << " " << std::setw(7)  << mem_stat();
4786     }
4787 
operator <<(std::ostream & out,mk_stat const & stat)4788     std::ostream & operator<<(std::ostream & out, mk_stat const & stat) {
4789         stat.display(out);
4790         return out;
4791     }
4792 
all_distinct(literal_vector const & lits)4793     bool solver::all_distinct(literal_vector const& lits) {
4794         init_visited();
4795         for (literal l : lits) {
4796             if (is_visited(l.var())) {
4797                 return false;
4798             }
4799             mark_visited(l.var());
4800         }
4801         return true;
4802     }
4803 
all_distinct(clause const & c)4804     bool solver::all_distinct(clause const& c) {
4805         init_visited();
4806         for (literal l : c) {
4807             if (is_visited(l.var())) {
4808                 return false;
4809             }
4810             mark_visited(l.var());
4811         }
4812         return true;
4813     }
4814 
init_visited()4815     void solver::init_visited() {
4816         if (m_visited.empty()) {
4817             m_visited_ts = 0;
4818         }
4819         m_visited_ts++;
4820         if (m_visited_ts == 0) {
4821             m_visited_ts = 1;
4822             m_visited.reset();
4823         }
4824         while (m_visited.size() < 2*num_vars()) {
4825             m_visited.push_back(0);
4826         }
4827     }
4828 
4829 
4830 
4831 };
4832