3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-25 20:46:01 +00:00

include disequality expansion for non-unit case.

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2024-11-04 09:26:32 -08:00
parent 6559584502
commit b870ed192a
5 changed files with 36 additions and 35 deletions

View file

@ -28,7 +28,7 @@ bit_blaster_cfg::bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, bool
m_rw(rw) { m_rw(rw) {
} }
static void sort_args(expr * & l1, expr * & l2, expr * & l3) { void bit_blaster_cfg::sort_args(expr * & l1, expr * & l2, expr * & l3) {
expr * args[3] = {l1, l2, l3}; expr * args[3] = {l1, l2, l3};
// ast_lt_proc is based on the AST ids. So, it is a total order on AST nodes. // ast_lt_proc is based on the AST ids. So, it is a total order on AST nodes.
// No need for stable_sort // No need for stable_sort
@ -41,7 +41,7 @@ void bit_blaster_cfg::mk_xor3(expr * l1, expr * l2, expr * l3, expr_ref & r) {
TRACE("xor3", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id();); TRACE("xor3", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
sort_args(l1, l2, l3); sort_args(l1, l2, l3);
TRACE("xor3_sorted", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id();); TRACE("xor3_sorted", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
if (m_params.m_bb_ext_gates) { if (m_ext_gates || m_params.m_bb_ext_gates) {
if (l1 == l2) if (l1 == l2)
r = l3; r = l3;
else if (l1 == l3) else if (l1 == l3)
@ -80,7 +80,7 @@ void bit_blaster_cfg::mk_carry(expr * l1, expr * l2, expr * l3, expr_ref & r) {
TRACE("carry", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id();); TRACE("carry", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
sort_args(l1, l2, l3); sort_args(l1, l2, l3);
TRACE("carry_sorted", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id();); TRACE("carry_sorted", tout << "#" << l1->get_id() << " #" << l2->get_id() << " #" << l3->get_id(););
if (m_params.m_bb_ext_gates) { if (m_ext_gates || m_params.m_bb_ext_gates) {
if ((m().is_false(l1) && m().is_false(l2)) || if ((m().is_false(l1) && m().is_false(l2)) ||
(m().is_false(l1) && m().is_false(l3)) || (m().is_false(l1) && m().is_false(l3)) ||
(m().is_false(l2) && m().is_false(l3))) (m().is_false(l2) && m().is_false(l3)))

View file

@ -31,35 +31,39 @@ protected:
bv_util & m_util; bv_util & m_util;
bit_blaster_params const & m_params; bit_blaster_params const & m_params;
bool_rewriter & m_rw; bool_rewriter & m_rw;
bool m_ext_gates = false;
void sort(expr*& a, expr*& b) { if (a->get_id() > b->get_id()) std::swap(a, b); }
void sort_args(expr*& l1, expr*& l2, expr*& l3);
public: public:
bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, bool_rewriter& rw); bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, bool_rewriter& rw);
ast_manager & m() const { return m_util.get_manager(); } ast_manager & m() const { return m_util.get_manager(); }
numeral power(unsigned n) const { return rational::power_of_two(n); } numeral power(unsigned n) const { return rational::power_of_two(n); }
void mk_xor(expr * a, expr * b, expr_ref & r) { m_rw.mk_xor(a, b, r); } void mk_xor(expr * a, expr * b, expr_ref & r) { sort(a, b); m_rw.mk_xor(a, b, r); }
void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r); void mk_xor3(expr * a, expr * b, expr * c, expr_ref & r);
void mk_carry(expr * a, expr * b, expr * c, expr_ref & r); void mk_carry(expr * a, expr * b, expr * c, expr_ref & r);
void mk_iff(expr * a, expr * b, expr_ref & r) { m_rw.mk_iff(a, b, r); } void mk_iff(expr * a, expr * b, expr_ref & r) { sort(a, b); m_rw.mk_iff(a, b, r); }
void mk_and(expr * a, expr * b, expr_ref & r) { m_rw.mk_and(a, b, r); } void mk_and(expr * a, expr * b, expr_ref & r) { sort(a, b); m_rw.mk_and(a, b, r); }
void mk_and(expr * a, expr * b, expr * c, expr_ref & r) { m_rw.mk_and(a, b, c, r); } void mk_and(expr* a, expr* b, expr* c, expr_ref& r) { sort_args(a, b, c); m_rw.mk_and(a, b, c, r); }
void mk_and(unsigned sz, expr * const * args, expr_ref & r) { m_rw.mk_and(sz, args, r); } void mk_and(unsigned sz, expr * const * args, expr_ref & r) { m_rw.mk_and(sz, args, r); }
void mk_ge2(expr* a, expr* b, expr* c, expr_ref& r) { m_rw.mk_ge2(a, b, c, r); } void mk_ge2(expr* a, expr* b, expr* c, expr_ref& r) { m_rw.mk_ge2(a, b, c, r); }
void mk_or(expr * a, expr * b, expr_ref & r) { m_rw.mk_or(a, b, r); } void mk_or(expr * a, expr * b, expr_ref & r) { sort(a, b); m_rw.mk_or(a, b, r); }
void mk_or(expr * a, expr * b, expr * c, expr_ref & r) { m_rw.mk_or(a, b, c, r); } void mk_or(expr * a, expr * b, expr * c, expr_ref & r) { sort_args(a, b, c); m_rw.mk_or(a, b, c, r); }
void mk_or(unsigned sz, expr * const * args, expr_ref & r) { m_rw.mk_or(sz, args, r); } void mk_or(unsigned sz, expr * const * args, expr_ref & r) { m_rw.mk_or(sz, args, r); }
void mk_not(expr * a, expr_ref & r) { m_rw.mk_not(a, r); } void mk_not(expr * a, expr_ref & r) { m_rw.mk_not(a, r); }
void mk_ite(expr * c, expr * t, expr * e, expr_ref & r) { m_rw.mk_ite(c, t, e, r); } void mk_ite(expr * c, expr * t, expr * e, expr_ref & r) { m_rw.mk_ite(c, t, e, r); }
void mk_nand(expr * a, expr * b, expr_ref & r) { m_rw.mk_nand(a, b, r); } void mk_nand(expr * a, expr * b, expr_ref & r) { sort(a, b); m_rw.mk_nand(a, b, r); }
void mk_nor(expr * a, expr * b, expr_ref & r) { m_rw.mk_nor(a, b, r); } void mk_nor(expr * a, expr * b, expr_ref & r) { sort(a, b); m_rw.mk_nor(a, b, r); }
}; };
class bit_blaster : public bit_blaster_tpl<bit_blaster_cfg> { class bit_blaster : public bit_blaster_tpl<bit_blaster_cfg> {
bv_util m_util; bv_util m_util;
bool_rewriter m_rw; bool_rewriter m_rw;
public: public:
bit_blaster(ast_manager & m, bit_blaster_params const & params); bit_blaster(ast_manager & m, bit_blaster_params const & params);
bit_blaster_params const & get_params() const { return this->m_params; } bit_blaster_params const & get_params() const { return this->m_params; }
void set_flat_and_or(bool f) { m_rw.set_flat_and_or(f); } void set_flat_and_or(bool f) { m_rw.set_flat_and_or(f); }
void set_ext_gates(bool f) { m_ext_gates = f; }
}; };

View file

@ -56,6 +56,7 @@ namespace bv {
m_bb(m, get_config()), m_bb(m, get_config()),
m_find(*this) { m_find(*this) {
m_bb.set_flat_and_or(false); m_bb.set_flat_and_or(false);
m_bb.set_ext_gates(true);
} }
bool solver::is_fixed(euf::theory_var v, expr_ref& val, sat::literal_vector& lits) { bool solver::is_fixed(euf::theory_var v, expr_ref& val, sat::literal_vector& lits) {
@ -267,7 +268,7 @@ namespace bv {
++num_undef; ++num_undef;
undef_idx = -static_cast<int>(i + 1); undef_idx = -static_cast<int>(i + 1);
} }
if (num_undef > 1) if (num_undef > 1 && false)
return; return;
} }
if (num_undef == 0) if (num_undef == 0)
@ -533,12 +534,10 @@ namespace bv {
} }
bool solver::unit_propagate() { bool solver::unit_propagate() {
if (m_prop_queue_head == m_prop_queue.size()) if (m_prop_queue.empty())
return false; return false;
force_push(); for (unsigned i = 0; i < m_prop_queue.size() && !s().inconsistent(); ++i) {
ctx.push(value_trail<unsigned>(m_prop_queue_head)); auto const p = m_prop_queue[i];
for (; m_prop_queue_head < m_prop_queue.size() && !s().inconsistent(); ++m_prop_queue_head) {
auto const p = m_prop_queue[m_prop_queue_head];
if (p.m_atom) { if (p.m_atom) {
for (auto vp : *p.m_atom) for (auto vp : *p.m_atom)
propagate_bits(vp); propagate_bits(vp);
@ -548,6 +547,7 @@ namespace bv {
else else
propagate_bits(p.m_vp); propagate_bits(p.m_vp);
} }
m_prop_queue.reset();
// check_missing_propagation(); // check_missing_propagation();
return true; return true;
} }
@ -587,6 +587,8 @@ namespace bv {
if (m_wpos[v1] == idx) if (m_wpos[v1] == idx)
find_wpos(v1); find_wpos(v1);
bool is_fixed = s().value(m_bits[v1][m_wpos[v1]]) != l_undef;
literal bit1 = m_bits[v1][idx]; literal bit1 = m_bits[v1][idx];
lbool val = s().value(bit1); lbool val = s().value(bit1);
TRACE("bv", tout << "propagating v" << v1 << " #" << var2enode(v1)->get_expr_id() << "[" << idx << "] = " << val << "\n";); TRACE("bv", tout << "propagating v" << v1 << " #" << var2enode(v1)->get_expr_id() << "[" << idx << "] = " << val << "\n";);
@ -613,7 +615,7 @@ namespace bv {
if (!assign_bit(bit2, v1, v2, idx, bit1, false)) if (!assign_bit(bit2, v1, v2, idx, bit1, false))
break; break;
} }
if (s().value(m_bits[v1][m_wpos[v1]]) != l_undef) if (!is_fixed && s().value(m_bits[v1][m_wpos[v1]]) != l_undef)
find_wpos(v1); find_wpos(v1);
return num_assigned > 0; return num_assigned > 0;
@ -626,7 +628,7 @@ namespace bv {
*/ */
sat::check_result solver::check() { sat::check_result solver::check() {
force_push(); force_push();
SASSERT(m_prop_queue.size() == m_prop_queue_head); SASSERT(m_prop_queue.empty());
bool ok = true; bool ok = true;
svector<std::pair<expr*, internalize_mode>> delay; svector<std::pair<expr*, internalize_mode>> delay;
for (auto kv : m_delay_internalize) for (auto kv : m_delay_internalize)
@ -651,22 +653,19 @@ namespace bv {
} }
void solver::push_core() { void solver::push_core() {
TRACE("bv", tout << "push: " << get_num_vars() << "@" << m_prop_queue_lim.size() << "\n";); TRACE("bv", tout << "push: " << get_num_vars() << "@" << m_prop_queue.size() << "\n";);
th_euf_solver::push_core(); th_euf_solver::push_core();
m_prop_queue_lim.push_back(m_prop_queue.size());
} }
void solver::pop_core(unsigned n) { void solver::pop_core(unsigned n) {
SASSERT(m_num_scopes == 0); SASSERT(m_num_scopes == 0);
unsigned old_sz = m_prop_queue_lim.size() - n;
m_prop_queue.shrink(m_prop_queue_lim[old_sz]);
m_prop_queue_lim.shrink(old_sz);
th_euf_solver::pop_core(n); th_euf_solver::pop_core(n);
old_sz = get_num_vars(); unsigned old_sz = get_num_vars();
m_bits.shrink(old_sz); m_bits.shrink(old_sz);
m_wpos.shrink(old_sz); m_wpos.shrink(old_sz);
m_zero_one_bits.shrink(old_sz); m_zero_one_bits.shrink(old_sz);
TRACE("bv", tout << "num vars " << old_sz << "@" << m_prop_queue_lim.size() << "\n";); m_prop_queue.reset();
TRACE("bv", tout << "num vars " << old_sz << "\n";);
} }
void solver::simplify() { void solver::simplify() {
@ -886,12 +885,14 @@ namespace bv {
void solver::merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { void solver::merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {
TRACE("bv", tout << "merging: v" << v1 << " #" << var2enode(v1)->get_expr_id() << " v" << v2 << " #" << var2enode(v2)->get_expr_id() << "\n";); TRACE("bv", tout << "merging: v" << v1 << " #" << var2enode(v1)->get_expr_id() << " v" << v2 << " #" << var2enode(v2)->get_expr_id() << "\n";);
if (!merge_zero_one_bits(r1, r2)) { if (!merge_zero_one_bits(r1, r2)) {
TRACE("bv", tout << "conflict detected\n";); TRACE("bv", tout << "conflict detected\n";);
return; // conflict was detected return; // conflict was detected
} }
m_prop_queue.reset();
SASSERT(m_bits[v1].size() == m_bits[v2].size()); SASSERT(m_bits[v1].size() == m_bits[v2].size());
unsigned sz = m_bits[v1].size(); unsigned sz = m_bits[v1].size();
if (sz == 1) if (sz == 1)
@ -982,8 +983,9 @@ namespace bv {
force_push(); force_push();
if (a) if (a)
for (auto curr : *a) for (auto curr : *a)
if (propagate_eqc || find(curr.first) != find(v2) || curr.second != idx) if (propagate_eqc || find(curr.first) != find(v2) || curr.second != idx) {
m_prop_queue.push_back(propagation_item(curr)); m_prop_queue.push_back(propagation_item(curr));
}
return true; return true;
} }
} }

View file

@ -234,8 +234,6 @@ namespace bv {
mutable vector<rational> m_power2; mutable vector<rational> m_power2;
literal_vector m_tmp_literals; literal_vector m_tmp_literals;
svector<propagation_item> m_prop_queue; svector<propagation_item> m_prop_queue;
unsigned_vector m_prop_queue_lim;
unsigned m_prop_queue_head = 0;
sat::literal m_true = sat::null_literal; sat::literal m_true = sat::null_literal;
euf::enode_vector m_bv2ints; euf::enode_vector m_bv2ints;
obj_map<app, lazy_mul*> m_lazymul; obj_map<app, lazy_mul*> m_lazymul;

View file

@ -155,9 +155,7 @@ namespace euf {
if (lit.sign()) { if (lit.sign()) {
v = si.add_bool_var(e); v = si.add_bool_var(e);
s().set_external(v); s().set_external(v);
s().set_eliminated(v, false); s().set_eliminated(v, false);
set_bool_var2expr(v, e);
m_var_trail.push_back(v);
sat::literal lit2 = literal(v, false); sat::literal lit2 = literal(v, false);
th_proof_hint* ph1 = nullptr, * ph2 = nullptr; th_proof_hint* ph1 = nullptr, * ph2 = nullptr;
if (use_drat()) { if (use_drat()) {
@ -185,7 +183,6 @@ namespace euf {
return lit; return lit;
} }
set_bool_var2expr(v, e); set_bool_var2expr(v, e);
enode* n = m_egraph.find(e); enode* n = m_egraph.find(e);
if (!n) if (!n)