mirror of
https://github.com/Z3Prover/z3
synced 2025-08-01 08:53:18 +00:00
Merge branch 'master' of https://github.com/z3prover/z3 into polysat
This commit is contained in:
commit
39f50d46cc
82 changed files with 1049 additions and 599 deletions
|
@ -67,4 +67,7 @@ inline std::string operator+(std::string const& s, mk_pp const& pp) {
|
|||
return strm.str();
|
||||
}
|
||||
|
||||
inline std::string& operator+=(std::string& s, mk_pp const& pp) {
|
||||
return s = s + pp;
|
||||
}
|
||||
|
||||
|
|
|
@ -367,6 +367,25 @@ namespace datatype {
|
|||
return m.mk_func_decl(name, arity, domain, range, info);
|
||||
}
|
||||
|
||||
ptr_vector<constructor> plugin::get_constructors(symbol const& s) const {
|
||||
ptr_vector<constructor> result;
|
||||
for (auto [k, d] : m_defs)
|
||||
for (auto* c : *d)
|
||||
if (c->name() == s)
|
||||
result.push_back(c);
|
||||
return result;
|
||||
}
|
||||
|
||||
ptr_vector<accessor> plugin::get_accessors(symbol const& s) const {
|
||||
ptr_vector<accessor> result;
|
||||
for (auto [k, d] : m_defs)
|
||||
for (auto* c : *d)
|
||||
for (auto* a : *c)
|
||||
if (a->name() == s)
|
||||
result.push_back(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
func_decl * decl::plugin::mk_recognizer(unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort *) {
|
||||
ast_manager& m = *m_manager;
|
||||
|
@ -556,9 +575,8 @@ namespace datatype {
|
|||
|
||||
void plugin::remove(symbol const& s) {
|
||||
def* d = nullptr;
|
||||
if (m_defs.find(s, d)) {
|
||||
if (m_defs.find(s, d))
|
||||
dealloc(d);
|
||||
}
|
||||
m_defs.remove(s);
|
||||
}
|
||||
|
||||
|
@ -688,18 +706,18 @@ namespace datatype {
|
|||
\brief Return true if the inductive datatype is recursive.
|
||||
*/
|
||||
bool util::is_recursive_core(sort* s) const {
|
||||
obj_map<sort, status> already_found;
|
||||
map<symbol, status, symbol_hash_proc, symbol_eq_proc> already_found;
|
||||
ptr_vector<sort> todo, subsorts;
|
||||
sort* s0 = s;
|
||||
todo.push_back(s);
|
||||
status st;
|
||||
status st;
|
||||
while (!todo.empty()) {
|
||||
s = todo.back();
|
||||
if (already_found.find(s, st) && st == BLACK) {
|
||||
if (already_found.find(datatype_name(s), st) && st == BLACK) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
already_found.insert(s, GRAY);
|
||||
already_found.insert(datatype_name(s), GRAY);
|
||||
def const& d = get_def(s);
|
||||
bool can_process = true;
|
||||
for (constructor const* c : d) {
|
||||
|
@ -710,9 +728,9 @@ namespace datatype {
|
|||
get_subsorts(d, subsorts);
|
||||
for (sort * s2 : subsorts) {
|
||||
if (is_datatype(s2)) {
|
||||
if (already_found.find(s2, st)) {
|
||||
if (already_found.find(datatype_name(s2), st)) {
|
||||
// type is recursive
|
||||
if (st == GRAY && s0 == s2)
|
||||
if (st == GRAY && datatype_name(s0) == datatype_name(s2))
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -724,7 +742,7 @@ namespace datatype {
|
|||
}
|
||||
}
|
||||
if (can_process) {
|
||||
already_found.insert(s, BLACK);
|
||||
already_found.insert(datatype_name(s), BLACK);
|
||||
todo.pop_back();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,6 +248,8 @@ namespace datatype {
|
|||
|
||||
def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); }
|
||||
def& get_def(symbol const& s) { return *(m_defs[s]); }
|
||||
ptr_vector<constructor> get_constructors(symbol const& s) const;
|
||||
ptr_vector<accessor> get_accessors(symbol const& s) const;
|
||||
bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); }
|
||||
unsigned get_axiom_base_id(symbol const& s) { return m_axiom_bases[s]; }
|
||||
util & u() const;
|
||||
|
@ -321,6 +323,7 @@ namespace datatype {
|
|||
bool is_covariant(ast_mark& mark, ptr_vector<sort>& subsorts, sort* s) const;
|
||||
def& get_def(symbol const& s) { return plugin().get_def(s); }
|
||||
void get_subsorts(sort* s, ptr_vector<sort>& sorts) const;
|
||||
symbol datatype_name(sort* s) const { return s->get_parameter(0).get_symbol(); }
|
||||
|
||||
public:
|
||||
util(ast_manager & m);
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace euf {
|
|||
void egraph::update_children(enode* n) {
|
||||
for (enode* child : enode_args(n))
|
||||
child->get_root()->add_parent(n);
|
||||
n->set_update_children();
|
||||
m_updates.push_back(update_record(n, update_record::update_children()));
|
||||
}
|
||||
|
||||
enode* egraph::mk(expr* f, unsigned generation, unsigned num_args, enode *const* args) {
|
||||
|
@ -118,14 +118,14 @@ namespace euf {
|
|||
n->set_is_equality();
|
||||
update_children(n);
|
||||
reinsert_equality(n);
|
||||
return n;
|
||||
}
|
||||
enode_bool_pair p = insert_table(n);
|
||||
enode* n2 = p.first;
|
||||
if (n2 == n)
|
||||
update_children(n);
|
||||
else
|
||||
merge(n, n2, justification::congruence(p.second));
|
||||
else {
|
||||
auto [n2, comm] = insert_table(n);
|
||||
if (n2 == n)
|
||||
update_children(n);
|
||||
else
|
||||
merge(n, n2, justification::congruence(comm));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -264,18 +264,21 @@ namespace euf {
|
|||
|
||||
void egraph::set_merge_enabled(enode* n, bool enable_merge) {
|
||||
if (enable_merge != n->merge_enabled()) {
|
||||
toggle_merge_enabled(n);
|
||||
toggle_merge_enabled(n, false);
|
||||
m_updates.push_back(update_record(n, update_record::toggle_merge()));
|
||||
}
|
||||
}
|
||||
|
||||
void egraph::toggle_merge_enabled(enode* n) {
|
||||
void egraph::toggle_merge_enabled(enode* n, bool backtracking) {
|
||||
bool enable_merge = !n->merge_enabled();
|
||||
n->set_merge_enabled(enable_merge);
|
||||
if (n->num_args() > 0) {
|
||||
if (enable_merge)
|
||||
insert_table(n);
|
||||
else if (m_table.contains_ptr(n))
|
||||
if (enable_merge) {
|
||||
auto [n2, comm] = insert_table(n);
|
||||
if (n2 != n && !backtracking)
|
||||
m_to_merge.push_back(to_merge(n, n2, comm));
|
||||
}
|
||||
else if (n->is_cgr())
|
||||
erase_from_table(n);
|
||||
}
|
||||
VERIFY(n->num_args() == 0 || !n->merge_enabled() || m_table.contains(n));
|
||||
|
@ -332,14 +335,15 @@ namespace euf {
|
|||
m_nodes.pop_back();
|
||||
m_exprs.pop_back();
|
||||
};
|
||||
for (unsigned i = m_updates.size(); i-- > num_updates; ) {
|
||||
unsigned sz = m_updates.size();
|
||||
for (unsigned i = sz; i-- > num_updates; ) {
|
||||
auto const& p = m_updates[i];
|
||||
switch (p.tag) {
|
||||
case update_record::tag_t::is_add_node:
|
||||
undo_node();
|
||||
break;
|
||||
case update_record::tag_t::is_toggle_merge:
|
||||
toggle_merge_enabled(p.r1);
|
||||
toggle_merge_enabled(p.r1, true);
|
||||
break;
|
||||
case update_record::tag_t::is_set_parent:
|
||||
undo_eq(p.r1, p.n1, p.r2_num_parents);
|
||||
|
@ -376,12 +380,18 @@ namespace euf {
|
|||
case update_record::tag_t::is_lbl_set:
|
||||
p.r1->m_lbls.set(p.m_lbls);
|
||||
break;
|
||||
case update_record::tag_t::is_update_children:
|
||||
for (unsigned i = 0; i < p.r1->num_args(); ++i) {
|
||||
SASSERT(p.r1->m_args[i]->get_root()->m_parents.back() == p.r1);
|
||||
p.r1->m_args[i]->get_root()->m_parents.pop_back();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SASSERT(m_updates.size() == sz);
|
||||
m_updates.shrink(num_updates);
|
||||
m_scopes.shrink(old_lim);
|
||||
m_region.pop_scope(num_scopes);
|
||||
|
@ -403,7 +413,7 @@ namespace euf {
|
|||
if (r1 == r2)
|
||||
return;
|
||||
|
||||
TRACE("euf", j.display(tout << "merge: " << bpp(n1) << " == " << bpp(n2) << " ", m_display_justification) << "\n";);
|
||||
TRACE("euf", j.display(tout << "merge: " << bpp(n1) << " == " << bpp(n2) << " ", m_display_justification) << "\n" << bpp(r1) << " " << bpp(r2) << "\n";);
|
||||
IF_VERBOSE(20, j.display(verbose_stream() << "merge: " << bpp(n1) << " == " << bpp(n2) << " ", m_display_justification) << "\n";);
|
||||
force_push();
|
||||
SASSERT(m_num_scopes == 0);
|
||||
|
@ -457,12 +467,13 @@ namespace euf {
|
|||
if (!p->is_marked1())
|
||||
continue;
|
||||
p->unmark1();
|
||||
TRACE("euf", tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->merge_enabled() << "\n";);
|
||||
if (p->merge_enabled()) {
|
||||
auto rc = insert_table(p);
|
||||
enode* p_other = rc.first;
|
||||
auto [p_other, comm] = insert_table(p);
|
||||
SASSERT(m_table.contains_ptr(p) == (p_other == p));
|
||||
TRACE("euf", tout << "other " << bpp(p_other) << "\n";);
|
||||
if (p_other != p)
|
||||
m_to_merge.push_back(to_merge(p_other, p, rc.second));
|
||||
m_to_merge.push_back(to_merge(p_other, p, comm));
|
||||
else
|
||||
r2->m_parents.push_back(p);
|
||||
if (p->is_equality())
|
||||
|
@ -752,7 +763,7 @@ namespace euf {
|
|||
out << "] ";
|
||||
}
|
||||
if (n->value() != l_undef)
|
||||
out << "[b" << n->bool_var() << " := " << (n->value() == l_true ? "T":"F") << "] ";
|
||||
out << "[b" << n->bool_var() << " := " << (n->value() == l_true ? "T":"F") << (n->merge_tf()?"":" no merge") << "] ";
|
||||
if (n->has_th_vars()) {
|
||||
out << "[t";
|
||||
for (auto v : enode_th_vars(n))
|
||||
|
|
|
@ -104,7 +104,8 @@ namespace euf {
|
|||
struct value_assignment {};
|
||||
struct lbl_hash {};
|
||||
struct lbl_set {};
|
||||
enum class tag_t { is_set_parent, is_add_node, is_toggle_merge,
|
||||
struct update_children {};
|
||||
enum class tag_t { is_set_parent, is_add_node, is_toggle_merge, is_update_children,
|
||||
is_add_th_var, is_replace_th_var, is_new_lit, is_new_th_eq,
|
||||
is_lbl_hash, is_new_th_eq_qhead, is_new_lits_qhead,
|
||||
is_inconsistent, is_value_assignment, is_lbl_set };
|
||||
|
@ -148,6 +149,8 @@ namespace euf {
|
|||
tag(tag_t::is_lbl_hash), r1(n), n1(nullptr), m_lbl_hash(n->m_lbl_hash) {}
|
||||
update_record(enode* n, lbl_set):
|
||||
tag(tag_t::is_lbl_set), r1(n), n1(nullptr), m_lbls(n->m_lbls.get()) {}
|
||||
update_record(enode* n, update_children) :
|
||||
tag(tag_t::is_update_children), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {}
|
||||
};
|
||||
ast_manager& m;
|
||||
svector<to_merge> m_to_merge;
|
||||
|
@ -211,7 +214,7 @@ namespace euf {
|
|||
void push_to_lca(enode* a, enode* lca);
|
||||
void push_congruence(enode* n1, enode* n2, bool commutative);
|
||||
void push_todo(enode* n);
|
||||
void toggle_merge_enabled(enode* n);
|
||||
void toggle_merge_enabled(enode* n, bool backtracking);
|
||||
|
||||
enode_bool_pair insert_table(enode* p);
|
||||
void erase_from_table(enode* p);
|
||||
|
@ -235,7 +238,7 @@ namespace euf {
|
|||
enode* find(expr* f, unsigned n, enode* const* args);
|
||||
enode* mk(expr* f, unsigned generation, unsigned n, enode *const* args);
|
||||
enode_vector const& enodes_of(func_decl* f);
|
||||
void push() { ++m_num_scopes; }
|
||||
void push() { if (!m_to_merge.empty()) propagate(); ++m_num_scopes; }
|
||||
void pop(unsigned num_scopes);
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,6 @@ namespace euf {
|
|||
bool m_mark1 = false;
|
||||
bool m_mark2 = false;
|
||||
bool m_commutative = false;
|
||||
bool m_update_children = false;
|
||||
bool m_interpreted = false;
|
||||
bool m_merge_enabled = true;
|
||||
bool m_is_equality = false; // Does the expression represent an equality
|
||||
|
@ -124,10 +123,7 @@ namespace euf {
|
|||
n->m_args[i] = nullptr;
|
||||
return n;
|
||||
}
|
||||
|
||||
void set_update_children() { m_update_children = true; }
|
||||
|
||||
|
||||
|
||||
friend class add_th_var_trail;
|
||||
friend class replace_th_var_trail;
|
||||
void add_th_var(theory_var v, theory_id id, region & r) { m_th_vars.add_var(v, id, r); }
|
||||
|
@ -142,12 +138,6 @@ namespace euf {
|
|||
~enode() {
|
||||
SASSERT(m_root == this);
|
||||
SASSERT(class_size() == 1);
|
||||
if (m_update_children) {
|
||||
for (unsigned i = 0; i < num_args(); ++i) {
|
||||
SASSERT(m_args[i]->get_root()->m_parents.back() == this);
|
||||
m_args[i]->get_root()->m_parents.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enode* const* args() const { return m_args; }
|
||||
|
|
|
@ -19,6 +19,7 @@ Notes:
|
|||
#include<math.h>
|
||||
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/well_sorted.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/used_vars.h"
|
||||
|
@ -4430,7 +4431,7 @@ expr* fpa2bv_converter_wrapped::bv2fpa_value(sort* s, expr* a, expr* b, expr* c)
|
|||
mpfm.set(f, ebits, sbits, mpzm.is_one(sgn_z), mpzm.get_int64(exp_u), sig_z);
|
||||
result = m_util.mk_value(f);
|
||||
|
||||
TRACE("t_fpa", tout << "result: [" <<
|
||||
TRACE("t_fpa", tout << mk_pp(a, m) << " " << mk_pp(b, m) << " " << mk_pp(c, m) << " result: [" <<
|
||||
mpzm.to_string(sgn_z) << "," <<
|
||||
mpzm.to_string(exp_z) << "," <<
|
||||
mpzm.to_string(sig_z) << "] --> " <<
|
||||
|
|
|
@ -126,7 +126,7 @@ bool macro_manager::insert(func_decl * f, quantifier * q, proof * pr, expr_depen
|
|||
}
|
||||
|
||||
app * head;
|
||||
expr * definition;
|
||||
expr_ref definition(m);
|
||||
bool revert = false;
|
||||
get_head_def(q, f, head, definition, revert);
|
||||
|
||||
|
@ -190,21 +190,23 @@ void macro_manager::mark_forbidden(unsigned n, justified_expr const * exprs) {
|
|||
}
|
||||
|
||||
|
||||
void macro_manager::get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def, bool& revert) const {
|
||||
app * body = to_app(q->get_expr());
|
||||
void macro_manager::get_head_def(quantifier * q, func_decl * d, app * & head, expr_ref & def, bool& revert) const {
|
||||
expr * body = q->get_expr();
|
||||
expr * lhs = nullptr, *rhs = nullptr;
|
||||
bool is_not = m.is_not(body, body);
|
||||
VERIFY(m.is_eq(body, lhs, rhs));
|
||||
SASSERT(is_app_of(lhs, d) || is_app_of(rhs, d));
|
||||
SASSERT(!is_app_of(lhs, d) || !is_app_of(rhs, d));
|
||||
SASSERT(!is_not || m.is_bool(lhs));
|
||||
if (is_app_of(lhs, d)) {
|
||||
revert = false;
|
||||
head = to_app(lhs);
|
||||
def = rhs;
|
||||
def = is_not ? m.mk_not(rhs) : rhs;
|
||||
}
|
||||
else {
|
||||
revert = true;
|
||||
head = to_app(rhs);
|
||||
def = lhs;
|
||||
def = is_not ? m.mk_not(lhs) : lhs;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +217,7 @@ void macro_manager::display(std::ostream & out) {
|
|||
quantifier * q = nullptr;
|
||||
m_decl2macro.find(f, q);
|
||||
app * head;
|
||||
expr * def;
|
||||
expr_ref def(m);
|
||||
bool r;
|
||||
get_head_def(q, f, head, def, r);
|
||||
SASSERT(q);
|
||||
|
@ -227,7 +229,7 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter
|
|||
func_decl * f = m_decls.get(i);
|
||||
quantifier * q = m_macros.get(i);
|
||||
app * head;
|
||||
expr * def;
|
||||
expr_ref def(m);
|
||||
bool r;
|
||||
get_head_def(q, f, head, def, r);
|
||||
TRACE("macro_bug",
|
||||
|
@ -298,7 +300,7 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
|
|||
TRACE("macro_manager", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
|
||||
if (mm.m_decl2macro.find(d, q)) {
|
||||
app * head = nullptr;
|
||||
expr * def = nullptr;
|
||||
expr_ref def(m);
|
||||
bool revert = false;
|
||||
mm.get_head_def(q, d, head, def, revert);
|
||||
unsigned num = n->get_num_args();
|
||||
|
@ -320,6 +322,14 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
|
|||
r = rr;
|
||||
if (m.proofs_enabled()) {
|
||||
expr_ref instance = s(q->get_expr(), num, subst_args.data());
|
||||
expr* eq, * lhs, * rhs;
|
||||
if (m.is_not(instance, eq) && m.is_eq(eq, lhs, rhs)) {
|
||||
if (revert)
|
||||
instance = m.mk_eq(m.mk_not(lhs), rhs);
|
||||
else
|
||||
instance = m.mk_eq(lhs, m.mk_not(rhs));
|
||||
}
|
||||
SASSERT(m.is_eq(instance));
|
||||
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.data());
|
||||
proof * q_pr = mm.m_decl2macro_pr.find(d);
|
||||
proof * prs[2] = { qi_pr, q_pr };
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
func_decl * get_macro_func_decl(unsigned i) const { return m_decls.get(i); }
|
||||
func_decl * get_macro_interpretation(unsigned i, expr_ref & interp) const;
|
||||
quantifier * get_macro_quantifier(func_decl * f) const { quantifier * q = nullptr; m_decl2macro.find(f, q); return q; }
|
||||
void get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def, bool& revert) const;
|
||||
void get_head_def(quantifier * q, func_decl * d, app * & head, expr_ref & def, bool& revert) const;
|
||||
void expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep);
|
||||
|
||||
|
||||
|
|
|
@ -184,6 +184,15 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he
|
|||
def = rhs;
|
||||
return true;
|
||||
}
|
||||
if (m_manager.is_not(n, lhs) && m_manager.is_eq(lhs, lhs, rhs) &&
|
||||
m_manager.is_bool(lhs) &&
|
||||
is_macro_head(lhs, num_decls) &&
|
||||
!is_forbidden(to_app(lhs)->get_decl()) &&
|
||||
!occurs(to_app(lhs)->get_decl(), rhs)) {
|
||||
head = to_app(lhs);
|
||||
def = m_manager.mk_not(rhs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -215,6 +224,15 @@ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & h
|
|||
def = lhs;
|
||||
return true;
|
||||
}
|
||||
if (m_manager.is_not(n, n) && m_manager.is_eq(n, lhs, rhs) &&
|
||||
m_manager.is_bool(lhs) &&
|
||||
is_macro_head(rhs, num_decls) &&
|
||||
!is_forbidden(to_app(rhs)->get_decl()) &&
|
||||
!occurs(to_app(rhs)->get_decl(), lhs)) {
|
||||
head = to_app(rhs);
|
||||
def = m_manager.mk_not(lhs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,15 @@ bool quasi_macros::depends_on(expr * e, func_decl * f) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool quasi_macros::is_quasi_def(quantifier* q, expr* lhs, expr* rhs) const {
|
||||
return
|
||||
is_non_ground_uninterp(lhs) &&
|
||||
is_unique(to_app(lhs)->get_decl()) &&
|
||||
!depends_on(rhs, to_app(lhs)->get_decl()) &&
|
||||
fully_depends_on(to_app(lhs), q);
|
||||
}
|
||||
|
||||
|
||||
bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
|
||||
// Our definition of a quasi-macro:
|
||||
// Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted,
|
||||
|
@ -158,27 +167,39 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
|
|||
quantifier * q = to_quantifier(e);
|
||||
expr * qe = q->get_expr(), *lhs = nullptr, *rhs = nullptr;
|
||||
if (m.is_eq(qe, lhs, rhs)) {
|
||||
if (is_non_ground_uninterp(lhs) && is_unique(to_app(lhs)->get_decl()) &&
|
||||
!depends_on(rhs, to_app(lhs)->get_decl()) && fully_depends_on(to_app(lhs), q)) {
|
||||
a = to_app(lhs);
|
||||
if (is_quasi_def(q, lhs, rhs)) {
|
||||
a = to_app(lhs);
|
||||
t = rhs;
|
||||
return true;
|
||||
} else if (is_non_ground_uninterp(rhs) && is_unique(to_app(rhs)->get_decl()) &&
|
||||
!depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) {
|
||||
a = to_app(rhs);
|
||||
} else if (is_quasi_def(q, rhs, lhs)) {
|
||||
a = to_app(rhs);
|
||||
t = lhs;
|
||||
return true;
|
||||
}
|
||||
} else if (m.is_not(qe, lhs) && is_non_ground_uninterp(lhs) &&
|
||||
}
|
||||
else if (m.is_not(qe, lhs) && is_non_ground_uninterp(lhs) &&
|
||||
is_unique(to_app(lhs)->get_decl())) { // this is like f(...) = false
|
||||
a = to_app(lhs);
|
||||
t = m.mk_false();
|
||||
return true;
|
||||
} else if (is_non_ground_uninterp(qe) && is_unique(to_app(qe)->get_decl())) { // this is like f(...) = true
|
||||
}
|
||||
else if (is_non_ground_uninterp(qe) && is_unique(to_app(qe)->get_decl())) { // this is like f(...) = true
|
||||
a = to_app(qe);
|
||||
t = m.mk_true();
|
||||
return true;
|
||||
}
|
||||
else if (m.is_not(qe, lhs) && m.is_eq(lhs, lhs, rhs) && m.is_bool(lhs)) {
|
||||
if (is_quasi_def(q, lhs, rhs)) {
|
||||
a = to_app(lhs);
|
||||
t = m.mk_not(rhs);
|
||||
return true;
|
||||
} else if (is_quasi_def(q, rhs, lhs)) {
|
||||
a = to_app(rhs);
|
||||
t = m.mk_not(lhs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -49,6 +49,7 @@ class quasi_macros {
|
|||
bool depends_on(expr * e, func_decl * f) const;
|
||||
|
||||
bool is_quasi_macro(expr * e, app_ref & a, expr_ref &v) const;
|
||||
bool is_quasi_def(quantifier* q, expr* lhs, expr* rhs) const;
|
||||
bool quasi_macro_to_macro(quantifier * q, app * a, expr * t, quantifier_ref & macro);
|
||||
|
||||
void find_occurrences(expr * e);
|
||||
|
|
|
@ -695,6 +695,12 @@ br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result)
|
|||
if (m_util.is_const(rhs) && m_util.is_store(lhs)) {
|
||||
std::swap(lhs, rhs);
|
||||
}
|
||||
if (m_util.is_const(lhs, v) && m_util.is_store(rhs)) {
|
||||
unsigned n = to_app(rhs)->get_num_args();
|
||||
result = m().mk_and(m().mk_eq(lhs, to_app(rhs)->get_arg(0)),
|
||||
m().mk_eq(v, to_app(rhs)->get_arg(n - 1)));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m_util.is_const(lhs, v) && m_util.is_const(rhs, w)) {
|
||||
result = m().mk_eq(v, w);
|
||||
return BR_REWRITE1;
|
||||
|
|
|
@ -35,16 +35,12 @@ protected:
|
|||
void mk_ext_rotate_left_right(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
|
||||
unsigned long long m_max_memory;
|
||||
bool m_use_wtm; /* Wallace Tree Multiplier */
|
||||
bool m_use_bcm; /* Booth Multiplier for constants */
|
||||
void checkpoint();
|
||||
|
||||
public:
|
||||
bit_blaster_tpl(Cfg const & cfg = Cfg(), unsigned long long max_memory = UINT64_MAX, bool use_wtm = false, bool use_bcm=false):
|
||||
bit_blaster_tpl(Cfg const & cfg = Cfg(), unsigned long long max_memory = UINT64_MAX):
|
||||
Cfg(cfg),
|
||||
m_max_memory(max_memory),
|
||||
m_use_wtm(use_wtm),
|
||||
m_use_bcm(use_bcm) {
|
||||
m_max_memory(max_memory) {
|
||||
}
|
||||
|
||||
void set_max_memory(unsigned long long max_memory) {
|
||||
|
@ -121,7 +117,6 @@ public:
|
|||
void mk_comp(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
|
||||
void mk_carry_save_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr * const * c_bits, expr_ref_vector & sum_bits, expr_ref_vector & carry_bits);
|
||||
bool mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
bool mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
void mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer<expr, 128>& a_bits, ptr_buffer<expr, 128>& b_bits, expr_ref_vector & out_bits);
|
||||
|
||||
|
|
|
@ -195,168 +195,88 @@ void bit_blaster_tpl<Cfg>::mk_multiplier(unsigned sz, expr * const * a_bits, exp
|
|||
return;
|
||||
}
|
||||
|
||||
if (mk_const_multiplier(sz, a_bits, b_bits, out_bits)) {
|
||||
SASSERT(sz == out_bits.size());
|
||||
return;
|
||||
}
|
||||
if (mk_const_multiplier(sz, b_bits, a_bits, out_bits)) {
|
||||
if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) {
|
||||
SASSERT(sz == out_bits.size());
|
||||
return;
|
||||
}
|
||||
out_bits.reset();
|
||||
if (!m_use_wtm) {
|
||||
#if 0
|
||||
static unsigned counter = 0;
|
||||
counter++;
|
||||
verbose_stream() << "MK_MULTIPLIER: " << counter << std::endl;
|
||||
#endif
|
||||
|
||||
expr_ref_vector cins(m()), couts(m());
|
||||
expr_ref out(m()), cout(m());
|
||||
|
||||
mk_and(a_bits[0], b_bits[0], out);
|
||||
out_bits.push_back(out);
|
||||
expr_ref_vector cins(m()), couts(m());
|
||||
expr_ref out(m()), cout(m());
|
||||
|
||||
/*
|
||||
out = a*b is encoded using the following circuit.
|
||||
|
||||
a[0]&b[0] a[0]&b[1] a[0]&b[2] a[0]&b[3] ...
|
||||
| | | |
|
||||
| a[1]&b[0] - HA a[1]&b[1] - HA a[1]&b[2] - HA
|
||||
| | \ | \ | \
|
||||
| | --------------- | -------------- | --- ...
|
||||
| | \| \
|
||||
| | a[2]&b[0] - FA a[2]&b[1] - FA
|
||||
| | | \ | \
|
||||
| | | -------------- | -- ...
|
||||
| | | \|
|
||||
| | | a[3]&b[0] - FA
|
||||
| | | | \
|
||||
| | | | -- ....
|
||||
... ... ... ...
|
||||
out[0] out[1] out[2] out[3]
|
||||
|
||||
HA denotes a half-adder.
|
||||
FA denotes a full-adder.
|
||||
*/
|
||||
mk_and(a_bits[0], b_bits[0], out);
|
||||
out_bits.push_back(out);
|
||||
|
||||
for (unsigned i = 1; i < sz; i++) {
|
||||
checkpoint();
|
||||
couts.reset();
|
||||
expr_ref i1(m()), i2(m());
|
||||
mk_and(a_bits[0], b_bits[i], i1);
|
||||
mk_and(a_bits[1], b_bits[i-1], i2);
|
||||
if (i < sz - 1) {
|
||||
mk_half_adder(i1, i2, out, cout);
|
||||
/*
|
||||
out = a*b is encoded using the following circuit.
|
||||
|
||||
a[0]&b[0] a[0]&b[1] a[0]&b[2] a[0]&b[3] ...
|
||||
| | | |
|
||||
| a[1]&b[0] - HA a[1]&b[1] - HA a[1]&b[2] - HA
|
||||
| | \ | \ | \
|
||||
| | --------------- | -------------- | --- ...
|
||||
| | \| \
|
||||
| | a[2]&b[0] - FA a[2]&b[1] - FA
|
||||
| | | \ | \
|
||||
| | | -------------- | -- ...
|
||||
| | | \|
|
||||
| | | a[3]&b[0] - FA
|
||||
| | | | \
|
||||
| | | | -- ....
|
||||
... ... ... ...
|
||||
out[0] out[1] out[2] out[3]
|
||||
|
||||
HA denotes a half-adder.
|
||||
FA denotes a full-adder.
|
||||
*/
|
||||
|
||||
for (unsigned i = 1; i < sz; i++) {
|
||||
checkpoint();
|
||||
couts.reset();
|
||||
expr_ref i1(m()), i2(m());
|
||||
mk_and(a_bits[0], b_bits[i], i1);
|
||||
mk_and(a_bits[1], b_bits[i - 1], i2);
|
||||
if (i < sz - 1) {
|
||||
mk_half_adder(i1, i2, out, cout);
|
||||
couts.push_back(cout);
|
||||
for (unsigned j = 2; j <= i; j++) {
|
||||
expr_ref prev_out(m());
|
||||
prev_out = out;
|
||||
expr_ref i3(m());
|
||||
mk_and(a_bits[j], b_bits[i - j], i3);
|
||||
mk_full_adder(i3, prev_out, cins.get(j - 2), out, cout);
|
||||
couts.push_back(cout);
|
||||
for (unsigned j = 2; j <= i; j++) {
|
||||
expr_ref prev_out(m());
|
||||
prev_out = out;
|
||||
expr_ref i3(m());
|
||||
mk_and(a_bits[j], b_bits[i-j], i3);
|
||||
mk_full_adder(i3, prev_out, cins.get(j-2), out, cout);
|
||||
couts.push_back(cout);
|
||||
}
|
||||
out_bits.push_back(out);
|
||||
cins.swap(couts);
|
||||
}
|
||||
else {
|
||||
// last step --> I don't need to generate/store couts.
|
||||
mk_xor(i1, i2, out);
|
||||
for (unsigned j = 2; j <= i; j++) {
|
||||
expr_ref i3(m());
|
||||
mk_and(a_bits[j], b_bits[i-j], i3);
|
||||
mk_xor3(i3, out, cins.get(j-2), out);
|
||||
}
|
||||
out_bits.push_back(out);
|
||||
out_bits.push_back(out);
|
||||
cins.swap(couts);
|
||||
}
|
||||
else {
|
||||
// last step --> I don't need to generate/store couts.
|
||||
mk_xor(i1, i2, out);
|
||||
for (unsigned j = 2; j <= i; j++) {
|
||||
expr_ref i3(m());
|
||||
mk_and(a_bits[j], b_bits[i - j], i3);
|
||||
mk_xor3(i3, out, cins.get(j - 2), out);
|
||||
}
|
||||
out_bits.push_back(out);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// WALLACE TREE MULTIPLIER
|
||||
|
||||
if (sz == 1) {
|
||||
expr_ref t(m());
|
||||
mk_and(a_bits[0], b_bits[0], t);
|
||||
out_bits.push_back(t);
|
||||
return;
|
||||
}
|
||||
|
||||
// There are sz numbers to add and we use a Wallace tree to reduce that to two.
|
||||
// In this tree, we reduce as early as possible, as opposed to the Dada tree where some
|
||||
// additions may be delayed if they don't increase the propagation delay [which may be
|
||||
// a little bit more efficient, but it's tricky to find out which additions create
|
||||
// additional delays].
|
||||
|
||||
expr_ref zero(m());
|
||||
zero = m().mk_false();
|
||||
|
||||
vector< expr_ref_vector > pps;
|
||||
pps.resize(sz, expr_ref_vector(m()));
|
||||
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
checkpoint();
|
||||
// The partial product is a_bits AND b_bits[i]
|
||||
// [or alternatively ITE(b_bits[i], a_bits, bv0[sz])]
|
||||
|
||||
expr_ref_vector & pp = pps[i];
|
||||
expr_ref t(m());
|
||||
for (unsigned j = 0; j < i; j++)
|
||||
pp.push_back(zero); // left shift by i bits
|
||||
for (unsigned j = 0; j < (sz - i); j++) {
|
||||
mk_and(a_bits[j], b_bits[i], t);
|
||||
pp.push_back(t);
|
||||
}
|
||||
|
||||
SASSERT(pps[i].size() == sz);
|
||||
}
|
||||
|
||||
while (pps.size() != 2) {
|
||||
unsigned save_inx = 0;
|
||||
unsigned i = 0;
|
||||
unsigned end = pps.size() - 3;
|
||||
for ( ; i <= end; i += 3) {
|
||||
checkpoint();
|
||||
expr_ref_vector pp1(m()), pp2(m()), pp3(m());
|
||||
pp1.swap(pps[i]);
|
||||
pp2.swap(pps[i+1]);
|
||||
pp3.swap(pps[i+2]);
|
||||
expr_ref_vector & sum_bits = pps[save_inx];
|
||||
expr_ref_vector & carry_bits = pps[save_inx+1];
|
||||
SASSERT(sum_bits.empty() && carry_bits.empty());
|
||||
carry_bits.push_back(zero);
|
||||
mk_carry_save_adder(pp1.size(), pp1.data(), pp2.data(), pp3.data(), sum_bits, carry_bits);
|
||||
carry_bits.pop_back();
|
||||
save_inx += 2;
|
||||
}
|
||||
|
||||
if (i == pps.size()-2) {
|
||||
pps[save_inx++].swap(pps[i++]);
|
||||
pps[save_inx++].swap(pps[i++]);
|
||||
}
|
||||
else if (i == pps.size()-1) {
|
||||
pps[save_inx++].swap(pps[i++]);
|
||||
}
|
||||
|
||||
SASSERT (save_inx < pps.size() && i == pps.size());
|
||||
pps.shrink(save_inx);
|
||||
}
|
||||
|
||||
SASSERT(pps.size() == 2);
|
||||
|
||||
// Now there are only two numbers to add, we can use a ripple carry adder here.
|
||||
mk_adder(sz, pps[0].data(), pps[1].data(), out_bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Cfg>
|
||||
void bit_blaster_tpl<Cfg>::mk_umul_no_overflow(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref & result) {
|
||||
void bit_blaster_tpl<Cfg>::mk_umul_no_overflow(unsigned sz, expr* const* a_bits, expr* const* b_bits, expr_ref& result) {
|
||||
SASSERT(sz > 0);
|
||||
expr_ref zero(m());
|
||||
zero = m().mk_false();
|
||||
ptr_buffer<expr,128> ext_a_bits;
|
||||
ptr_buffer<expr,128> ext_b_bits;
|
||||
ptr_buffer<expr, 128> ext_a_bits;
|
||||
ptr_buffer<expr, 128> ext_b_bits;
|
||||
ext_a_bits.append(sz, a_bits);
|
||||
ext_b_bits.append(sz, b_bits);
|
||||
ext_a_bits.push_back(zero);
|
||||
|
@ -1196,30 +1116,32 @@ bool bit_blaster_tpl<Cfg>::mk_const_case_multiplier(unsigned sz, expr * const *
|
|||
unsigned case_size = 1;
|
||||
unsigned circuit_size = sz*sz*5;
|
||||
for (unsigned i = 0; case_size < circuit_size && i < sz; ++i) {
|
||||
if (!is_bool_const(a_bits[i])) {
|
||||
case_size *= 2;
|
||||
}
|
||||
if (!is_bool_const(b_bits[i])) {
|
||||
case_size *= 2;
|
||||
}
|
||||
if (!is_bool_const(a_bits[i]))
|
||||
case_size *= 2;
|
||||
if (!is_bool_const(b_bits[i]))
|
||||
case_size *= 2;
|
||||
}
|
||||
if (case_size >= circuit_size) {
|
||||
if (case_size >= circuit_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
SASSERT(out_bits.empty());
|
||||
ptr_buffer<expr, 128> na_bits;
|
||||
na_bits.append(sz, a_bits);
|
||||
ptr_buffer<expr, 128> nb_bits;
|
||||
nb_bits.append(sz, b_bits);
|
||||
mk_const_case_multiplier(true, 0, sz, na_bits, nb_bits, out_bits);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Cfg>
|
||||
void bit_blaster_tpl<Cfg>::mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer<expr, 128>& a_bits, ptr_buffer<expr, 128>& b_bits, expr_ref_vector & out_bits) {
|
||||
while (is_a && i < sz && is_bool_const(a_bits[i])) ++i;
|
||||
if (is_a && i == sz) { is_a = false; i = 0; }
|
||||
while (!is_a && i < sz && is_bool_const(b_bits[i])) ++i;
|
||||
if (is_a && i == sz) {
|
||||
is_a = false;
|
||||
i = 0;
|
||||
}
|
||||
while (!is_a && i < sz && is_bool_const(b_bits[i]))
|
||||
++i;
|
||||
if (i < sz) {
|
||||
expr_ref_vector out1(m()), out2(m());
|
||||
expr_ref x(m());
|
||||
|
@ -1230,9 +1152,11 @@ void bit_blaster_tpl<Cfg>::mk_const_case_multiplier(bool is_a, unsigned i, unsig
|
|||
mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out2);
|
||||
if (is_a) a_bits[i] = x; else b_bits[i] = x;
|
||||
SASSERT(out_bits.empty());
|
||||
expr_ref bit(m());
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
out_bits.push_back(m().mk_ite(x, out1[j].get(), out2[j].get()));
|
||||
}
|
||||
mk_ite(x, out1.get(j), out2.get(j), bit);
|
||||
out_bits.push_back(bit);
|
||||
}
|
||||
}
|
||||
else {
|
||||
numeral n_a, n_b;
|
||||
|
@ -1244,101 +1168,3 @@ void bit_blaster_tpl<Cfg>::mk_const_case_multiplier(bool is_a, unsigned i, unsig
|
|||
}
|
||||
SASSERT(out_bits.size() == sz);
|
||||
}
|
||||
|
||||
template<typename Cfg>
|
||||
bool bit_blaster_tpl<Cfg>::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
|
||||
numeral n_a;
|
||||
if (!is_numeral(sz, a_bits, n_a)) {
|
||||
return false;
|
||||
}
|
||||
SASSERT(out_bits.empty());
|
||||
|
||||
if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) {
|
||||
SASSERT(sz == out_bits.size());
|
||||
return true;
|
||||
}
|
||||
out_bits.reset();
|
||||
if (!m_use_bcm) {
|
||||
return false;
|
||||
}
|
||||
expr_ref_vector minus_b_bits(m()), tmp(m());
|
||||
mk_neg(sz, b_bits, minus_b_bits);
|
||||
|
||||
out_bits.resize(sz, m().mk_false());
|
||||
|
||||
#if 1
|
||||
bool last = false, now;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
now = m().is_true(a_bits[i]);
|
||||
SASSERT(now || m().is_false(a_bits[i]));
|
||||
tmp.reset();
|
||||
|
||||
if (now && !last) {
|
||||
mk_adder(sz - i, out_bits.data() + i, minus_b_bits.data(), tmp);
|
||||
for (unsigned j = 0; j < (sz - i); j++)
|
||||
out_bits.set(i+j, tmp.get(j)); // do not use [], it does not work on Linux.
|
||||
}
|
||||
else if (!now && last) {
|
||||
mk_adder(sz - i, out_bits.data() + i, b_bits, tmp);
|
||||
for (unsigned j = 0; j < (sz - i); j++)
|
||||
out_bits.set(i+j, tmp.get(j)); // do not use [], it does not work on Linux.
|
||||
}
|
||||
|
||||
last = now;
|
||||
}
|
||||
#else
|
||||
// Radix 4 Booth encoder
|
||||
// B = b_bits, -B = minus_b_bits
|
||||
// 2B = b2_bits, -2B = minus_b2_bits
|
||||
|
||||
expr_ref_vector b2_bits(m());
|
||||
expr_ref_vector minus_b2_bits(m());
|
||||
|
||||
b2_bits.push_back(m().mk_false());
|
||||
minus_b2_bits.push_back(m().mk_false());
|
||||
for (unsigned i = 0; i < sz-1; i++) {
|
||||
b2_bits.push_back(b_bits[i]);
|
||||
minus_b2_bits.push_back(minus_b_bits.get(i));
|
||||
}
|
||||
|
||||
bool last=false, now1, now2;
|
||||
for (unsigned i = 0; i < sz; i += 2) {
|
||||
now1 = m().is_true(a_bits[i]);
|
||||
now2 = m().is_true(a_bits[i+1]);
|
||||
SASSERT(now1 || m().is_false(a_bits[i]));
|
||||
SASSERT(now2 || m().is_false(a_bits[i+1]));
|
||||
tmp.reset();
|
||||
|
||||
if ((!now2 && !now1 && last) ||
|
||||
(!now2 && now1 && !last)) { // Add B
|
||||
mk_adder(sz - i, out_bits.c_ptr() + i, b_bits, tmp);
|
||||
for (unsigned j = 0; j < (sz - i); j++)
|
||||
out_bits.set(i+j, tmp.get(j));
|
||||
}
|
||||
else if (!now2 && now1 && last) { // Add 2B
|
||||
mk_adder(sz - i, out_bits.c_ptr() + i, b2_bits.c_ptr(), tmp);
|
||||
for (unsigned j = 0; j < (sz - i); j++)
|
||||
out_bits.set(i+j, tmp.get(j));
|
||||
}
|
||||
else if (now2 && !now1 && !last) { // Add -2B
|
||||
mk_adder(sz - i, out_bits.c_ptr() + i, minus_b2_bits.c_ptr(), tmp);
|
||||
for (unsigned j = 0; j < (sz - i); j++)
|
||||
out_bits.set(i+j, tmp.get(j));
|
||||
}
|
||||
else if ((now2 && !now1 && last) ||
|
||||
(now2 && now1 && !last)) { // Add -B
|
||||
mk_adder(sz - i, out_bits.c_ptr() + i, minus_b_bits.c_ptr(), tmp);
|
||||
for (unsigned j = 0; j < (sz - i); j++)
|
||||
out_bits.set(i+j, tmp.get(j));
|
||||
}
|
||||
|
||||
last = now2;
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE("bit_blaster_tpl_booth", for (unsigned i=0; i<out_bits.size(); i++)
|
||||
tout << "Booth encoding: " << mk_pp(out_bits[i].get(), m()) << "\n"; );
|
||||
|
||||
SASSERT(out_bits.size() == sz);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -721,9 +721,18 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (m().is_not(rhs))
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
if (m().is_not(lhs, lhs)) {
|
||||
result = m().mk_not(m().mk_eq(lhs, rhs));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
if (unfolded) {
|
||||
result = mk_eq(lhs, rhs);
|
||||
return BR_DONE;
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
|
||||
expr *la, *lb, *ra, *rb;
|
||||
|
|
|
@ -137,6 +137,11 @@ public:
|
|||
mk_eq(lhs, rhs, r);
|
||||
return r;
|
||||
}
|
||||
expr_ref mk_xor(expr* a, expr* b) {
|
||||
expr_ref result(m());
|
||||
mk_xor(a, b, result);
|
||||
return result;
|
||||
}
|
||||
void mk_iff(expr * lhs, expr * rhs, expr_ref & result) { mk_eq(lhs, rhs, result); }
|
||||
void mk_xor(expr * lhs, expr * rhs, expr_ref & result);
|
||||
void mk_and(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
|
@ -169,6 +174,16 @@ public:
|
|||
mk_and(args.size(), args.data(), result);
|
||||
return result;
|
||||
}
|
||||
expr_ref mk_and(expr* a, expr* b) {
|
||||
expr_ref result(m());
|
||||
mk_and(a, b, result);
|
||||
return result;
|
||||
}
|
||||
expr_ref mk_or(expr* a, expr* b) {
|
||||
expr_ref result(m());
|
||||
mk_or(a, b, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void mk_and(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
expr * args[2] = {arg1, arg2};
|
||||
|
|
|
@ -136,8 +136,12 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
var * v = nullptr;
|
||||
expr_ref t(m);
|
||||
|
||||
if (m.is_or(e)) {
|
||||
unsigned num_args = to_app(e)->get_num_args();
|
||||
if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t))
|
||||
r = m.mk_false();
|
||||
else {
|
||||
expr_ref_vector ors(m);
|
||||
flatten_or(e, ors);
|
||||
unsigned num_args = ors.size();
|
||||
unsigned diseq_count = 0;
|
||||
unsigned largest_vinx = 0;
|
||||
|
||||
|
@ -149,7 +153,7 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
|
||||
// Find all disequalities
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
if (is_var_diseq(to_app(e)->get_arg(i), num_decls, v, t)) {
|
||||
if (is_var_diseq(ors.get(i), num_decls, v, t)) {
|
||||
unsigned idx = v->get_idx();
|
||||
if (m_map.get(idx, nullptr) == nullptr) {
|
||||
m_map.reserve(idx + 1);
|
||||
|
@ -170,7 +174,7 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
|
||||
if (!m_order.empty()) {
|
||||
create_substitution(largest_vinx + 1);
|
||||
apply_substitution(q, r);
|
||||
apply_substitution(q, ors, r);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -180,11 +184,6 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
}
|
||||
// Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses.
|
||||
// So, we must perform a occurs check here.
|
||||
else if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t)) {
|
||||
r = m.mk_false();
|
||||
}
|
||||
else
|
||||
r = q;
|
||||
|
||||
if (m.proofs_enabled()) {
|
||||
pr = r == q ? nullptr : m.mk_der(q, r);
|
||||
|
@ -327,9 +326,8 @@ void der::create_substitution(unsigned sz) {
|
|||
}
|
||||
}
|
||||
|
||||
void der::apply_substitution(quantifier * q, expr_ref & r) {
|
||||
expr * e = q->get_expr();
|
||||
unsigned num_args=to_app(e)->get_num_args();
|
||||
void der::apply_substitution(quantifier * q, expr_ref_vector& ors, expr_ref & r) {
|
||||
unsigned num_args = ors.size();
|
||||
|
||||
// get a new expression
|
||||
m_new_args.reset();
|
||||
|
@ -338,13 +336,11 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
|
|||
if (x != -1 && m_map.get(x) != nullptr)
|
||||
continue; // this is a disequality with definition (vanishes)
|
||||
|
||||
m_new_args.push_back(to_app(e)->get_arg(i));
|
||||
m_new_args.push_back(ors.get(i));
|
||||
}
|
||||
|
||||
unsigned sz = m_new_args.size();
|
||||
expr_ref t(m);
|
||||
t = (sz == 1) ? m_new_args[0] : m.mk_or(sz, m_new_args.data());
|
||||
expr_ref new_e = m_subst(t, m_subst_map.size(), m_subst_map.data());
|
||||
expr_ref t(mk_or(m, m_new_args.size(), m_new_args.data()), m);
|
||||
expr_ref new_e = m_subst(t, m_subst_map);
|
||||
|
||||
// don't forget to update the quantifier patterns
|
||||
expr_ref_buffer new_patterns(m);
|
||||
|
|
|
@ -147,7 +147,7 @@ class der {
|
|||
|
||||
void get_elimination_order();
|
||||
void create_substitution(unsigned sz);
|
||||
void apply_substitution(quantifier * q, expr_ref & r);
|
||||
void apply_substitution(quantifier * q, expr_ref_vector& ors, expr_ref & r);
|
||||
|
||||
void reduce1(quantifier * q, expr_ref & r, proof_ref & pr);
|
||||
|
||||
|
|
|
@ -52,21 +52,21 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
arith_util m_a_util;
|
||||
bv_util m_bv_util;
|
||||
expr_safe_replace m_rep;
|
||||
bool m_new_subst { false };
|
||||
expr_ref_vector m_pinned;
|
||||
unsigned long long m_max_memory; // in bytes
|
||||
unsigned m_max_steps;
|
||||
bool m_pull_cheap_ite;
|
||||
bool m_flat;
|
||||
bool m_cache_all;
|
||||
bool m_push_ite_arith;
|
||||
bool m_push_ite_bv;
|
||||
bool m_ignore_patterns_on_ground_qbody;
|
||||
bool m_rewrite_patterns;
|
||||
|
||||
// substitution support
|
||||
// substitution support
|
||||
expr_dependency_ref m_used_dependencies; // set of dependencies of used substitutions
|
||||
expr_substitution * m_subst;
|
||||
expr_substitution * m_subst = nullptr;
|
||||
unsigned long long m_max_memory; // in bytes
|
||||
bool m_new_subst = false;
|
||||
unsigned m_max_steps = UINT_MAX;
|
||||
bool m_pull_cheap_ite = true;
|
||||
bool m_flat = true;
|
||||
bool m_cache_all = false;
|
||||
bool m_push_ite_arith = true;
|
||||
bool m_push_ite_bv = true;
|
||||
bool m_ignore_patterns_on_ground_qbody = true;
|
||||
bool m_rewrite_patterns = true;
|
||||
|
||||
|
||||
ast_manager & m() const { return m_b_rw.m(); }
|
||||
|
||||
|
@ -805,8 +805,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
m_bv_util(m),
|
||||
m_rep(m),
|
||||
m_pinned(m),
|
||||
m_used_dependencies(m),
|
||||
m_subst(nullptr) {
|
||||
m_used_dependencies(m) {
|
||||
updt_local_params(p);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue