mirror of
https://github.com/Z3Prover/z3
synced 2025-06-26 07:43:41 +00:00
updates to euf-completion to
This commit is contained in:
parent
9db227dbf1
commit
9d35a8c702
3 changed files with 239 additions and 112 deletions
|
@ -38,15 +38,10 @@ Algorithm for extracting canonical form from an E-graph:
|
||||||
Conditional saturation:
|
Conditional saturation:
|
||||||
- forall X . Body => Head
|
- forall X . Body => Head
|
||||||
- propagate when (all assertions in) Body is merged with True
|
- propagate when (all assertions in) Body is merged with True
|
||||||
- Possible efficient approaches:
|
- insert expressions from Body into a watch list.
|
||||||
- use on_merge?
|
When elements of the watch list are merged by true/false
|
||||||
- or bit set in nodes with Body?
|
trigger rep-propagation with respect to body.
|
||||||
- register Boolean reduction rules to EUF?
|
|
||||||
- register function "body_of" and monitor merges based on function?
|
|
||||||
|
|
||||||
Delayed solver invocation
|
|
||||||
- So far default code for checking rules
|
|
||||||
- EUF check should be on demand, see note on conditional saturation
|
|
||||||
|
|
||||||
Mam optimization?
|
Mam optimization?
|
||||||
match(p, t, S) = suppose all variables in p are bound in S, check equality using canonization of p[S], otherwise prune instances from S.
|
match(p, t, S) = suppose all variables in p are bound in S, check equality using canonization of p[S], otherwise prune instances from S.
|
||||||
|
@ -59,10 +54,11 @@ Mam optimization?
|
||||||
#include "ast/rewriter/var_subst.h"
|
#include "ast/rewriter/var_subst.h"
|
||||||
#include "ast/simplifiers/euf_completion.h"
|
#include "ast/simplifiers/euf_completion.h"
|
||||||
#include "ast/shared_occs.h"
|
#include "ast/shared_occs.h"
|
||||||
|
#include "params/tactic_params.hpp"
|
||||||
|
|
||||||
namespace euf {
|
namespace euf {
|
||||||
|
|
||||||
completion::completion(ast_manager& m, dependent_expr_state& fmls):
|
completion::completion(ast_manager& m, dependent_expr_state& fmls) :
|
||||||
dependent_expr_simplifier(m, fmls),
|
dependent_expr_simplifier(m, fmls),
|
||||||
m_egraph(m),
|
m_egraph(m),
|
||||||
m_mam(mam::mk(*this, *this)),
|
m_mam(mam::mk(*this, *this)),
|
||||||
|
@ -77,13 +73,14 @@ namespace euf {
|
||||||
|
|
||||||
std::function<void(euf::enode*, euf::enode*)> _on_merge =
|
std::function<void(euf::enode*, euf::enode*)> _on_merge =
|
||||||
[&](euf::enode* root, euf::enode* other) {
|
[&](euf::enode* root, euf::enode* other) {
|
||||||
m_mam->on_merge(root, other);
|
m_mam->on_merge(root, other);
|
||||||
};
|
watch_rule(root, other);
|
||||||
|
};
|
||||||
|
|
||||||
std::function<void(euf::enode*)> _on_make =
|
std::function<void(euf::enode*)> _on_make =
|
||||||
[&](euf::enode* n) {
|
[&](euf::enode* n) {
|
||||||
m_mam->add_node(n, false);
|
m_mam->add_node(n, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
m_egraph.set_on_merge(_on_merge);
|
m_egraph.set_on_merge(_on_merge);
|
||||||
m_egraph.set_on_make(_on_make);
|
m_egraph.set_on_make(_on_make);
|
||||||
|
@ -92,9 +89,76 @@ namespace euf {
|
||||||
completion::~completion() {
|
completion::~completion() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool completion::should_stop() {
|
||||||
|
return
|
||||||
|
!m.inc() ||
|
||||||
|
m_egraph.inconsistent() ||
|
||||||
|
m_fmls.inconsistent() ||
|
||||||
|
resource_limits_exceeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void completion::updt_params(params_ref const& p) {
|
||||||
|
tactic_params tp(p);
|
||||||
|
m_max_instantiations = tp.completion_max_instantiations();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct completion::push_watch_rule : public trail {
|
||||||
|
vector<ptr_vector<conditional_rule>>& m_rules;
|
||||||
|
unsigned idx;
|
||||||
|
push_watch_rule(vector<ptr_vector<conditional_rule>>& r, unsigned i) : m_rules(r), idx(i) {}
|
||||||
|
void undo() override {
|
||||||
|
m_rules[idx].pop_back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void completion::push() {
|
||||||
|
if (m_side_condition_solver)
|
||||||
|
m_side_condition_solver->push();
|
||||||
|
m_egraph.push();
|
||||||
|
dependent_expr_simplifier::push();
|
||||||
|
}
|
||||||
|
|
||||||
|
void completion::pop(unsigned n) {
|
||||||
|
clear_propagation_queue();
|
||||||
|
dependent_expr_simplifier::pop(n);
|
||||||
|
m_egraph.pop(n);
|
||||||
|
if (m_side_condition_solver)
|
||||||
|
m_side_condition_solver->pop(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void completion::clear_propagation_queue() {
|
||||||
|
for (auto r : m_propagation_queue)
|
||||||
|
r->m_in_queue = false;
|
||||||
|
m_propagation_queue.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void completion::watch_rule(enode* root, enode* other) {
|
||||||
|
auto oid = other->get_id();
|
||||||
|
if (oid >= m_rule_watch.size())
|
||||||
|
return;
|
||||||
|
if (m_rule_watch[oid].empty())
|
||||||
|
return;
|
||||||
|
auto is_true_or_false = m.is_true(root->get_expr()) || m.is_false(root->get_expr());
|
||||||
|
if (is_true_or_false) {
|
||||||
|
for (auto r : m_rule_watch[oid])
|
||||||
|
if (!r->m_in_queue)
|
||||||
|
r->m_in_queue = true,
|
||||||
|
m_propagation_queue.push_back(r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// root is not true or false, use root to watch rules
|
||||||
|
auto rid = root->get_id();
|
||||||
|
m_rule_watch.reserve(rid + 1);
|
||||||
|
for (auto r : m_rule_watch[oid]) {
|
||||||
|
m_rule_watch[rid].push_back(r);
|
||||||
|
get_trail().push(push_watch_rule(m_rule_watch, rid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void completion::reduce() {
|
void completion::reduce() {
|
||||||
m_has_new_eq = true;
|
m_has_new_eq = true;
|
||||||
for (unsigned rounds = 0; m_has_new_eq && rounds <= 3 && !m_fmls.inconsistent(); ++rounds) {
|
for (unsigned rounds = 0; m_has_new_eq && rounds <= 3 && !should_stop(); ++rounds) {
|
||||||
++m_epoch;
|
++m_epoch;
|
||||||
m_has_new_eq = false;
|
m_has_new_eq = false;
|
||||||
add_egraph();
|
add_egraph();
|
||||||
|
@ -113,13 +177,14 @@ namespace euf {
|
||||||
add_constraint(f, d);
|
add_constraint(f, d);
|
||||||
}
|
}
|
||||||
m_should_propagate = true;
|
m_should_propagate = true;
|
||||||
while (m_should_propagate && m.inc() && !m_egraph.inconsistent()) {
|
while (m_should_propagate && !should_stop()) {
|
||||||
m_should_propagate = false;
|
m_should_propagate = false;
|
||||||
m_egraph.propagate();
|
m_egraph.propagate();
|
||||||
m_mam->propagate();
|
m_mam->propagate();
|
||||||
|
propagate_rules();
|
||||||
IF_VERBOSE(11, verbose_stream() << "propagate " << m_stats.m_num_instances << "\n");
|
IF_VERBOSE(11, verbose_stream() << "propagate " << m_stats.m_num_instances << "\n");
|
||||||
if (!m_should_propagate)
|
if (!m_should_propagate)
|
||||||
check_rules();
|
propagate_all_rules();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +194,7 @@ namespace euf {
|
||||||
auto add_children = [&](enode* n) {
|
auto add_children = [&](enode* n) {
|
||||||
for (auto* ch : enode_args(n))
|
for (auto* ch : enode_args(n))
|
||||||
m_nodes_to_canonize.push_back(ch);
|
m_nodes_to_canonize.push_back(ch);
|
||||||
};
|
};
|
||||||
expr* x, * y;
|
expr* x, * y;
|
||||||
if (m.is_eq(f, x, y)) {
|
if (m.is_eq(f, x, y)) {
|
||||||
enode* a = mk_enode(x);
|
enode* a = mk_enode(x);
|
||||||
|
@ -184,6 +249,8 @@ namespace euf {
|
||||||
d = m.mk_join(d, explain_eq(n, n->get_root()));
|
d = m.mk_join(d, explain_eq(n, n->get_root()));
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
if (m.is_true(n->get_root()->get_expr()))
|
||||||
|
return l_false;
|
||||||
}
|
}
|
||||||
if (m_side_condition_solver) {
|
if (m_side_condition_solver) {
|
||||||
expr_dependency* sd = nullptr;
|
expr_dependency* sd = nullptr;
|
||||||
|
@ -220,48 +287,63 @@ namespace euf {
|
||||||
if (body.empty())
|
if (body.empty())
|
||||||
add_constraint(head, d);
|
add_constraint(head, d);
|
||||||
else {
|
else {
|
||||||
m_rules.push_back(alloc(ground_rule, body, head, d));
|
// create a new rule.
|
||||||
|
// add all (one is actually enough) parts of the body to watch list.
|
||||||
|
auto r = alloc(conditional_rule, body, head, d);
|
||||||
|
m_rules.push_back(r);
|
||||||
|
get_trail().push(new_obj_trail(r));
|
||||||
get_trail().push(push_back_vector(m_rules));
|
get_trail().push(push_back_vector(m_rules));
|
||||||
}
|
for (auto f : body) {
|
||||||
}
|
auto n = m_egraph.find(f)->get_root();
|
||||||
|
if (m.is_not(n->get_expr()))
|
||||||
void completion::check_rules() {
|
n = n->get_arg(0)->get_root();
|
||||||
for (auto& r : m_rules) {
|
m_rule_watch.reserve(n->get_id() + 1);
|
||||||
if (!r->m_active)
|
m_rule_watch[n->get_id()].push_back(r);
|
||||||
continue;
|
get_trail().push(push_watch_rule(m_rule_watch, n->get_id()));
|
||||||
switch (check_rule(*r)) {
|
|
||||||
case l_true:
|
|
||||||
get_trail().push(value_trail(r->m_active));
|
|
||||||
r->m_active = false;
|
|
||||||
break; // remove rule, it is activated
|
|
||||||
case l_false:
|
|
||||||
get_trail().push(value_trail(r->m_active));
|
|
||||||
r->m_active = false;
|
|
||||||
break; // remove rule, premise is false
|
|
||||||
case l_undef:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool completion::check_rule(ground_rule& r) {
|
void completion::propagate_all_rules() {
|
||||||
|
for (auto* r : m_rules)
|
||||||
|
if (!r->m_in_queue)
|
||||||
|
r->m_in_queue = true,
|
||||||
|
m_propagation_queue.push_back(r);
|
||||||
|
propagate_rules();
|
||||||
|
}
|
||||||
|
|
||||||
|
void completion::propagate_rules() {
|
||||||
|
for (unsigned i = 0; i < m_propagation_queue.size() && !should_stop(); ++i) {
|
||||||
|
auto r = m_propagation_queue[i];
|
||||||
|
r->m_in_queue = false;
|
||||||
|
propagate_rule(*r);
|
||||||
|
}
|
||||||
|
clear_propagation_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void completion::propagate_rule(conditional_rule& r) {
|
||||||
|
if (!r.m_active)
|
||||||
|
return;
|
||||||
for (auto* f : r.m_body) {
|
for (auto* f : r.m_body) {
|
||||||
switch (eval_cond(f, r.m_dep)) {
|
switch (eval_cond(f, r.m_dep)) {
|
||||||
case l_true:
|
case l_true:
|
||||||
break;
|
break;
|
||||||
case l_false:
|
case l_false:
|
||||||
return l_false;
|
get_trail().push(value_trail(r.m_active));
|
||||||
|
r.m_active = false;
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (r.m_body.empty()) {
|
if (r.m_body.empty()) {
|
||||||
add_constraint(r.m_head, r.m_dep);
|
add_constraint(r.m_head, r.m_dep);
|
||||||
return l_true;
|
get_trail().push(value_trail(r.m_active));
|
||||||
|
r.m_active = false;
|
||||||
}
|
}
|
||||||
return l_undef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// callback when mam finds a binding
|
||||||
void completion::on_binding(quantifier* q, app* pat, enode* const* binding, unsigned mg, unsigned ming, unsigned mx) {
|
void completion::on_binding(quantifier* q, app* pat, enode* const* binding, unsigned mg, unsigned ming, unsigned mx) {
|
||||||
if (m_egraph.inconsistent())
|
if (m_egraph.inconsistent())
|
||||||
return;
|
return;
|
||||||
|
@ -272,6 +354,7 @@ namespace euf {
|
||||||
expr_ref r = subst(q->get_expr(), _binding);
|
expr_ref r = subst(q->get_expr(), _binding);
|
||||||
IF_VERBOSE(12, verbose_stream() << "add " << r << "\n");
|
IF_VERBOSE(12, verbose_stream() << "add " << r << "\n");
|
||||||
add_constraint(r, get_dependency(q));
|
add_constraint(r, get_dependency(q));
|
||||||
|
propagate_rules();
|
||||||
m_should_propagate = true;
|
m_should_propagate = true;
|
||||||
++m_stats.m_num_instances;
|
++m_stats.m_num_instances;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +444,7 @@ namespace euf {
|
||||||
|
|
||||||
auto is_nullary = [&](expr* e) {
|
auto is_nullary = [&](expr* e) {
|
||||||
return is_app(e) && to_app(e)->get_num_args() == 0;
|
return is_app(e) && to_app(e)->get_num_args() == 0;
|
||||||
};
|
};
|
||||||
expr* x, * y;
|
expr* x, * y;
|
||||||
if (m.is_eq(f, x, y)) {
|
if (m.is_eq(f, x, y)) {
|
||||||
expr_ref x1 = canonize(x, d);
|
expr_ref x1 = canonize(x, d);
|
||||||
|
@ -576,7 +659,7 @@ namespace euf {
|
||||||
m_reps.setx(n->get_id(), rep, nullptr);
|
m_reps.setx(n->get_id(), rep, nullptr);
|
||||||
|
|
||||||
TRACE(euf_completion, tout << "rep " << m_egraph.bpp(n) << " -> " << m_egraph.bpp(rep) << "\n";
|
TRACE(euf_completion, tout << "rep " << m_egraph.bpp(n) << " -> " << m_egraph.bpp(rep) << "\n";
|
||||||
for (enode* k : enode_class(n)) tout << m_egraph.bpp(k) << "\n";);
|
for (enode* k : enode_class(n)) tout << m_egraph.bpp(k) << "\n";);
|
||||||
m_todo.push_back(n->get_expr());
|
m_todo.push_back(n->get_expr());
|
||||||
for (enode* arg : enode_args(n)) {
|
for (enode* arg : enode_args(n)) {
|
||||||
arg = arg->get_root();
|
arg = arg->get_root();
|
||||||
|
@ -636,5 +719,4 @@ namespace euf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,7 +7,10 @@ Module Name:
|
||||||
|
|
||||||
Abstract:
|
Abstract:
|
||||||
|
|
||||||
Ground completion for equalities
|
Completion for (conditional) equalities.
|
||||||
|
This transforms expressions into a normal form by perorming equality saturation modulo
|
||||||
|
ground equations and E-matching on quantified axioms.
|
||||||
|
It supports conditional equations in terms of implications.
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
|
|
||||||
|
@ -27,11 +30,17 @@ namespace euf {
|
||||||
|
|
||||||
class side_condition_solver {
|
class side_condition_solver {
|
||||||
public:
|
public:
|
||||||
|
struct solution {
|
||||||
|
expr* var;
|
||||||
|
expr_ref term;
|
||||||
|
expr_ref guard;
|
||||||
|
};
|
||||||
virtual ~side_condition_solver() = default;
|
virtual ~side_condition_solver() = default;
|
||||||
virtual void add_constraint(expr* f, expr_dependency* d) = 0;
|
virtual void add_constraint(expr* f, expr_dependency* d) = 0;
|
||||||
virtual bool is_true(expr* f, expr_dependency*& d) = 0;
|
virtual bool is_true(expr* f, expr_dependency*& d) = 0;
|
||||||
virtual void push() = 0;
|
virtual void push() = 0;
|
||||||
virtual void pop(unsigned n) = 0;
|
virtual void pop(unsigned n) = 0;
|
||||||
|
virtual void solve_for(vector<solution>& sol) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class completion : public dependent_expr_simplifier, public on_binding_callback, public mam_solver {
|
class completion : public dependent_expr_simplifier, public on_binding_callback, public mam_solver {
|
||||||
|
@ -42,12 +51,13 @@ namespace euf {
|
||||||
void reset() { memset(this, 0, sizeof(*this)); }
|
void reset() { memset(this, 0, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ground_rule {
|
struct conditional_rule {
|
||||||
expr_ref_vector m_body;
|
expr_ref_vector m_body;
|
||||||
expr_ref m_head;
|
expr_ref m_head;
|
||||||
expr_dependency* m_dep;
|
expr_dependency* m_dep;
|
||||||
bool m_active = true;
|
bool m_active = true;
|
||||||
ground_rule(expr_ref_vector& b, expr_ref& h, expr_dependency* d) :
|
bool m_in_queue = false;
|
||||||
|
conditional_rule(expr_ref_vector& b, expr_ref& h, expr_dependency* d) :
|
||||||
m_body(b), m_head(h), m_dep(d) {}
|
m_body(b), m_head(h), m_dep(d) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,9 +74,11 @@ namespace euf {
|
||||||
th_rewriter m_rewriter;
|
th_rewriter m_rewriter;
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
scoped_ptr<side_condition_solver> m_side_condition_solver;
|
scoped_ptr<side_condition_solver> m_side_condition_solver;
|
||||||
ptr_vector<ground_rule> m_rules;
|
ptr_vector<conditional_rule> m_rules;
|
||||||
bool m_has_new_eq = false;
|
bool m_has_new_eq = false;
|
||||||
bool m_should_propagate = false;
|
bool m_should_propagate = false;
|
||||||
|
unsigned m_max_instantiations = std::numeric_limits<unsigned>::max();
|
||||||
|
vector<ptr_vector<conditional_rule>> m_rule_watch;
|
||||||
|
|
||||||
enode* mk_enode(expr* e);
|
enode* mk_enode(expr* e);
|
||||||
bool is_new_eq(expr* a, expr* b);
|
bool is_new_eq(expr* a, expr* b);
|
||||||
|
@ -87,32 +99,38 @@ namespace euf {
|
||||||
|
|
||||||
lbool eval_cond(expr* f, expr_dependency*& d);
|
lbool eval_cond(expr* f, expr_dependency*& d);
|
||||||
|
|
||||||
lbool check_rule(ground_rule& rule);
|
|
||||||
void check_rules();
|
bool should_stop();
|
||||||
|
|
||||||
void add_rule(expr* f, expr_dependency* d);
|
void add_rule(expr* f, expr_dependency* d);
|
||||||
|
void watch_rule(enode* root, enode* other);
|
||||||
|
void propagate_rule(conditional_rule& r);
|
||||||
|
void propagate_rules();
|
||||||
|
void propagate_all_rules();
|
||||||
|
void clear_propagation_queue();
|
||||||
|
ptr_vector<conditional_rule> m_propagation_queue;
|
||||||
|
struct push_watch_rule;
|
||||||
|
|
||||||
bool is_gt(expr* a, expr* b) const;
|
bool is_gt(expr* a, expr* b) const;
|
||||||
public:
|
public:
|
||||||
completion(ast_manager& m, dependent_expr_state& fmls);
|
completion(ast_manager& m, dependent_expr_state& fmls);
|
||||||
~completion() override;
|
~completion() override;
|
||||||
char const* name() const override { return "euf-completion"; }
|
char const* name() const override { return "euf-completion"; }
|
||||||
void push() override { if (m_side_condition_solver) m_side_condition_solver->push(); m_egraph.push(); dependent_expr_simplifier::push(); }
|
void push() override;
|
||||||
void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_egraph.pop(n); if (m_side_condition_solver) m_side_condition_solver->pop(1);
|
void pop(unsigned n) override;
|
||||||
}
|
|
||||||
void reduce() override;
|
void reduce() override;
|
||||||
void collect_statistics(statistics& st) const override;
|
void collect_statistics(statistics& st) const override;
|
||||||
void reset_statistics() override { m_stats.reset(); }
|
void reset_statistics() override { m_stats.reset(); }
|
||||||
|
void updt_params(params_ref const& p) override;
|
||||||
|
|
||||||
trail_stack& get_trail() override { return m_trail;}
|
trail_stack& get_trail() override { return m_trail;}
|
||||||
region& get_region() override { return m_trail.get_region(); }
|
region& get_region() override { return m_trail.get_region(); }
|
||||||
egraph& get_egraph() override { return m_egraph; }
|
egraph& get_egraph() override { return m_egraph; }
|
||||||
bool is_relevant(enode* n) const override { return true; }
|
bool is_relevant(enode* n) const override { return true; }
|
||||||
bool resource_limits_exceeded() const override { return false; }
|
bool resource_limits_exceeded() const override { return m_stats.m_num_instances > m_max_instantiations; }
|
||||||
ast_manager& get_manager() override { return m; }
|
ast_manager& get_manager() override { return m; }
|
||||||
|
|
||||||
void on_binding(quantifier* q, app* pat, enode* const* binding, unsigned mg, unsigned ming, unsigned mx) override;
|
void on_binding(quantifier* q, app* pat, enode* const* binding, unsigned mg, unsigned ming, unsigned mx) override;
|
||||||
|
|
||||||
void set_solver(side_condition_solver* s) { m_side_condition_solver = s; }
|
void set_solver(side_condition_solver* s) { m_side_condition_solver = s; }
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ Author:
|
||||||
#include "tactic/tactic.h"
|
#include "tactic/tactic.h"
|
||||||
#include "tactic/portfolio/euf_completion_tactic.h"
|
#include "tactic/portfolio/euf_completion_tactic.h"
|
||||||
#include "solver/solver.h"
|
#include "solver/solver.h"
|
||||||
|
#include "smt/smt_solver.h"
|
||||||
|
|
||||||
class euf_side_condition_solver : public euf::side_condition_solver {
|
class euf_side_condition_solver : public euf::side_condition_solver {
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
|
@ -25,55 +26,81 @@ class euf_side_condition_solver : public euf::side_condition_solver {
|
||||||
scoped_ptr<solver> m_solver;
|
scoped_ptr<solver> m_solver;
|
||||||
expr_ref_vector m_deps;
|
expr_ref_vector m_deps;
|
||||||
obj_map<expr, expr_dependency*> m_e2d;
|
obj_map<expr, expr_dependency*> m_e2d;
|
||||||
|
expr_ref_vector m_fmls;
|
||||||
|
obj_hashtable<expr> m_seen;
|
||||||
|
trail_stack m_trail;
|
||||||
|
|
||||||
void init_solver() {
|
void init_solver() {
|
||||||
if (m_solver.get())
|
if (m_solver.get())
|
||||||
return;
|
return;
|
||||||
m_params.set_uint("smt.max_conflicts", 100);
|
m_params.set_uint("smt.max_conflicts", 100);
|
||||||
scoped_ptr<solver_factory> f = mk_smt_strategic_solver_factory();
|
scoped_ptr<solver_factory> f = mk_smt_solver_factory();
|
||||||
m_solver = (*f)(m, m_params, false, false, true, symbol::null);
|
m_solver = (*f)(m, m_params, false, false, true, symbol::null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
euf_side_condition_solver(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_deps(m) {}
|
|
||||||
|
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 {
|
void push() override {
|
||||||
init_solver();
|
init_solver();
|
||||||
m_solver->push();
|
m_solver->push();
|
||||||
|
m_trail.pop_scope(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop(unsigned n) override {
|
void pop(unsigned n) override {
|
||||||
|
m_trail.push_scope();
|
||||||
SASSERT(m_solver.get());
|
SASSERT(m_solver.get());
|
||||||
m_solver->pop(n);
|
m_solver->pop(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_constraint(expr* f, expr_dependency* d) override {
|
void add_constraint(expr* f, 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))
|
if (!is_ground(f))
|
||||||
return;
|
return;
|
||||||
|
if (m.is_implies(f))
|
||||||
|
return;
|
||||||
init_solver();
|
init_solver();
|
||||||
expr* e_dep = nullptr;
|
|
||||||
if (d) {
|
if (d) {
|
||||||
e_dep = m.mk_fresh_const("dep", m.mk_bool_sort());
|
expr* e_dep = m.mk_fresh_const("dep", m.mk_bool_sort());
|
||||||
m_deps.push_back(e_dep);
|
m_deps.push_back(e_dep);
|
||||||
m_e2d.insert(e_dep, d);
|
m_e2d.insert(e_dep, d);
|
||||||
|
m_trail.push(insert_obj_map(m_e2d, e_dep));
|
||||||
|
m_solver->assert_expr(f, e_dep);
|
||||||
}
|
}
|
||||||
m_solver->assert_expr(f, e_dep);
|
else
|
||||||
|
m_solver->assert_expr(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_true(expr* f, expr_dependency*& d) override {
|
bool is_true(expr* f, expr_dependency*& d) override {
|
||||||
d = nullptr;
|
d = nullptr;
|
||||||
m_solver->push();
|
solver::scoped_push _sp(*m_solver);
|
||||||
expr_ref_vector fmls(m);
|
m_fmls.reset();
|
||||||
fmls.push_back(m.mk_not(f));
|
m_fmls.push_back(m.mk_not(f));
|
||||||
expr_ref nf(m.mk_not(f), m);
|
expr_ref nf(m.mk_not(f), m);
|
||||||
lbool r = m_solver->check_sat(fmls);
|
lbool r = m_solver->check_sat(m_fmls);
|
||||||
if (r == l_false) {
|
if (r == l_false) {
|
||||||
expr_ref_vector core(m);
|
expr_ref_vector core(m);
|
||||||
m_solver->get_unsat_core(core);
|
m_solver->get_unsat_core(core);
|
||||||
for (auto c : core)
|
for (auto c : core)
|
||||||
d = m.mk_join(d, m_e2d[c]);
|
d = m.mk_join(d, m_e2d[c]);
|
||||||
}
|
}
|
||||||
m_solver->pop(1);
|
|
||||||
return r == l_false;
|
return r == l_false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void solve_for(vector<solution>& sol) override {
|
||||||
|
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) {
|
dependent_expr_simplifier* mk_euf_completion_simplifier(ast_manager& m, dependent_expr_state& s, params_ref const& p) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue