3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-28 05:58:55 +00:00

Merge branch 'Z3Prover:master' into parallel-solving

This commit is contained in:
Ilana Shapiro 2025-07-28 16:45:45 -07:00 committed by GitHub
commit f607a704ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 396 additions and 218 deletions

View file

@ -225,13 +225,15 @@ extern "C" {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_fresh_func_decl(c, prefix, domain_size, domain, range); LOG_Z3_mk_fresh_func_decl(c, prefix, domain_size, domain, range);
RESET_ERROR_CODE(); RESET_ERROR_CODE();
CHECK_IS_SORT(range, nullptr);
CHECK_SORTS(domain_size, domain, nullptr);
if (prefix == nullptr) { if (prefix == nullptr) {
prefix = ""; prefix = "";
} }
func_decl* d = mk_c(c)->m().mk_fresh_func_decl(prefix, func_decl* d = mk_c(c)->m().mk_fresh_func_decl(prefix,
domain_size, domain_size,
reinterpret_cast<sort*const*>(domain), to_sorts(domain),
to_sort(range), false); to_sort(range), false);
mk_c(c)->save_ast_trail(d); mk_c(c)->save_ast_trail(d);
@ -243,9 +245,11 @@ extern "C" {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_fresh_const(c, prefix, ty); LOG_Z3_mk_fresh_const(c, prefix, ty);
RESET_ERROR_CODE(); RESET_ERROR_CODE();
CHECK_IS_SORT(ty, nullptr);
if (prefix == nullptr) { if (prefix == nullptr) {
prefix = ""; prefix = "";
} }
app* a = mk_c(c)->m().mk_fresh_const(prefix, to_sort(ty), false); app* a = mk_c(c)->m().mk_fresh_const(prefix, to_sort(ty), false);
mk_c(c)->save_ast_trail(a); mk_c(c)->save_ast_trail(a);
RETURN_Z3(of_ast(a)); RETURN_Z3(of_ast(a));
@ -654,6 +658,7 @@ extern "C" {
Z3_TRY; Z3_TRY;
LOG_Z3_get_sort_name(c, t); LOG_Z3_get_sort_name(c, t);
RESET_ERROR_CODE(); RESET_ERROR_CODE();
CHECK_IS_SORT(t, of_symbol(symbol::null));
CHECK_VALID_AST(t, of_symbol(symbol::null)); CHECK_VALID_AST(t, of_symbol(symbol::null));
return of_symbol(to_sort(t)->get_name()); return of_symbol(to_sort(t)->get_name());
Z3_CATCH_RETURN(of_symbol(symbol::null)); Z3_CATCH_RETURN(of_symbol(symbol::null));

View file

@ -286,10 +286,13 @@ namespace api {
inline api::context * mk_c(Z3_context c) { return reinterpret_cast<api::context*>(c); } inline api::context * mk_c(Z3_context c) { return reinterpret_cast<api::context*>(c); }
#define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); } #define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); }
#define SET_ERROR_CODE(ERR, MSG) { mk_c(c)->set_error_code(ERR, MSG); } #define SET_ERROR_CODE(ERR, MSG) { mk_c(c)->set_error_code(ERR, MSG); }
#define CHECK_NON_NULL(_p_,_ret_) { if (_p_ == 0) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is null"); return _ret_; } } #define CHECK_NON_NULL(_p_,_ret_) { if (_p_ == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is null"); return _ret_; } }
#define CHECK_VALID_AST(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "not a valid ast"); return _ret_; } } #define CHECK_VALID_AST(_a_, _ret_) { if (_a_ == nullptr || !CHECK_REF_COUNT(_a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "not a valid ast"); return _ret_; } }
inline bool is_expr(Z3_ast a) { return is_expr(to_ast(a)); } inline bool is_expr(Z3_ast a) { return is_expr(to_ast(a)); }
#define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == 0 || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is not an expression"); return _ret_; } } #define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == nullptr || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is not an expression"); return _ret_; } }
#define CHECK_IS_SORT(_p_, _ret_) { if (_p_ == nullptr || !is_sort(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is not a sort"); return _ret_; } }
#define CHECK_SORTS(_n_, _ps_, _ret_) { for (unsigned i = 0; i < _n_; ++i) if (!is_sort(_ps_[i])) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is not a sort"); return _ret_; } }
inline bool is_bool_expr(Z3_context c, Z3_ast a) { return is_expr(a) && mk_c(c)->m().is_bool(to_expr(a)); } inline bool is_bool_expr(Z3_context c, Z3_ast a) { return is_expr(a) && mk_c(c)->m().is_bool(to_expr(a)); }
#define CHECK_FORMULA(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return _ret_; } } #define CHECK_FORMULA(_a_, _ret_) { if (_a_ == nullptr || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return _ret_; } }
inline void check_sorts(Z3_context c, ast * n) { mk_c(c)->check_sorts(n); } inline void check_sorts(Z3_context c, ast * n) { mk_c(c)->check_sorts(n); }

View file

@ -67,6 +67,7 @@ inline ast * const * to_asts(Z3_ast const* a) { return reinterpret_cast<ast* con
inline sort * to_sort(Z3_sort a) { return reinterpret_cast<sort*>(a); } inline sort * to_sort(Z3_sort a) { return reinterpret_cast<sort*>(a); }
inline Z3_sort of_sort(sort* s) { return reinterpret_cast<Z3_sort>(s); } inline Z3_sort of_sort(sort* s) { return reinterpret_cast<Z3_sort>(s); }
inline bool is_sort(Z3_sort a) { return is_sort(to_sort(a)); }
inline sort * const * to_sorts(Z3_sort const* a) { return reinterpret_cast<sort* const*>(a); } inline sort * const * to_sorts(Z3_sort const* a) { return reinterpret_cast<sort* const*>(a); }
inline Z3_sort const * of_sorts(sort* const* s) { return reinterpret_cast<Z3_sort const*>(s); } inline Z3_sort const * of_sorts(sort* const* s) { return reinterpret_cast<Z3_sort const*>(s); }

View file

@ -1506,6 +1506,8 @@ def Consts(names, sort):
def FreshConst(sort, prefix="c"): def FreshConst(sort, prefix="c"):
"""Create a fresh constant of a specified sort""" """Create a fresh constant of a specified sort"""
if z3_debug():
_z3_assert(is_sort(sort), f"Z3 sort expected, got {type(sort)}")
ctx = _get_ctx(sort.ctx) ctx = _get_ctx(sort.ctx)
return _to_expr_ref(Z3_mk_fresh_const(ctx.ref(), prefix, sort.ast), ctx) return _to_expr_ref(Z3_mk_fresh_const(ctx.ref(), prefix, sort.ast), ctx)

View file

@ -136,15 +136,13 @@ namespace euf {
// unit -> {} // unit -> {}
void ac_plugin::add_unit(enode* u) { void ac_plugin::add_unit(enode* u) {
m_units.push_back(u); push_equation(u, nullptr);
mk_node(u);
auto m_id = to_monomial(u, {});
init_equation(eq(to_monomial(u), m_id, justification::axiom(get_id())));
} }
// zero x -> zero // zero x -> zero
void ac_plugin::add_zero(enode* z) { void ac_plugin::add_zero(enode* z) {
mk_node(z)->is_zero = true; mk_node(z)->is_zero = true;
// zeros persist
} }
void ac_plugin::register_shared(enode* n) { void ac_plugin::register_shared(enode* n) {
@ -165,12 +163,16 @@ namespace euf {
push_undo(is_register_shared); push_undo(is_register_shared);
} }
void ac_plugin::push_scope_eh() {
push_undo(is_push_scope);
}
void ac_plugin::undo() { void ac_plugin::undo() {
auto k = m_undo.back(); auto k = m_undo.back();
m_undo.pop_back(); m_undo.pop_back();
switch (k) { switch (k) {
case is_add_eq: { case is_queue_eq: {
m_active.pop_back(); m_queued.pop_back();
break; break;
} }
case is_add_node: { case is_add_node: {
@ -180,14 +182,15 @@ namespace euf {
n->~node(); n->~node();
break; break;
} }
case is_add_monomial: { case is_push_scope: {
m_monomials.pop_back(); m_active.reset();
m_passive.reset();
m_units.reset();
m_queue_head = 0;
break; break;
} }
case is_update_eq: { case is_add_monomial: {
auto const& [idx, eq] = m_update_eq_trail.back(); m_monomials.pop_back();
m_active[idx] = eq;
m_update_eq_trail.pop_back();
break; break;
} }
case is_add_shared_index: { case is_add_shared_index: {
@ -316,14 +319,24 @@ namespace euf {
} }
void ac_plugin::merge_eh(enode* l, enode* r) { void ac_plugin::merge_eh(enode* l, enode* r) {
if (l == r) push_equation(l, r);
return; }
void ac_plugin::pop_equation(enode* l, enode* r) {
m_fuel += m_fuel_inc; m_fuel += m_fuel_inc;
if (!r) {
m_units.push_back(l);
mk_node(l);
auto m_id = to_monomial(l, {});
init_equation(eq(to_monomial(l), m_id, justification::axiom(get_id())), true);
}
else {
auto j = justification::equality(l, r); auto j = justification::equality(l, r);
auto m1 = to_monomial(l); auto m1 = to_monomial(l);
auto m2 = to_monomial(r); auto m2 = to_monomial(r);
TRACE(plugin, tout << "merge: " << m_name << " " << g.bpp(l) << " == " << g.bpp(r) << " " << m_pp_ll(*this, monomial(m1)) << " == " << m_pp_ll(*this, monomial(m2)) << "\n"); TRACE(plugin, tout << "merge: " << m_name << " " << g.bpp(l) << " == " << g.bpp(r) << " " << m_pp_ll(*this, monomial(m1)) << " == " << m_pp_ll(*this, monomial(m2)) << "\n");
init_equation(eq(m1, m2, j)); init_equation(eq(m1, m2, j), true);
}
} }
void ac_plugin::diseq_eh(enode* eq) { void ac_plugin::diseq_eh(enode* eq) {
@ -336,12 +349,32 @@ namespace euf {
register_shared(b); register_shared(b);
} }
bool ac_plugin::init_equation(eq const& e) { void ac_plugin::push_equation(enode* l, enode* r) {
m_active.push_back(e); if (l == r)
auto& eq = m_active.back(); return;
deduplicate(monomial(eq.l).m_nodes, monomial(eq.r).m_nodes); m_queued.push_back({ l, r });
push_undo(is_queue_eq);
}
if (orient_equation(eq)) { bool ac_plugin::init_equation(eq eq, bool is_active) {
deduplicate(monomial(eq.l), monomial(eq.r));
if (!orient_equation(eq))
return false;
#if 1
if (is_reducing(eq))
is_active = true;
#else
is_active = true; // set to active by default
#endif
if (!is_active) {
m_passive.push_back(eq);
return true;
}
m_active.push_back(eq);
auto& ml = monomial(eq.l); auto& ml = monomial(eq.l);
auto& mr = monomial(eq.r); auto& mr = monomial(eq.r);
@ -388,11 +421,7 @@ namespace euf {
return true; return true;
} }
else {
m_active.pop_back();
return false;
}
}
bool ac_plugin::orient_equation(eq& e) { bool ac_plugin::orient_equation(eq& e) {
auto& ml = monomial(e.l); auto& ml = monomial(e.l);
@ -455,8 +484,11 @@ namespace euf {
uint64_t ac_plugin::filter(monomial_t& m) { uint64_t ac_plugin::filter(monomial_t& m) {
auto& bloom = m.m_bloom; auto& bloom = m.m_bloom;
if (bloom.m_tick == m_tick)
if (bloom.m_tick == m_tick) {
SASSERT(bloom_filter_is_correct(m.m_nodes, m.m_bloom));
return bloom.m_filter; return bloom.m_filter;
}
bloom.m_filter = 0; bloom.m_filter = 0;
for (auto n : m) for (auto n : m)
bloom.m_filter |= (1ull << (n->id() % 64ull)); bloom.m_filter |= (1ull << (n->id() % 64ull));
@ -466,6 +498,13 @@ namespace euf {
return bloom.m_filter; return bloom.m_filter;
} }
bool ac_plugin::bloom_filter_is_correct(ptr_vector<node> const& m, bloom const& b) const {
uint64_t f = 0;
for (auto n : m)
f |= (1ull << (n->id() % 64ull));
return b.m_filter == f;
}
bool ac_plugin::can_be_subset(monomial_t& subset, monomial_t& superset) { bool ac_plugin::can_be_subset(monomial_t& subset, monomial_t& superset) {
if (subset.size() > superset.size()) if (subset.size() > superset.size())
return false; return false;
@ -477,6 +516,7 @@ namespace euf {
bool ac_plugin::can_be_subset(monomial_t& subset, ptr_vector<node> const& m, bloom& bloom) { bool ac_plugin::can_be_subset(monomial_t& subset, ptr_vector<node> const& m, bloom& bloom) {
if (subset.size() > m.size()) if (subset.size() > m.size())
return false; return false;
SASSERT(bloom.m_tick != m_tick || bloom_filter_is_correct(m, bloom));
if (bloom.m_tick != m_tick) { if (bloom.m_tick != m_tick) {
bloom.m_filter = 0; bloom.m_filter = 0;
for (auto n : m) for (auto n : m)
@ -562,6 +602,10 @@ namespace euf {
} }
void ac_plugin::propagate() { void ac_plugin::propagate() {
while (m_queue_head < m_queued.size()) {
auto [l, r] = m_queued[m_queue_head++];
pop_equation(l, r);
}
while (true) { while (true) {
loop_start: loop_start:
if (m_fuel == 0) if (m_fuel == 0)
@ -583,7 +627,7 @@ namespace euf {
goto loop_start; goto loop_start;
auto& eq = m_active[eq_id]; auto& eq = m_active[eq_id];
deduplicate(monomial(eq.l).m_nodes, monomial(eq.r).m_nodes); deduplicate(monomial(eq.l), monomial(eq.r));
if (monomial(eq.l).size() == 0) { if (monomial(eq.l).size() == 0) {
set_status(eq_id, eq_status::is_dead_eq); set_status(eq_id, eq_status::is_dead_eq);
continue; continue;
@ -623,12 +667,20 @@ namespace euf {
} }
unsigned ac_plugin::pick_next_eq() { unsigned ac_plugin::pick_next_eq() {
init_pick:
while (!m_to_simplify_todo.empty()) { while (!m_to_simplify_todo.empty()) {
unsigned id = *m_to_simplify_todo.begin(); unsigned id = *m_to_simplify_todo.begin();
if (id < m_active.size() && is_to_simplify(id)) if (id < m_active.size() && is_to_simplify(id))
return id; return id;
m_to_simplify_todo.remove(id); m_to_simplify_todo.remove(id);
} }
if (!m_passive.empty()) {
auto eq = m_passive.back();
// verbose_stream() << "pick passive " << eq_pp_ll(*this, eq) << "\n";
m_passive.pop_back();
init_equation(eq, true);
goto init_pick;
}
return UINT_MAX; return UINT_MAX;
} }
@ -640,11 +692,7 @@ namespace euf {
if (are_equal(monomial(eq.l), monomial(eq.r))) if (are_equal(monomial(eq.l), monomial(eq.r)))
s = eq_status::is_dead_eq; s = eq_status::is_dead_eq;
if (eq.status != s) {
m_update_eq_trail.push_back({ id, eq });
eq.status = s; eq.status = s;
push_undo(is_update_eq);
}
switch (s) { switch (s) {
case eq_status::is_processed_eq: case eq_status::is_processed_eq:
case eq_status::is_reducing_eq: case eq_status::is_reducing_eq:
@ -673,7 +721,7 @@ namespace euf {
} }
// //
// backward iterator allows simplification of eq // forward iterator allows simplification of eq
// The rhs of eq is a super-set of lhs of other eq. // The rhs of eq is a super-set of lhs of other eq.
// //
unsigned_vector const& ac_plugin::forward_iterator(unsigned eq_id) { unsigned_vector const& ac_plugin::forward_iterator(unsigned eq_id) {
@ -749,7 +797,7 @@ namespace euf {
} }
// //
// forward iterator simplifies other eqs where their rhs is a superset of lhs of eq // backward iterator simplifies other eqs where their rhs is a superset of lhs of eq
// //
unsigned_vector const& ac_plugin::backward_iterator(unsigned eq_id) { unsigned_vector const& ac_plugin::backward_iterator(unsigned eq_id) {
auto& eq = m_active[eq_id]; auto& eq = m_active[eq_id];
@ -843,10 +891,8 @@ namespace euf {
reduce(m_src_r, j); reduce(m_src_r, j);
auto new_r = to_monomial(m_src_r); auto new_r = to_monomial(m_src_r);
index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r)); index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r));
m_update_eq_trail.push_back({ dst_eq, m_active[dst_eq] });
m_active[dst_eq].r = new_r; m_active[dst_eq].r = new_r;
m_active[dst_eq].j = j; m_active[dst_eq].j = j;
push_undo(is_update_eq);
m_src_r.reset(); m_src_r.reset();
m_src_r.append(monomial(src.r).m_nodes); m_src_r.append(monomial(src.r).m_nodes);
TRACE(plugin_verbose, tout << "rewritten to " << m_pp_ll(*this, monomial(new_r)) << "\n"); TRACE(plugin_verbose, tout << "rewritten to " << m_pp_ll(*this, monomial(new_r)) << "\n");
@ -862,7 +908,7 @@ namespace euf {
// //
// dst_ids, dst_count contain rhs of dst_eq // dst_ids, dst_count contain rhs of dst_eq
// //
TRACE(plugin, tout << "backward simplify " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " can-be-subset: " << can_be_subset(monomial(src.l), monomial(dst.r)) << "\n"); TRACE(plugin, tout << "forward simplify " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " can-be-subset: " << can_be_subset(monomial(src.l), monomial(dst.r)) << "\n");
if (forward_subsumes(src_eq, dst_eq)) { if (forward_subsumes(src_eq, dst_eq)) {
set_status(dst_eq, eq_status::is_dead_eq); set_status(dst_eq, eq_status::is_dead_eq);
@ -891,11 +937,9 @@ namespace euf {
reduce(m, j); reduce(m, j);
auto new_r = to_monomial(m); auto new_r = to_monomial(m);
index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r)); index_new_r(dst_eq, monomial(m_active[dst_eq].r), monomial(new_r));
m_update_eq_trail.push_back({ dst_eq, m_active[dst_eq] });
m_active[dst_eq].r = new_r; m_active[dst_eq].r = new_r;
m_active[dst_eq].j = j; m_active[dst_eq].j = j;
TRACE(plugin, tout << "rewritten to " << m_pp(*this, monomial(new_r)) << "\n"); TRACE(plugin, tout << "rewritten to " << m_pp(*this, monomial(new_r)) << "\n");
push_undo(is_update_eq);
return true; return true;
} }
@ -975,7 +1019,9 @@ namespace euf {
SASSERT(!are_equal(m_active[src_eq], m_active[dst_eq])); SASSERT(!are_equal(m_active[src_eq], m_active[dst_eq]));
return false; return false;
} }
return all_of(monomial(dst.r), [&](node* n) { unsigned id = n->id(); return m_src_r_counts[id] == m_dst_r_counts[id]; }); bool r = all_of(monomial(dst.r), [&](node* n) { unsigned id = n->id(); return m_src_r_counts[id] == m_dst_r_counts[id]; });
SASSERT(r || !are_equal(m_active[src_eq], m_active[dst_eq]));
return r;
} }
// src_l_counts, src_r_counts are initialized for src.l, src.r // src_l_counts, src_r_counts are initialized for src.l, src.r
@ -1079,8 +1125,7 @@ namespace euf {
goto init_loop; goto init_loop;
} }
} }
} } while (false);
while (false);
VERIFY(sz >= m.size()); VERIFY(sz >= m.size());
return change; return change;
} }
@ -1177,7 +1222,7 @@ namespace euf {
unsigned max_left_new = std::max(m_src_r.size(), m_dst_r.size()); unsigned max_left_new = std::max(m_src_r.size(), m_dst_r.size());
unsigned min_right_new = std::min(m_src_r.size(), m_dst_r.size()); unsigned min_right_new = std::min(m_src_r.size(), m_dst_r.size());
if (max_left_new <= max_left && min_right_new <= min_right) if (max_left_new <= max_left && min_right_new <= min_right)
added_eq = init_equation(eq(to_monomial(m_src_r), to_monomial(m_dst_r), j)); added_eq = init_equation(eq(to_monomial(m_src_r), to_monomial(m_dst_r), j), false);
CTRACE(plugin, added_eq, CTRACE(plugin, added_eq,
tout << "superpose: " << m_name << " " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " --> "; tout << "superpose: " << m_name << " " << eq_pp_ll(*this, src) << " " << eq_pp_ll(*this, dst) << " --> ";
@ -1202,23 +1247,36 @@ namespace euf {
SASSERT(is_active(other_eq)); SASSERT(is_active(other_eq));
backward_reduce(eq, other_eq); backward_reduce(eq, other_eq);
} }
for (auto p : m_passive) {
bool change = false;
if (backward_reduce_monomial(eq, p, monomial(p.l)))
change = true;
if (backward_reduce_monomial(eq, p, monomial(p.r)))
change = true;
(void)change;
CTRACE(plugin, change,
verbose_stream() << "backward reduce " << eq_pp_ll(*this, eq) << " " << eq_pp_ll(*this, p) << "\n");
}
} }
// TODO: this is destructive. It breaks reversibility.
// TODO: also need justifications from eq if there is a change.
void ac_plugin::backward_reduce(eq const& eq, unsigned other_eq_id) { void ac_plugin::backward_reduce(eq const& eq, unsigned other_eq_id) {
auto& other_eq = m_active[other_eq_id]; auto& other_eq = m_active[other_eq_id];
TRACE(plugin_verbose,
tout << "backward reduce " << eq_pp_ll(*this, eq) << " " << eq_pp_ll(*this, other_eq) << "\n");
bool change = false; bool change = false;
if (backward_reduce_monomial(eq, monomial(other_eq.l))) if (backward_reduce_monomial(eq, other_eq, monomial(other_eq.l)))
change = true; change = true;
if (backward_reduce_monomial(eq, monomial(other_eq.r))) if (backward_reduce_monomial(eq, other_eq, monomial(other_eq.r)))
change = true; change = true;
if (change) CTRACE(plugin, change,
tout << "backward reduce " << eq_pp_ll(*this, eq) << " " << eq_pp_ll(*this, other_eq) << "\n");
if (change) {
set_status(other_eq_id, eq_status::is_to_simplify_eq); set_status(other_eq_id, eq_status::is_to_simplify_eq);
} }
}
bool ac_plugin::backward_reduce_monomial(eq const& eq, monomial_t& m) { bool ac_plugin::backward_reduce_monomial(eq const& src, eq& dst, monomial_t& m) {
auto const& r = monomial(eq.r); auto const& r = monomial(src.r);
unsigned j = 0; unsigned j = 0;
bool change = false; bool change = false;
for (auto n : m) { for (auto n : m) {
@ -1241,6 +1299,10 @@ namespace euf {
m.m_nodes[j++] = r[0]; m.m_nodes[j++] = r[0];
} }
m.m_nodes.shrink(j); m.m_nodes.shrink(j);
if (change) {
m.m_bloom.m_tick = 0;
dst.j = join(dst.j, src);
}
return change; return change;
} }
@ -1277,8 +1339,17 @@ namespace euf {
return true; return true;
} }
void ac_plugin::deduplicate(monomial_t& a, monomial_t& b) {
unsigned sza = a.size(), szb = b.size();
deduplicate(a.m_nodes, b.m_nodes);
if (sza != a.size())
a.m_bloom.m_tick = 0;
if (szb != b.size())
b.m_bloom.m_tick = 0;
}
void ac_plugin::deduplicate(ptr_vector<node>& a, ptr_vector<node>& b) { void ac_plugin::deduplicate(ptr_vector<node>& a, ptr_vector<node>& b) {
{
for (auto n : a) { for (auto n : a) {
if (n->is_zero) { if (n->is_zero) {
a[0] = n; a[0] = n;
@ -1293,7 +1364,6 @@ namespace euf {
break; break;
} }
} }
}
if (!m_is_injective) if (!m_is_injective)
return; return;
@ -1385,9 +1455,7 @@ namespace euf {
push_undo(is_update_shared); push_undo(is_update_shared);
m_shared[idx].m = new_m; m_shared[idx].m = new_m;
m_shared[idx].j = j; m_shared[idx].j = j;
TRACE(plugin_verbose, tout << "shared simplified to " << m_pp_ll(*this, monomial(new_m)) << "\n"); TRACE(plugin_verbose, tout << "shared simplified to " << m_pp_ll(*this, monomial(new_m)) << "\n");
push_merge(old_n, new_n, j); push_merge(old_n, new_n, j);
} }
@ -1397,19 +1465,15 @@ namespace euf {
} }
justification::dependency* ac_plugin::justify_equation(unsigned eq) { justification::dependency* ac_plugin::justify_equation(unsigned eq) {
auto const& e = m_active[eq]; return m_dep_manager.mk_leaf(m_active[eq].j);
auto* j = m_dep_manager.mk_leaf(e.j);
j = justify_monomial(j, monomial(e.l));
j = justify_monomial(j, monomial(e.r));
return j;
}
justification::dependency* ac_plugin::justify_monomial(justification::dependency* j, monomial_t const& m) {
return j;
} }
justification ac_plugin::join(justification j, unsigned eq) { justification ac_plugin::join(justification j, unsigned eq) {
return justification::dependent(m_dep_manager.mk_join(m_dep_manager.mk_leaf(j), justify_equation(eq))); return justification::dependent(m_dep_manager.mk_join(m_dep_manager.mk_leaf(j), justify_equation(eq)));
} }
justification ac_plugin::join(justification j, eq const& eq) {
return justification::dependent(m_dep_manager.mk_join(m_dep_manager.mk_leaf(j), m_dep_manager.mk_leaf(eq.j)));
}
} }

View file

@ -123,6 +123,7 @@ namespace euf {
func_decl* m_decl = nullptr; func_decl* m_decl = nullptr;
bool m_is_injective = false; bool m_is_injective = false;
vector<eq> m_active, m_passive; vector<eq> m_active, m_passive;
enode_pair_vector m_queued;
ptr_vector<node> m_nodes; ptr_vector<node> m_nodes;
bool_vector m_shared_nodes; bool_vector m_shared_nodes;
vector<monomial_t> m_monomials; vector<monomial_t> m_monomials;
@ -146,21 +147,21 @@ namespace euf {
// backtrackable state // backtrackable state
enum undo_kind { enum undo_kind {
is_add_eq, is_queue_eq,
is_add_monomial, is_add_monomial,
is_add_node, is_add_node,
is_update_eq,
is_add_shared_index, is_add_shared_index,
is_add_eq_index, is_add_eq_index,
is_register_shared, is_register_shared,
is_update_shared is_update_shared,
is_push_scope
}; };
svector<undo_kind> m_undo; svector<undo_kind> m_undo;
ptr_vector<node> m_node_trail; ptr_vector<node> m_node_trail;
unsigned m_queue_head = 0;
svector<std::pair<unsigned, shared>> m_update_shared_trail; svector<std::pair<unsigned, shared>> m_update_shared_trail;
svector<std::tuple<node*, unsigned, unsigned>> m_merge_trail; svector<std::tuple<node*, unsigned, unsigned>> m_merge_trail;
svector<std::pair<unsigned, eq>> m_update_eq_trail;
@ -178,6 +179,7 @@ namespace euf {
enode* from_monomial(ptr_vector<node> const& m); enode* from_monomial(ptr_vector<node> const& m);
monomial_t const& monomial(unsigned i) const { return m_monomials[i]; } monomial_t const& monomial(unsigned i) const { return m_monomials[i]; }
monomial_t& monomial(unsigned i) { return m_monomials[i]; } monomial_t& monomial(unsigned i) { return m_monomials[i]; }
void sort(monomial_t& monomial); void sort(monomial_t& monomial);
bool is_sorted(monomial_t const& monomial) const; bool is_sorted(monomial_t const& monomial) const;
uint64_t filter(monomial_t& m); uint64_t filter(monomial_t& m);
@ -188,11 +190,12 @@ namespace euf {
bool are_equal(eq const& a, eq const& b) { bool are_equal(eq const& a, eq const& b) {
return are_equal(monomial(a.l), monomial(b.l)) && are_equal(monomial(a.r), monomial(b.r)); return are_equal(monomial(a.l), monomial(b.l)) && are_equal(monomial(a.r), monomial(b.r));
} }
bool bloom_filter_is_correct(ptr_vector<node> const& m, bloom const& b) const;
bool well_formed(eq const& e) const; bool well_formed(eq const& e) const;
bool is_reducing(eq const& e) const; bool is_reducing(eq const& e) const;
void backward_reduce(unsigned eq_id); void backward_reduce(unsigned eq_id);
void backward_reduce(eq const& src, unsigned dst); void backward_reduce(eq const& eq, unsigned dst);
bool backward_reduce_monomial(eq const& eq, monomial_t& m); bool backward_reduce_monomial(eq const& src, eq & dst, monomial_t& m);
void forward_subsume_new_eqs(); void forward_subsume_new_eqs();
bool is_forward_subsumed(unsigned dst_eq); bool is_forward_subsumed(unsigned dst_eq);
bool forward_subsumes(unsigned src_eq, unsigned dst_eq); bool forward_subsumes(unsigned src_eq, unsigned dst_eq);
@ -208,7 +211,9 @@ namespace euf {
return nullptr; return nullptr;
} }
bool init_equation(eq const& e); bool init_equation(eq e, bool is_active);
void push_equation(enode* l, enode* r);
void pop_equation(enode* l, enode* r);
bool orient_equation(eq& e); bool orient_equation(eq& e);
void set_status(unsigned eq_id, eq_status s); void set_status(unsigned eq_id, eq_status s);
unsigned pick_next_eq(); unsigned pick_next_eq();
@ -217,6 +222,7 @@ namespace euf {
void backward_simplify(unsigned eq_id, unsigned using_eq); void backward_simplify(unsigned eq_id, unsigned using_eq);
bool forward_simplify(unsigned eq_id, unsigned using_eq); bool forward_simplify(unsigned eq_id, unsigned using_eq);
bool superpose(unsigned src_eq, unsigned dst_eq); bool superpose(unsigned src_eq, unsigned dst_eq);
void deduplicate(monomial_t& a, monomial_t& b);
void deduplicate(ptr_vector<node>& a, ptr_vector<node>& b); void deduplicate(ptr_vector<node>& a, ptr_vector<node>& b);
ptr_vector<node> m_src_r, m_src_l, m_dst_r, m_dst_l; ptr_vector<node> m_src_r, m_src_l, m_dst_r, m_dst_l;
@ -260,8 +266,8 @@ namespace euf {
justification justify_rewrite(unsigned eq1, unsigned eq2); justification justify_rewrite(unsigned eq1, unsigned eq2);
justification::dependency* justify_equation(unsigned eq); justification::dependency* justify_equation(unsigned eq);
justification::dependency* justify_monomial(justification::dependency* d, monomial_t const& m);
justification join(justification j1, unsigned eq); justification join(justification j1, unsigned eq);
justification join(justification j1, eq const& eq);
bool is_correct_ref_count(monomial_t const& m, ref_counts const& counts) const; bool is_correct_ref_count(monomial_t const& m, ref_counts const& counts) const;
bool is_correct_ref_count(ptr_vector<node> const& m, ref_counts const& counts) const; bool is_correct_ref_count(ptr_vector<node> const& m, ref_counts const& counts) const;
@ -301,6 +307,8 @@ namespace euf {
void undo() override; void undo() override;
void push_scope_eh() override;
void propagate() override; void propagate() override;
std::ostream& display(std::ostream& out) const override; std::ostream& display(std::ostream& out) const override;

View file

@ -43,6 +43,11 @@ namespace euf {
void undo() override; void undo() override;
void push_scope_eh() override {
m_add.push_scope_eh();
m_mul.push_scope_eh();
}
void propagate() override; void propagate() override;
std::ostream& display(std::ostream& out) const override; std::ostream& display(std::ostream& out) const override;

View file

@ -103,6 +103,9 @@ namespace euf {
m_scopes.push_back(m_updates.size()); m_scopes.push_back(m_updates.size());
m_region.push_scope(); m_region.push_scope();
m_updates.push_back(update_record(m_new_th_eqs_qhead, update_record::new_th_eq_qhead())); m_updates.push_back(update_record(m_new_th_eqs_qhead, update_record::new_th_eq_qhead()));
for (auto p : m_plugins)
if (p)
p->push_scope_eh();
} }
SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size()); SASSERT(m_new_th_eqs_qhead <= m_new_th_eqs.size());
} }

View file

@ -53,6 +53,8 @@ namespace euf {
virtual void undo() = 0; virtual void undo() = 0;
virtual void push_scope_eh() {}
virtual std::ostream& display(std::ostream& out) const = 0; virtual std::ostream& display(std::ostream& out) const = 0;
virtual void collect_statistics(statistics& st) const {} virtual void collect_statistics(statistics& st) const {}

View file

@ -2265,6 +2265,20 @@ br_status bv_rewriter::mk_bv_ext_rotate_left(expr * arg1, expr * arg2, expr_ref
unsigned shift = static_cast<unsigned>((r2 % numeral(bv_size)).get_uint64() % static_cast<uint64_t>(bv_size)); unsigned shift = static_cast<unsigned>((r2 % numeral(bv_size)).get_uint64() % static_cast<uint64_t>(bv_size));
return mk_bv_rotate_left(shift, arg1, result); return mk_bv_rotate_left(shift, arg1, result);
} }
expr* x = nullptr, * y = nullptr;
if (m_util.is_ext_rotate_right(arg1, x, y) && arg2 == y) {
// bv_ext_rotate_left(bv_ext_rotate_right(x, y), y) --> x
result = x;
return BR_DONE;
}
if (m_util.is_ext_rotate_left(arg1, x, y)) {
result = m_util.mk_bv_rotate_left(x, m_util.mk_bv_add(y, arg2));
return BR_REWRITE2;
}
if (m_util.is_ext_rotate_right(arg1, x, y)) {
result = m_util.mk_bv_rotate_left(x, m_util.mk_bv_sub(arg2, y));
return BR_REWRITE2;
}
return BR_FAILED; return BR_FAILED;
} }
@ -2275,6 +2289,20 @@ br_status bv_rewriter::mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref
unsigned shift = static_cast<unsigned>((r2 % numeral(bv_size)).get_uint64() % static_cast<uint64_t>(bv_size)); unsigned shift = static_cast<unsigned>((r2 % numeral(bv_size)).get_uint64() % static_cast<uint64_t>(bv_size));
return mk_bv_rotate_right(shift, arg1, result); return mk_bv_rotate_right(shift, arg1, result);
} }
expr* x = nullptr, * y = nullptr;
if (m_util.is_ext_rotate_left(arg1, x, y) && arg2 == y) {
// bv_ext_rotate_right(bv_ext_rotate_left(x, y), y) --> x
result = x;
return BR_DONE;
}
if (m_util.is_ext_rotate_right(arg1, x, y)) {
result = m_util.mk_bv_rotate_right(x, m_util.mk_bv_add(y, arg2));
return BR_REWRITE2;
}
if (m_util.is_ext_rotate_left(arg1, x, y)) {
result = m_util.mk_bv_rotate_right(x, m_util.mk_bv_sub(arg2, y));
return BR_REWRITE2;
}
return BR_FAILED; return BR_FAILED;
} }

View file

@ -1224,16 +1224,40 @@ namespace seq {
let n = len(x) let n = len(x)
- len(a ++ b) = len(a) + len(b) if x = a ++ b - len(a ++ b) = len(a) + len(b) if x = a ++ b
- len(unit(u)) = 1 if x = unit(u) - len(unit(u)) = 1 if x = unit(u)
- len(extract(x, o, l)) = l if len(x) >= o + l etc
- len(str) = str.length() if x = str - len(str) = str.length() if x = str
- len(empty) = 0 if x = empty - len(empty) = 0 if x = empty
- len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|)) - len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|))
- len(x) >= 0 otherwise - len(x) >= 0 otherwise
*/ */
void axioms::length_axiom(expr* n) { void axioms::length_axiom(expr* n) {
expr* x = nullptr; expr* x = nullptr, * y = nullptr, * offs = nullptr, * l = nullptr;
VERIFY(seq.str.is_length(n, x)); VERIFY(seq.str.is_length(n, x));
if (seq.str.is_concat(x) || if (seq.str.is_concat(x) && to_app(x)->get_num_args() != 0) {
seq.str.is_unit(x) || ptr_vector<expr> args;
for (auto arg : *to_app(x))
args.push_back(seq.str.mk_length(arg));
expr_ref len(a.mk_add(args), m);
add_clause(mk_eq(len, n));
}
else if (seq.str.is_extract(x, y, offs, l)) {
// len(extract(y, o, l)) = l if len(y) >= o + l, o >= 0, l >= 0
// len(extract(y, o, l)) = 0 if o < 0 or l <= 0 or len(y) < o
// len(extract(y, o, l)) = len(y) - o if o <= len(y) < o + l
expr_ref len_y(mk_len(y), m);
expr_ref z(a.mk_int(0), m);
expr_ref y_ge_l = mk_ge(a.mk_sub(len_y, a.mk_add(offs, l)), 0);
expr_ref y_ge_o = mk_ge(a.mk_sub(len_y, offs), 0);
expr_ref offs_ge_0 = mk_ge(offs, 0);
expr_ref l_ge_0 = mk_ge(l, 0);
add_clause(~offs_ge_0, ~l_ge_0, ~y_ge_l, mk_eq(n, l));
add_clause(offs_ge_0, mk_eq(n, z));
add_clause(l_ge_0, mk_eq(n, z));
add_clause(y_ge_o, mk_eq(n, z));
add_clause(~y_ge_o, y_ge_l, mk_eq(n, a.mk_sub(len_y, offs)));
}
else if (seq.str.is_unit(x) ||
seq.str.is_empty(x) || seq.str.is_empty(x) ||
seq.str.is_string(x)) { seq.str.is_string(x)) {
expr_ref len(n, m); expr_ref len(n, m);

View file

@ -6021,6 +6021,12 @@ bool seq_rewriter::reduce_eq_empty(expr* l, expr* r, expr_ref& result) {
result = m_autil.mk_lt(s, zero()); result = m_autil.mk_lt(s, zero());
return true; return true;
} }
// at(s, offset) = "" <=> len(s) <= offset or offset < 0
if (str().is_at(r, s, offset)) {
expr_ref len_s(str().mk_length(s), m());
result = m().mk_or(m_autil.mk_le(len_s, offset), m_autil.mk_lt(offset, zero()));
return true;
}
return false; return false;
} }

View file

@ -112,7 +112,7 @@ eliminate:
--*/ --*/
#include "params/smt_params_helper.hpp"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
#include "ast/recfun_decl_plugin.h" #include "ast/recfun_decl_plugin.h"
@ -166,7 +166,7 @@ void elim_unconstrained::eliminate() {
expr_ref rr(m.mk_app(t->get_decl(), t->get_num_args(), m_args.data() + sz), m); expr_ref rr(m.mk_app(t->get_decl(), t->get_num_args(), m_args.data() + sz), m);
bool inverted = m_inverter(t->get_decl(), t->get_num_args(), m_args.data() + sz, r); bool inverted = m_inverter(t->get_decl(), t->get_num_args(), m_args.data() + sz, r);
proof_ref pr(m); proof_ref pr(m);
if (inverted && m_enable_proofs) { if (inverted && m_config.m_enable_proofs) {
expr * s = m.mk_app(t->get_decl(), t->get_num_args(), m_args.data() + sz); expr * s = m.mk_app(t->get_decl(), t->get_num_args(), m_args.data() + sz);
expr * eq = m.mk_eq(s, r); expr * eq = m.mk_eq(s, r);
proof * pr1 = m.mk_def_intro(eq); proof * pr1 = m.mk_def_intro(eq);
@ -267,7 +267,7 @@ void elim_unconstrained::reset_nodes() {
*/ */
void elim_unconstrained::init_nodes() { void elim_unconstrained::init_nodes() {
m_enable_proofs = false; m_config.m_enable_proofs = false;
m_trail.reset(); m_trail.reset();
m_fmls.freeze_suffix(); m_fmls.freeze_suffix();
@ -276,7 +276,7 @@ void elim_unconstrained::init_nodes() {
auto [f, p, d] = m_fmls[i](); auto [f, p, d] = m_fmls[i]();
terms.push_back(f); terms.push_back(f);
if (p) if (p)
m_enable_proofs = true; m_config.m_enable_proofs = true;
} }
m_heap.reset(); m_heap.reset();
@ -303,7 +303,7 @@ void elim_unconstrained::init_nodes() {
for (expr* e : terms) for (expr* e : terms)
get_node(e).set_top(); get_node(e).set_top();
m_inverter.set_produce_proofs(m_enable_proofs); m_inverter.set_produce_proofs(m_config.m_enable_proofs);
} }
@ -422,6 +422,8 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector<
} }
void elim_unconstrained::reduce() { void elim_unconstrained::reduce() {
if (!m_config.m_enabled)
return;
generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained");
m_inverter.set_model_converter(mc.get()); m_inverter.set_model_converter(mc.get());
m_created_compound = true; m_created_compound = true;
@ -436,3 +438,8 @@ void elim_unconstrained::reduce() {
mc->reset(); mc->reset();
} }
} }
void elim_unconstrained::updt_params(params_ref const& p) {
smt_params_helper sp(p);
m_config.m_enabled = sp.elim_unconstrained();
}

View file

@ -79,6 +79,10 @@ class elim_unconstrained : public dependent_expr_simplifier {
unsigned m_num_eliminated = 0; unsigned m_num_eliminated = 0;
void reset() { m_num_eliminated = 0; } void reset() { m_num_eliminated = 0; }
}; };
struct config {
bool m_enabled = true;
bool m_enable_proofs = false;
};
expr_inverter m_inverter; expr_inverter m_inverter;
ptr_vector<node> m_nodes; ptr_vector<node> m_nodes;
var_lt m_lt; var_lt m_lt;
@ -86,8 +90,8 @@ class elim_unconstrained : public dependent_expr_simplifier {
expr_ref_vector m_trail; expr_ref_vector m_trail;
expr_ref_vector m_args; expr_ref_vector m_args;
stats m_stats; stats m_stats;
config m_config;
bool m_created_compound = false; bool m_created_compound = false;
bool m_enable_proofs = false;
bool is_var_lt(int v1, int v2) const; bool is_var_lt(int v1, int v2) const;
node& get_node(unsigned n) const { return *m_nodes[n]; } node& get_node(unsigned n) const { return *m_nodes[n]; }
@ -119,4 +123,7 @@ public:
void collect_statistics(statistics& st) const override { st.update("elim-unconstrained", m_stats.m_num_eliminated); } void collect_statistics(statistics& st) const override { st.update("elim-unconstrained", m_stats.m_num_eliminated); }
void reset_statistics() override { m_stats.reset(); } void reset_statistics() override { m_stats.reset(); }
void updt_params(params_ref const& p) override;
}; };

View file

@ -46,6 +46,7 @@ Outline of a presumably better scheme:
#include "ast/simplifiers/solve_context_eqs.h" #include "ast/simplifiers/solve_context_eqs.h"
#include "ast/converters/generic_model_converter.h" #include "ast/converters/generic_model_converter.h"
#include "params/tactic_params.hpp" #include "params/tactic_params.hpp"
#include "params/smt_params_helper.hpp"
namespace euf { namespace euf {
@ -119,6 +120,9 @@ namespace euf {
if (m_fmls.frozen(v)) if (m_fmls.frozen(v))
continue; continue;
if (!m_config.m_enable_non_ground && has_quantifiers(t))
continue;
bool is_safe = true; bool is_safe = true;
unsigned todo_sz = todo.size(); unsigned todo_sz = todo.size();
@ -126,6 +130,8 @@ namespace euf {
// all time-stamps must be at or above current level // all time-stamps must be at or above current level
// unexplored variables that are part of substitution are appended to work list. // unexplored variables that are part of substitution are appended to work list.
SASSERT(m_todo.empty()); SASSERT(m_todo.empty());
m_todo.push_back(t); m_todo.push_back(t);
expr_fast_mark1 visited; expr_fast_mark1 visited;
while (!m_todo.empty()) { while (!m_todo.empty()) {
@ -224,6 +230,9 @@ namespace euf {
void solve_eqs::reduce() { void solve_eqs::reduce() {
if (!m_config.m_enabled)
return;
m_fmls.freeze_suffix(); m_fmls.freeze_suffix();
for (extract_eq* ex : m_extract_plugins) for (extract_eq* ex : m_extract_plugins)
@ -330,6 +339,9 @@ namespace euf {
for (auto* ex : m_extract_plugins) for (auto* ex : m_extract_plugins)
ex->updt_params(p); ex->updt_params(p);
m_rewriter.updt_params(p); m_rewriter.updt_params(p);
smt_params_helper sp(p);
m_config.m_enabled = sp.solve_eqs();
m_config.m_enable_non_ground = sp.solve_eqs_non_ground();
} }
void solve_eqs::collect_param_descrs(param_descrs& r) { void solve_eqs::collect_param_descrs(param_descrs& r) {

View file

@ -41,6 +41,8 @@ namespace euf {
struct config { struct config {
bool m_context_solve = true; bool m_context_solve = true;
unsigned m_max_occs = UINT_MAX; unsigned m_max_occs = UINT_MAX;
bool m_enabled = true;
bool m_enable_non_ground = true;
}; };
stats m_stats; stats m_stats;

View file

@ -20,6 +20,7 @@ def_module_params(module_name='smt',
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'), ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'),
('elim_unconstrained', BOOL, True, 'pre-processing: eliminate unconstrained subterms'), ('elim_unconstrained', BOOL, True, 'pre-processing: eliminate unconstrained subterms'),
('solve_eqs', BOOL, True, 'pre-processing: solve equalities'), ('solve_eqs', BOOL, True, 'pre-processing: solve equalities'),
('solve_eqs.non_ground', BOOL, True, 'pre-processing: solve equalities. Allow eliminating variables by non-ground solutions which can break behavior for model evaluation.'),
('propagate_values', BOOL, True, 'pre-processing: propagate values'), ('propagate_values', BOOL, True, 'pre-processing: propagate values'),
('bound_simplifier', BOOL, True, 'apply bounds simplification during pre-processing'), ('bound_simplifier', BOOL, True, 'apply bounds simplification during pre-processing'),
('pull_nested_quantifiers', BOOL, False, 'pre-processing: pull nested quantifiers'), ('pull_nested_quantifiers', BOOL, False, 'pre-processing: pull nested quantifiers'),

View file

@ -439,7 +439,6 @@ final_check_status theory_seq::final_check_eh() {
} }
bool theory_seq::set_empty(expr* x) { bool theory_seq::set_empty(expr* x) {
add_axiom(~mk_eq(m_autil.mk_int(0), mk_len(x), false), mk_eq_empty(x)); add_axiom(~mk_eq(m_autil.mk_int(0), mk_len(x), false), mk_eq_empty(x));
return true; return true;
@ -475,10 +474,9 @@ bool theory_seq::check_fixed_length(bool is_zero, bool check_long_strings) {
bool found = false; bool found = false;
for (unsigned i = 0; i < m_length.size(); ++i) { for (unsigned i = 0; i < m_length.size(); ++i) {
expr* e = m_length.get(i); expr* e = m_length.get(i);
if (fixed_length(e, is_zero, check_long_strings)) { if (fixed_length(e, is_zero, check_long_strings))
found = true; found = true;
} }
}
return found; return found;
} }