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