mirror of
https://github.com/Z3Prover/z3
synced 2025-08-15 07:15:26 +00:00
138 lines
3.9 KiB
C++
138 lines
3.9 KiB
C++
/*++
|
|
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<solver> m_solver;
|
|
expr_ref_vector m_deps;
|
|
obj_map<expr, std::pair<proof*, expr_dependency*>> m_e2d;
|
|
expr_ref_vector m_fmls;
|
|
obj_hashtable<expr> m_seen;
|
|
trail_stack m_trail;
|
|
|
|
void init_solver() {
|
|
if (m_solver.get())
|
|
return;
|
|
m_params.set_uint("smt.max_conflicts", 100);
|
|
scoped_ptr<solver_factory> 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<solution>& sol) override {
|
|
init_solver();
|
|
vector<solver::solution> 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); });
|
|
}
|