1 /*++
2 Copyright (c) 2020 Microsoft Corporation
3 
4 Module Name:
5 
6     euf_solver.cpp
7 
8 Abstract:
9 
10     Solver plugin for EUF
11 
12 Author:
13 
14     Nikolaj Bjorner (nbjorner) 2020-08-25
15 
16 --*/
17 
18 #include "ast/pb_decl_plugin.h"
19 #include "ast/ast_ll_pp.h"
20 #include "sat/sat_solver.h"
21 #include "sat/smt/sat_smt.h"
22 #include "sat/smt/ba_solver.h"
23 #include "sat/smt/bv_solver.h"
24 #include "sat/smt/euf_solver.h"
25 #include "sat/smt/array_solver.h"
26 #include "sat/smt/arith_solver.h"
27 #include "sat/smt/q_solver.h"
28 #include "sat/smt/fpa_solver.h"
29 #include "sat/smt/dt_solver.h"
30 
31 namespace euf {
32 
solver(ast_manager & m,sat::sat_internalizer & si,params_ref const & p)33     solver::solver(ast_manager& m, sat::sat_internalizer& si, params_ref const& p) :
34         extension(symbol("euf"), m.mk_family_id("euf")),
35         m(m),
36         si(si),
37         m_egraph(m),
38         m_trail(*this),
39         m_rewriter(m),
40         m_unhandled_functions(m),
41         m_lookahead(nullptr),
42         m_to_m(&m),
43         m_to_si(&si),
44         m_values(m)
45     {
46         updt_params(p);
47 
48         std::function<void(std::ostream&, void*)> disp =
49             [&](std::ostream& out, void* j) {
50             display_justification_ptr(out, reinterpret_cast<size_t*>(j));
51         };
52         m_egraph.set_display_justification(disp);
53     }
54 
updt_params(params_ref const & p)55     void solver::updt_params(params_ref const& p) {
56         m_config.updt_params(p);
57     }
58 
59     /**
60     * retrieve extension that is associated with Boolean variable.
61     */
bool_var2solver(sat::bool_var v)62     th_solver* solver::bool_var2solver(sat::bool_var v) {
63         if (v >= m_bool_var2expr.size())
64             return nullptr;
65         expr* e = m_bool_var2expr[v];
66         if (!e)
67             return nullptr;
68         return expr2solver(e);
69     }
70 
expr2solver(expr * e)71     th_solver* solver::expr2solver(expr* e) {
72         if (is_app(e))
73             return func_decl2solver(to_app(e)->get_decl());
74         if (is_forall(e) || is_exists(e))
75             return quantifier2solver();
76         return nullptr;
77     }
78 
quantifier2solver()79     th_solver* solver::quantifier2solver() {
80         family_id fid = m.mk_family_id(symbol("quant"));
81         auto* ext = m_id2solver.get(fid, nullptr);
82         if (ext)
83             return ext;
84         ext = alloc(q::solver, *this, fid);
85         m_qsolver = ext;
86         add_solver(ext);
87         return ext;
88     }
89 
get_solver(family_id fid,func_decl * f)90     th_solver* solver::get_solver(family_id fid, func_decl* f) {
91         if (fid == null_family_id)
92             return nullptr;
93         auto* ext = m_id2solver.get(fid, nullptr);
94         if (ext)
95             return ext;
96         if (fid == m.get_basic_family_id())
97             return nullptr;
98         if (fid == m.get_user_sort_family_id())
99             return nullptr;
100         pb_util pb(m);
101         bv_util bvu(m);
102         array_util au(m);
103         fpa_util fpa(m);
104         arith_util arith(m);
105         datatype_util dt(m);
106         if (pb.get_family_id() == fid)
107             ext = alloc(sat::ba_solver, *this, fid);
108         else if (bvu.get_family_id() == fid)
109             ext = alloc(bv::solver, *this, fid);
110         else if (au.get_family_id() == fid)
111             ext = alloc(array::solver, *this, fid);
112         else if (fpa.get_family_id() == fid)
113             ext = alloc(fpa::solver, *this);
114         else if (arith.get_family_id() == fid)
115             ext = alloc(arith::solver, *this, fid);
116         else if (dt.get_family_id() == fid)
117             ext = alloc(dt::solver, *this, fid);
118 
119         if (ext)
120             add_solver(ext);
121         else if (f)
122             unhandled_function(f);
123         return ext;
124     }
125 
add_solver(th_solver * th)126     void solver::add_solver(th_solver* th) {
127         family_id fid = th->get_id();
128         if (use_drat())
129             s().get_drat().add_theory(fid, th->name());
130         th->set_solver(m_solver);
131         th->push_scopes(s().num_scopes() + s().num_user_scopes());
132         m_solvers.push_back(th);
133         m_id2solver.setx(fid, th, nullptr);
134         if (th->use_diseqs())
135             m_egraph.set_th_propagates_diseqs(fid);
136     }
137 
unhandled_function(func_decl * f)138     void solver::unhandled_function(func_decl* f) {
139         if (m_unhandled_functions.contains(f))
140             return;
141         if (m.is_model_value(f))
142             return;
143         m_unhandled_functions.push_back(f);
144         m_trail.push(push_back_vector<solver, func_decl_ref_vector>(m_unhandled_functions));
145         IF_VERBOSE(0, verbose_stream() << mk_pp(f, m) << " not handled\n");
146     }
147 
init_search()148     void solver::init_search() {
149         TRACE("before_search", s().display(tout););
150         for (auto* s : m_solvers)
151             s->init_search();
152     }
153 
is_external(bool_var v)154     bool solver::is_external(bool_var v) {
155         if (s().is_external(v))
156             return true;
157         if (nullptr != m_bool_var2expr.get(v, nullptr))
158             return true;
159         for (auto* s : m_solvers)
160             if (s->is_external(v))
161                 return true;
162         return false;
163     }
164 
propagated(literal l,ext_constraint_idx idx)165     bool solver::propagated(literal l, ext_constraint_idx idx) {
166         auto* ext = sat::constraint_base::to_extension(idx);
167         SASSERT(ext != this);
168         return ext->propagated(l, idx);
169     }
170 
set_conflict(ext_constraint_idx idx)171     void solver::set_conflict(ext_constraint_idx idx) {
172         s().set_conflict(sat::justification::mk_ext_justification(s().scope_lvl(), idx));
173     }
174 
propagate(literal lit,ext_justification_idx idx)175     void solver::propagate(literal lit, ext_justification_idx idx) {
176         s().assign(lit, sat::justification::mk_ext_justification(s().scope_lvl(), idx));
177     }
178 
get_antecedents(literal l,ext_justification_idx idx,literal_vector & r,bool probing)179     void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) {
180         m_egraph.begin_explain();
181         m_explain.reset();
182         auto* ext = sat::constraint_base::to_extension(idx);
183         if (ext == this)
184             get_antecedents(l, constraint::from_idx(idx), r, probing);
185         else
186             ext->get_antecedents(l, idx, r, probing);
187         for (unsigned qhead = 0; qhead < m_explain.size(); ++qhead) {
188             size_t* e = m_explain[qhead];
189             if (is_literal(e))
190                 r.push_back(get_literal(e));
191             else {
192                 size_t idx = get_justification(e);
193                 auto* ext = sat::constraint_base::to_extension(idx);
194                 SASSERT(ext != this);
195                 sat::literal lit = sat::null_literal;
196                 ext->get_antecedents(lit, idx, r, probing);
197             }
198         }
199         m_egraph.end_explain();
200         unsigned j = 0;
201         for (sat::literal lit : r)
202             if (s().lvl(lit) > 0) r[j++] = lit;
203         r.shrink(j);
204         TRACE("euf", tout << "eplain " << l << " <- " << r << " " << probing << "\n";);
205         DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true););
206 
207         if (!probing)
208             log_antecedents(l, r);
209     }
210 
get_antecedents(literal l,th_propagation & jst,literal_vector & r,bool probing)211     void solver::get_antecedents(literal l, th_propagation& jst, literal_vector& r, bool probing) {
212         for (auto lit : euf::th_propagation::lits(jst))
213             r.push_back(lit);
214         for (auto eq : euf::th_propagation::eqs(jst))
215             add_antecedent(eq.first, eq.second);
216 
217         if (!probing && use_drat())
218             log_justification(l, jst);
219     }
220 
add_antecedent(enode * a,enode * b)221     void solver::add_antecedent(enode* a, enode* b) {
222         m_egraph.explain_eq<size_t>(m_explain, a, b);
223     }
224 
propagate(enode * a,enode * b,ext_justification_idx idx)225     bool solver::propagate(enode* a, enode* b, ext_justification_idx idx) {
226         if (a->get_root() == b->get_root())
227             return false;
228         m_egraph.merge(a, b, to_ptr(idx));
229         return true;
230     }
231 
get_antecedents(literal l,constraint & j,literal_vector & r,bool probing)232     void solver::get_antecedents(literal l, constraint& j, literal_vector& r, bool probing) {
233         expr* e = nullptr;
234         euf::enode* n = nullptr;
235 
236         if (!probing && !m_drating)
237             init_ackerman();
238 
239         switch (j.kind()) {
240         case constraint::kind_t::conflict:
241             SASSERT(m_egraph.inconsistent());
242             m_egraph.explain<size_t>(m_explain);
243             break;
244         case constraint::kind_t::eq:
245             e = m_bool_var2expr[l.var()];
246             n = m_egraph.find(e);
247             SASSERT(n);
248             SASSERT(n->is_equality());
249             SASSERT(!l.sign());
250             m_egraph.explain_eq<size_t>(m_explain, n->get_arg(0), n->get_arg(1));
251             break;
252         case constraint::kind_t::lit:
253             e = m_bool_var2expr[l.var()];
254             n = m_egraph.find(e);
255             SASSERT(n);
256             SASSERT(m.is_bool(n->get_expr()));
257             m_egraph.explain_eq<size_t>(m_explain, n, (l.sign() ? mk_false() : mk_true()));
258             break;
259         default:
260             IF_VERBOSE(0, verbose_stream() << (unsigned)j.kind() << "\n");
261             UNREACHABLE();
262         }
263     }
264 
asserted(literal l)265     void solver::asserted(literal l) {
266         expr* e = m_bool_var2expr.get(l.var(), nullptr);
267         if (!e) {
268             TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << "\n";);
269             return;
270         }
271         TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";);
272         euf::enode* n = m_egraph.find(e);
273         if (!n)
274             return;
275         bool sign = l.sign();
276         m_egraph.set_value(n, sign ? l_false : l_true);
277         for (auto th : enode_th_vars(n))
278             m_id2solver[th.get_id()]->asserted(l);
279 
280         size_t* c = to_ptr(l);
281         SASSERT(is_literal(c));
282         SASSERT(l == get_literal(c));
283         if (!sign && n->is_equality()) {
284             SASSERT(!m.is_iff(e));
285             euf::enode* na = n->get_arg(0);
286             euf::enode* nb = n->get_arg(1);
287             m_egraph.merge(na, nb, c);
288         }
289         else if (n->merge_enabled()) {
290             euf::enode* nb = sign ? mk_false() : mk_true();
291             m_egraph.merge(n, nb, c);
292         }
293         else if (sign && n->is_equality())
294             m_egraph.new_diseq(n);
295     }
296 
297 
unit_propagate()298     bool solver::unit_propagate() {
299         bool propagated = false;
300         while (!s().inconsistent()) {
301             if (m_egraph.inconsistent()) {
302                 unsigned lvl = s().scope_lvl();
303                 s().set_conflict(sat::justification::mk_ext_justification(lvl, conflict_constraint().to_index()));
304                 return true;
305             }
306             bool propagated1 = false;
307             if (m_egraph.propagate()) {
308                 propagate_literals();
309                 propagate_th_eqs();
310                 propagated1 = true;
311             }
312 
313             for (auto* s : m_solvers) {
314                 if (s->unit_propagate())
315                     propagated1 = true;
316             }
317             if (!propagated1)
318                 break;
319             propagated = true;
320         }
321         DEBUG_CODE(if (!s().inconsistent()) check_missing_eq_propagation(););
322         return propagated;
323     }
324 
propagate_literals()325     void solver::propagate_literals() {
326         for (; m_egraph.has_literal() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_literal()) {
327             euf::enode_bool_pair p = m_egraph.get_literal();
328             euf::enode* n = p.first;
329             bool is_eq = p.second;
330             expr* e = n->get_expr();
331             expr* a = nullptr, *b = nullptr;
332             bool_var v = n->bool_var();
333             SASSERT(m.is_bool(e));
334             size_t cnstr;
335             literal lit;
336             if (is_eq) {
337                 VERIFY(m.is_eq(e, a, b));
338                 cnstr = eq_constraint().to_index();
339                 lit = literal(v, false);
340             }
341             else {
342                 lbool val = n->get_root()->value();
343                 a = e;
344                 b = (val == l_true) ? m.mk_true() : m.mk_false();
345                 SASSERT(val != l_undef);
346                 cnstr = lit_constraint().to_index();
347                 lit = literal(v, val == l_false);
348             }
349             unsigned lvl = s().scope_lvl();
350 
351             CTRACE("euf", s().value(lit) != l_true, tout << lit << " " << s().value(lit) << "@" << lvl << " " << is_eq << " " << mk_bounded_pp(a, m) << " = " << mk_bounded_pp(b, m) << "\n";);
352             if (s().value(lit) == l_false && m_ackerman)
353                 m_ackerman->cg_conflict_eh(a, b);
354             switch (s().value(lit)) {
355             case l_true:
356                 break;
357             case l_undef:
358             case l_false:
359                 s().assign(lit, sat::justification::mk_ext_justification(lvl, cnstr));
360                 break;
361             }
362         }
363     }
364 
is_self_propagated(th_eq const & e)365     bool solver::is_self_propagated(th_eq const& e) {
366         if (!e.is_eq())
367             return false;
368 
369         m_egraph.begin_explain();
370         m_explain.reset();
371         m_egraph.explain_eq<size_t>(m_explain, e.child(), e.root());
372         m_egraph.end_explain();
373         if (m_egraph.uses_congruence())
374             return false;
375         for (auto p : m_explain) {
376             if (is_literal(p))
377                 return false;
378 
379             size_t idx = get_justification(p);
380             auto* ext = sat::constraint_base::to_extension(idx);
381             if (ext->get_id() != e.id())
382                 return false;
383         }
384         return true;
385     }
386 
propagate_th_eqs()387     void solver::propagate_th_eqs() {
388         for (; m_egraph.has_th_eq() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_th_eq()) {
389             th_eq eq = m_egraph.get_th_eq();
390             if (eq.is_eq()) {
391                 if (!is_self_propagated(eq))
392                     m_id2solver[eq.id()]->new_eq_eh(eq);
393             }
394             else
395                 m_id2solver[eq.id()]->new_diseq_eh(eq);
396         }
397     }
398 
mk_constraint(constraint * & c,constraint::kind_t k)399     constraint& solver::mk_constraint(constraint*& c, constraint::kind_t k) {
400         if (!c) {
401             void* mem = memory::allocate(sat::constraint_base::obj_size(sizeof(constraint)));
402             c = new (sat::constraint_base::ptr2mem(mem)) constraint(k);
403             sat::constraint_base::initialize(mem, this);
404         }
405         return *c;
406     }
407 
mk_true()408     enode* solver::mk_true() {
409         VERIFY(visit(m.mk_true()));
410         return m_egraph.find(m.mk_true());
411     }
412 
mk_false()413     enode* solver::mk_false() {
414         VERIFY(visit(m.mk_false()));
415         return m_egraph.find(m.mk_false());
416     }
417 
check()418     sat::check_result solver::check() {
419         TRACE("euf", s().display(tout););
420         bool give_up = false;
421         bool cont = false;
422 
423         if (!init_relevancy())
424             give_up = true;
425 
426         for (auto* e : m_solvers) {
427             if (!m.inc())
428                 return sat::check_result::CR_GIVEUP;
429             if (e == m_qsolver)
430                 continue;
431             switch (e->check()) {
432             case sat::check_result::CR_CONTINUE: cont = true; break;
433             case sat::check_result::CR_GIVEUP: give_up = true; break;
434             default: break;
435             }
436             if (s().inconsistent())
437                 return sat::check_result::CR_CONTINUE;
438         }
439         if (cont)
440             return sat::check_result::CR_CONTINUE;
441         if (give_up)
442             return sat::check_result::CR_GIVEUP;
443         if (m_qsolver)
444             return m_qsolver->check();
445         TRACE("after_search", s().display(tout););
446         return sat::check_result::CR_DONE;
447     }
448 
push()449     void solver::push() {
450         si.push();
451         scope s;
452         s.m_var_lim = m_var_trail.size();
453         m_scopes.push_back(s);
454         m_trail.push_scope();
455         for (auto* e : m_solvers)
456             e->push();
457         m_egraph.push();
458     }
459 
pop(unsigned n)460     void solver::pop(unsigned n) {
461         start_reinit(n);
462         m_trail.pop_scope(n);
463         for (auto* e : m_solvers)
464             e->pop(n);
465         si.pop(n);
466         m_egraph.pop(n);
467         scope const & sc = m_scopes[m_scopes.size() - n];
468         for (unsigned i = m_var_trail.size(); i-- > sc.m_var_lim; ) {
469             bool_var v = m_var_trail[i];
470             m_bool_var2expr[v] = nullptr;
471             s().set_non_external(v);
472         }
473         m_var_trail.shrink(sc.m_var_lim);
474         m_scopes.shrink(m_scopes.size() - n);
475         SASSERT(m_egraph.num_scopes() == m_scopes.size());
476         TRACE("euf_verbose", display(tout << "pop to: " << m_scopes.size() << "\n"););
477     }
478 
user_push()479     void solver::user_push() {
480         push();
481         if (m_dual_solver)
482             m_dual_solver->push();
483     }
484 
user_pop(unsigned n)485     void solver::user_pop(unsigned n) {
486         pop(n);
487         if (m_dual_solver)
488             m_dual_solver->pop(n);
489     }
490 
start_reinit(unsigned n)491     void solver::start_reinit(unsigned n) {
492         m_reinit.reset();
493         for (sat::bool_var v : s().get_vars_to_reinit()) {
494             expr* e = bool_var2expr(v);
495             if (e)
496                 m_reinit.push_back(reinit_t(expr_ref(e, m), get_enode(e)?get_enode(e)->generation():0, v));
497         }
498     }
499 
500     /**
501     * After a pop has completed, re-initialize the association between Boolean variables
502     * and the theories by re-creating the expression/variable mapping used for Booleans
503     * and replaying internalization.
504     */
finish_reinit()505     void solver::finish_reinit() {
506         if (m_reinit.empty())
507             return;
508 
509         struct scoped_set_replay {
510             solver& s;
511             obj_map<expr, sat::bool_var> m;
512             scoped_set_replay(solver& s) :s(s) {
513                 s.si.set_expr2var_replay(&m);
514             }
515             ~scoped_set_replay() {
516                 s.si.set_expr2var_replay(nullptr);
517             }
518         };
519         scoped_set_replay replay(*this);
520         scoped_suspend_rlimit suspend_rlimit(m.limit());
521 
522         for (auto const& t : m_reinit)
523             replay.m.insert(std::get<0>(t), std::get<2>(t));
524 
525         TRACE("euf", for (auto const& kv : replay.m) tout << kv.m_value << "\n";);
526         for (auto const& t : m_reinit) {
527             expr_ref e          = std::get<0>(t);
528             unsigned generation = std::get<1>(t);
529             sat::bool_var v     = std::get<2>(t);
530             scoped_generation _sg(*this, generation);
531             TRACE("euf", tout << "replay: " << v << " " << mk_bounded_pp(e, m) << "\n";);
532             sat::literal lit;
533             if (si.is_bool_op(e))
534                 lit = literal(replay.m[e], false);
535             else
536                 lit = si.internalize(e, true);
537             VERIFY(lit.var() == v);
538             attach_lit(lit, e);
539         }
540         TRACE("euf", display(tout << "replay done\n"););
541     }
542 
pre_simplify()543     void solver::pre_simplify() {
544         for (auto* e : m_solvers)
545             e->pre_simplify();
546     }
547 
simplify()548     void solver::simplify() {
549         for (auto* e : m_solvers)
550             e->simplify();
551         if (m_ackerman)
552             m_ackerman->propagate();
553     }
554 
clauses_modifed()555     void solver::clauses_modifed() {
556         for (auto* e : m_solvers)
557             e->clauses_modifed();
558     }
559 
get_phase(bool_var v)560     lbool solver::get_phase(bool_var v) {
561         auto* ext = bool_var2solver(v);
562         if (ext)
563             return ext->get_phase(v);
564         return l_undef;
565     }
566 
set_root(literal l,literal r)567     bool solver::set_root(literal l, literal r) {
568         expr* e = bool_var2expr(l.var());
569         if (!e)
570             return true;
571         bool ok = true;
572         for (auto* s : m_solvers)
573             if (!s->set_root(l, r))
574                 ok = false;
575         if (m.is_eq(e) && !m.is_iff(e))
576             ok = false;
577         euf::enode* n = get_enode(e);
578         if (n && n->merge_enabled())
579             ok = false;
580 
581         (void)ok;
582         TRACE("euf", tout << ok << " " << l << " -> " << r << "\n";);
583         // roots cannot be eliminated as long as the egraph contains the expressions.
584         return false;
585     }
586 
flush_roots()587     void solver::flush_roots() {
588         for (auto* s : m_solvers)
589             s->flush_roots();
590     }
591 
display(std::ostream & out) const592     std::ostream& solver::display(std::ostream& out) const {
593         m_egraph.display(out);
594         out << "bool-vars\n";
595         for (unsigned v : m_var_trail) {
596             expr* e = m_bool_var2expr[v];
597             out << v << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1) << "\n";
598         }
599         for (auto* e : m_solvers)
600             e->display(out);
601         return out;
602     }
603 
display_justification_ptr(std::ostream & out,size_t * j) const604     std::ostream& solver::display_justification_ptr(std::ostream& out, size_t* j) const {
605         if (is_literal(j))
606             return out << "sat: " << get_literal(j);
607         else
608             return display_justification(out, get_justification(j));
609     }
610 
display_justification(std::ostream & out,ext_justification_idx idx) const611     std::ostream& solver::display_justification(std::ostream& out, ext_justification_idx idx) const {
612         auto* ext = sat::constraint_base::to_extension(idx);
613         if (ext == this) {
614             constraint& c = constraint::from_idx(idx);
615             switch (c.kind()) {
616             case constraint::kind_t::conflict:
617                 return out << "euf conflict";
618             case constraint::kind_t::eq:
619                 return out << "euf equality propagation";
620             case constraint::kind_t::lit:
621                 return out << "euf literal propagation";
622             default:
623                 UNREACHABLE();
624                 return out;
625             }
626         }
627         else
628             return ext->display_justification(out, idx);
629         return out;
630     }
631 
display_constraint(std::ostream & out,ext_constraint_idx idx) const632     std::ostream& solver::display_constraint(std::ostream& out, ext_constraint_idx idx) const {
633         auto* ext = sat::constraint_base::to_extension(idx);
634         if (ext != this)
635             return ext->display_constraint(out, idx);
636         return display_justification(out, idx);
637     }
638 
collect_statistics(statistics & st) const639     void solver::collect_statistics(statistics& st) const {
640         m_egraph.collect_statistics(st);
641         for (auto* e : m_solvers)
642             e->collect_statistics(st);
643         st.update("euf ackerman", m_stats.m_ackerman);
644     }
645 
copy(solver & dst_ctx,enode * src_n)646     enode* solver::copy(solver& dst_ctx, enode* src_n) {
647         if (!src_n)
648             return nullptr;
649         ast_translation tr(m, dst_ctx.get_manager(), false);
650         expr* e1 = src_n->get_expr();
651         expr* e2 = tr(e1);
652         euf::enode* n2 = dst_ctx.get_enode(e2);
653         SASSERT(n2);
654         return n2;
655     }
656 
copy(sat::solver * s)657     sat::extension* solver::copy(sat::solver* s) {
658         auto* r = alloc(solver, *m_to_m, *m_to_si);
659         r->m_config = m_config;
660         sat::literal true_lit = sat::null_literal;
661         if (s->init_trail_size() > 0)
662             true_lit = s->trail_literal(0);
663         std::function<void* (void*)> copy_justification = [&](void* x) {
664             SASSERT(true_lit != sat::null_literal);
665             return (void*)(r->to_ptr(true_lit));
666         };
667         r->m_egraph.copy_from(m_egraph, copy_justification);
668         r->set_solver(s);
669         for (auto* s_orig : m_id2solver) {
670             if (s_orig) {
671                 auto* s_clone = s_orig->clone(*r);
672                 r->add_solver(s_clone);
673                 s_clone->set_solver(s);
674             }
675         }
676         return r;
677     }
678 
find_mutexes(literal_vector & lits,vector<literal_vector> & mutexes)679     void solver::find_mutexes(literal_vector& lits, vector<literal_vector> & mutexes) {
680         for (auto* e : m_solvers)
681             e->find_mutexes(lits, mutexes);
682     }
683 
gc()684     void solver::gc() {
685         for (auto* e : m_solvers)
686             e->gc();
687     }
688 
pop_reinit()689     void solver::pop_reinit() {
690         finish_reinit();
691         for (auto* e : m_solvers)
692             e->pop_reinit();
693 
694 #if 0
695         for (enode* n : m_egraph.nodes()) {
696             if (n->bool_var() != sat::null_bool_var && s().is_free(n->bool_var()))
697                 std::cout << "has free " << n->bool_var() << "\n";
698         }
699 #endif
700     }
701 
validate()702     bool solver::validate() {
703         for (auto* e : m_solvers)
704             if (!e->validate())
705                 return false;
706         check_eqc_bool_assignment();
707         check_missing_bool_enode_propagation();
708         check_missing_eq_propagation();
709         m_egraph.invariant();
710         return true;
711     }
712 
init_use_list(sat::ext_use_list & ul)713     void solver::init_use_list(sat::ext_use_list& ul) {
714         for (auto* e : m_solvers)
715             e->init_use_list(ul);
716     }
717 
is_blocked(literal l,ext_constraint_idx idx)718     bool solver::is_blocked(literal l, ext_constraint_idx idx) {
719         auto* ext = sat::constraint_base::to_extension(idx);
720         if (ext != this)
721             return ext->is_blocked(l, idx);
722         return false;
723     }
724 
check_model(sat::model const & m) const725     bool solver::check_model(sat::model const& m) const {
726         for (auto* e : m_solvers)
727             if (!e->check_model(m))
728                 return false;
729         return true;
730     }
731 
gc_vars(unsigned num_vars)732     void solver::gc_vars(unsigned num_vars) {
733         for (auto* e : m_solvers)
734             e->gc_vars(num_vars);
735     }
736 
get_reward(literal l,ext_constraint_idx idx,sat::literal_occs_fun & occs) const737     double solver::get_reward(literal l, ext_constraint_idx idx, sat::literal_occs_fun& occs) const {
738         auto* ext = sat::constraint_base::to_extension(idx);
739         SASSERT(ext);
740         return (ext == this) ? 0 : ext->get_reward(l, idx, occs);
741     }
742 
is_extended_binary(ext_justification_idx idx,literal_vector & r)743     bool solver::is_extended_binary(ext_justification_idx idx, literal_vector& r) {
744         auto* ext = sat::constraint_base::to_extension(idx);
745         SASSERT(ext);
746         return (ext != this) && ext->is_extended_binary(idx, r);
747     }
748 
init_ackerman()749     void solver::init_ackerman() {
750         if (m_ackerman)
751             return;
752         if (m_config.m_dack == dyn_ack_strategy::DACK_DISABLED)
753             return;
754         m_ackerman = alloc(ackerman, *this, m);
755         std::function<void(expr*,expr*,expr*)> used_eq = [&](expr* a, expr* b, expr* lca) {
756             m_ackerman->used_eq_eh(a, b, lca);
757         };
758         std::function<void(app*,app*)> used_cc = [&](app* a, app* b) {
759             m_ackerman->used_cc_eh(a, b);
760         };
761         m_egraph.set_used_eq(used_eq);
762         m_egraph.set_used_cc(used_cc);
763     }
764 
to_formulas(std::function<expr_ref (sat::literal)> & l2e,expr_ref_vector & fmls)765     bool solver::to_formulas(std::function<expr_ref(sat::literal)>& l2e, expr_ref_vector& fmls) {
766         for (auto* th : m_solvers) {
767             if (!th->to_formulas(l2e, fmls))
768                 return false;
769         }
770         for (euf::enode* n : m_egraph.nodes()) {
771             if (!n->is_root())
772                 fmls.push_back(m.mk_eq(n->get_expr(), n->get_root()->get_expr()));
773         }
774         return true;
775     }
776 
extract_pb(std::function<void (unsigned sz,literal const * c,unsigned k)> & card,std::function<void (unsigned sz,literal const * c,unsigned const * coeffs,unsigned k)> & pb)777     bool solver::extract_pb(std::function<void(unsigned sz, literal const* c, unsigned k)>& card,
778                             std::function<void(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k)>& pb) {
779         for (auto* e : m_solvers)
780             if (!e->extract_pb(card, pb))
781                 return false;
782         return true;
783     }
784 
user_propagate_init(void * ctx,::solver::push_eh_t & push_eh,::solver::pop_eh_t & pop_eh,::solver::fresh_eh_t & fresh_eh)785     void solver::user_propagate_init(
786         void* ctx,
787         ::solver::push_eh_t& push_eh,
788         ::solver::pop_eh_t& pop_eh,
789         ::solver::fresh_eh_t& fresh_eh) {
790         m_user_propagator = alloc(user::solver, *this);
791         m_user_propagator->add(ctx, push_eh, pop_eh, fresh_eh);
792         for (unsigned i = m_scopes.size(); i-- > 0; )
793             m_user_propagator->push();
794         m_solvers.push_back(m_user_propagator);
795         m_id2solver.setx(m_user_propagator->get_id(), m_user_propagator, nullptr);
796     }
797 
watches_fixed(enode * n) const798     bool solver::watches_fixed(enode* n) const {
799         return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_id()) != null_theory_var;
800     }
801 
assign_fixed(enode * n,expr * val,unsigned sz,literal const * explain)802     void solver::assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain) {
803         theory_var v = n->get_th_var(m_user_propagator->get_id());
804         m_user_propagator->new_fixed_eh(v, val, sz, explain);
805     }
806 
807 
808 }
809