/*++ Copyright (c) 2022 Microsoft Corporation Module Name: euf_completion_tactic.cpp Abstract: Tactic for simplifying with equations. Author: Nikolaj Bjorner (nbjorner) 2022-10-30 --*/ #include "ast/rewriter/expr_safe_replace.h" #include "tactic/tactic.h" #include "tactic/portfolio/euf_completion_tactic.h" #include "solver/solver.h" #include "smt/smt_solver.h" class euf_side_condition_solver : public euf::side_condition_solver { ast_manager& m; params_ref m_params; scoped_ptr m_solver; expr_ref_vector m_deps; obj_map> m_e2d; expr_ref_vector m_fmls; obj_hashtable m_seen; trail_stack m_trail; void init_solver() { if (m_solver.get()) return; m_params.set_uint("smt.max_conflicts", 100); scoped_ptr f = mk_smt_solver_factory(); m_solver = (*f)(m, m_params, false, false, true, symbol::null); } public: euf_side_condition_solver(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_deps(m), m_fmls(m) {} void push() override { init_solver(); m_solver->push(); m_trail.pop_scope(1); } void pop(unsigned n) override { m_trail.push_scope(); SASSERT(m_solver.get()); m_solver->pop(n); } void add_constraint(expr* f, proof* pr, expr_dependency* d) override { if (m_seen.contains(f)) return; m_seen.insert(f); m_trail.push(insert_obj_trail(m_seen, f)); if (!is_ground(f)) return; if (m.is_implies(f)) return; init_solver(); if (d) { expr* e_dep = m.mk_fresh_const("dep", m.mk_bool_sort()); m_deps.push_back(e_dep); m_e2d.insert(e_dep, { pr, d }); m_trail.push(insert_obj_map(m_e2d, e_dep)); m_solver->assert_expr(f, e_dep); } else m_solver->assert_expr(f); } bool is_true(expr* f, proof_ref& pr, expr_dependency*& d) override { d = nullptr; init_solver(); solver::scoped_push _sp(*m_solver); m_fmls.reset(); m_fmls.push_back(m.mk_not(f)); expr_ref nf(m.mk_not(f), m); lbool r = m_solver->check_sat(m_fmls); if (r == l_false) { expr_ref_vector core(m); m_solver->get_unsat_core(core); for (auto c : core) { if (c == nf) continue; auto [pr, dep] = m_e2d[c]; d = m.mk_join(d, dep); } if (m.proofs_enabled()) { pr = m_solver->get_proof(); SASSERT(pr); expr_safe_replace rep(m); for (auto c : core) { if (c == nf) continue; auto [p, dep] = m_e2d[c]; rep.insert(m.mk_asserted(c), p); } expr_ref ppr(pr, m); rep(ppr); pr = to_app(ppr.get()); } } return r == l_false; } void solve_for(vector& sol) override { init_solver(); vector ss; for (auto [v, t, g] : sol) ss.push_back({ v, t, g }); sol.reset(); m_solver->solve_for(ss); for (auto [v, t, g] : ss) sol.push_back({ v, t, g }); } }; dependent_expr_simplifier* mk_euf_completion_simplifier(ast_manager& m, dependent_expr_state& s, params_ref const& p) { auto r = alloc(euf::completion, m, s); auto scs = alloc(euf_side_condition_solver, m, p); r->set_solver(scs); return r; } tactic * mk_euf_completion_tactic(ast_manager& m, params_ref const& p) { return alloc(dependent_expr_state_tactic, m, p, [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return mk_euf_completion_simplifier(m, s, p); }); }