3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-07 18:05:21 +00:00

fixes to bv/dual-solver,

This commit is contained in:
Nikolaj Bjorner 2020-11-08 17:17:43 -08:00
parent a4354c960c
commit 89ffb45c4f
19 changed files with 94 additions and 75 deletions

View file

@ -245,7 +245,7 @@ public:
bool is_unsigned(expr const * n, unsigned& u) const {
rational val;
bool is_int = true;
return is_numeral(n, val, is_int) && is_int && val.is_unsigned(), u = val.get_unsigned(), true;
return is_numeral(n, val, is_int) && is_int && val.is_unsigned() && (u = val.get_unsigned(), true);
}
bool is_numeral(expr const * n, rational & val, bool & is_int) const;
bool is_numeral(expr const * n, rational & val) const { bool is_int; return is_numeral(n, val, is_int); }

View file

@ -95,7 +95,7 @@ unmerge(a,a')
- n1 is reinserted. It used to be a root.
--*/
*/
#include "ast/euf/euf_egraph.h"
#include "ast/ast_pp.h"
@ -317,11 +317,22 @@ namespace euf {
void egraph::set_merge_enabled(enode* n, bool enable_merge) {
if (enable_merge != n->merge_enabled()) {
toggle_merge_enabled(n);
m_updates.push_back(update_record(n, update_record::toggle_merge()));
n->set_merge_enabled(enable_merge);
}
}
void egraph::toggle_merge_enabled(enode* n) {
bool enable_merge = !n->merge_enabled();
n->set_merge_enabled(enable_merge);
if (n->num_args() > 0) {
if (enable_merge)
insert_table(n);
else
m_table.erase(n);
}
}
void egraph::set_value(enode* n, lbool value) {
force_push();
TRACE("euf", tout << bpp(n) << "\n";);
@ -362,7 +373,7 @@ namespace euf {
undo_node();
break;
case update_record::tag_t::is_toggle_merge:
p.r1->set_merge_enabled(!p.r1->merge_enabled());
toggle_merge_enabled(p.r1);
break;
case update_record::tag_t::is_set_parent:
undo_eq(p.r1, p.n1, p.r2_num_parents);
@ -520,6 +531,12 @@ namespace euf {
for (enode* c : enode_class(r1))
c->m_root = r1;
for (enode* p : enode_parents(r1))
if (p->merge_enabled() && !p->is_cgr() && !p->m_cg) {
std::cout << bpp(p) << "\n";
SASSERT(false);
}
for (enode* p : enode_parents(r1))
if (p->merge_enabled() && (p->is_cgr() || !p->congruent(p->m_cg)))
insert_table(p);

View file

@ -196,6 +196,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);
enode_bool_pair insert_table(enode* p);

View file

@ -138,7 +138,7 @@ namespace euf {
bool is_cgr() const { return this == m_cg; }
bool commutative() const { return m_commutative; }
void mark_interpreted() { SASSERT(num_args() == 0); m_interpreted = true; }
bool merge_enabled() { return m_merge_enabled; }
bool merge_enabled() const { return m_merge_enabled; }
enode* get_arg(unsigned i) const { SASSERT(i < num_args()); return m_args[i]; }
unsigned hash() const { return m_expr->hash(); }

View file

@ -1192,10 +1192,10 @@ namespace lp {
impq lar_solver::get_tv_ivalue(tv const& t) const {
if (t.is_var())
return get_ivalue(t.column());
return get_column_value(t.column());
impq r;
for (const auto& p : get_term(t))
r += p.coeff() * get_ivalue(p.column());
r += p.coeff() * get_column_value(p.column());
return r;
}
@ -1317,9 +1317,8 @@ namespace lp {
void lar_solver::mark_rows_for_bound_prop(lpvar j) {
auto& column = A_r().m_columns[j];
for (auto const& r : column) {
m_rows_with_changed_bounds.insert(r.var());
}
for (auto const& r : column)
m_rows_with_changed_bounds.insert(r.var());
}

View file

@ -638,7 +638,7 @@ public:
inline const static_matrix<mpq, impq> & A_r() const { return m_mpq_lar_core_solver.m_r_A; }
// columns
bool column_is_int(column_index const& j) const { return column_is_int((unsigned)j); }
const impq& get_ivalue(column_index const& j) const { return get_column_value(j); }
// const impq& get_ivalue(column_index const& j) const { return get_column_value(j); }
const impq& get_column_value(column_index const& j) const { return m_mpq_lar_core_solver.m_r_x[j]; }
inline
var_index external_to_local(unsigned j) const {

View file

@ -51,7 +51,6 @@ namespace arith {
solver::~solver() {
del_bounds(0);
std::for_each(m_internalize_states.begin(), m_internalize_states.end(), delete_proc<internalize_state>());
}
void solver::asserted(literal l) {

View file

@ -111,7 +111,7 @@ namespace arith {
m_to_ensure_var.reset();
}
};
ptr_vector<internalize_state> m_internalize_states;
scoped_ptr_vector<internalize_state> m_internalize_states;
unsigned m_internalize_head{ 0 };
class scoped_internalize_state {

View file

@ -223,6 +223,9 @@ namespace array {
args1.push_back(k);
args2.push_back(k);
}
std::cout << "e1: " << mk_pp(e1, m) << "\n";
std::cout << "e2: " << mk_pp(e2, m) << "\n";
std::cout << "funcs: " << funcs << "\n";
expr_ref sel1(a.mk_select(args1), m);
expr_ref sel2(a.mk_select(args2), m);
literal lit1 = eq_internalize(e1, e2);
@ -521,13 +524,11 @@ namespace array {
for (unsigned i = 0; i < num_vars; i++) {
euf::enode * n = var2enode(i);
if (!a.is_array(n->get_expr())) {
continue;
}
if (!is_array(n))
continue;
euf::enode * r = n->get_root();
if (r->is_marked1()) {
continue;
}
if (r->is_marked1())
continue;
// arrays used as indices in other arrays have to be treated as shared issue #3532, #3529
if (ctx.is_shared(r) || is_select_arg(r))
roots.push_back(r->get_th_var(get_id()));

View file

@ -86,6 +86,7 @@ namespace array {
}
void solver::internalize_ext(euf::enode* n) {
SASSERT(is_array(n->get_arg(0)));
push_axiom(extensionality_axiom(n->get_arg(0), n->get_arg(1)));
}

View file

@ -165,7 +165,10 @@ namespace array {
void solver::new_diseq_eh(euf::th_eq const& eq) {
force_push();
push_axiom(extensionality_axiom(var2enode(eq.v1()), var2enode(eq.v2())));
euf::enode* n1 = var2enode(eq.v1());
euf::enode* n2 = var2enode(eq.v2());
if (is_array(n1))
push_axiom(extensionality_axiom(n1, n2));
}
bool solver::unit_propagate() {

View file

@ -158,6 +158,7 @@ namespace array {
void collect_shared_vars(sbuffer<theory_var>& roots);
bool add_interface_equalities();
bool is_select_arg(euf::enode* r);
bool is_array(euf::enode* n) const { return a.is_array(n->get_expr()); }
// solving
void add_parent_select(theory_var v_child, euf::enode* select);

View file

@ -176,10 +176,10 @@ namespace bv {
args[i] = arg_value;
expr_ref r(m.mk_app(n->get_decl(), args), m);
set_delay_internalize(r, internalize_mode::init_bits_only_i); // do not bit-blast this multiplier.
args[i] = n->get_arg(i);
std::cout << "@" << s().scope_lvl() << "\n";
args[i] = n->get_arg(i);
add_unit(eq_internalize(r, arg_value));
}
IF_VERBOSE(0, verbose_stream() << "delay internalize @" << s().scope_lvl() << "\n");
return false;
}
if (bv.is_zero(mul_value)) {

View file

@ -133,6 +133,9 @@ namespace bv {
euf::enode* n = expr2enode(e);
app* a = to_app(e);
if (visited(e))
return true;
SASSERT(!n || !n->is_attached_to(get_id()));
bool suppress_args = !get_config().m_bv_reflect && !m.is_considered_uninterpreted(a->get_decl());
if (!n)
@ -294,27 +297,12 @@ namespace bv {
atom* a = get_bv2a(bv);
if (a)
return a;
a = new (get_region()) atom();
a = new (get_region()) atom(bv);
insert_bv2a(bv, a);
ctx.push(mk_atom_trail(bv, *this));
return a;
}
#if 0
solver::eq_atom* solver::mk_eq_atom(sat::bool_var bv) {
atom* a = get_bv2a(bv);
if (a)
return a->is_eq() ? &a->to_eq() : nullptr;
else {
eq_atom* b = new (get_region()) eq_atom();
insert_bv2a(bv, b);
ctx.push(mk_atom_trail(bv, *this));
return b;
}
}
#endif
void solver::set_bit_eh(theory_var v, literal l, unsigned idx) {
SASSERT(m_bits[v][idx] == l);
if (s().value(l) != l_undef && s().lvl(l) == 0)
@ -323,8 +311,7 @@ namespace bv {
atom* b = mk_atom(l.var());
if (b->m_occs)
find_new_diseq_axioms(*b, v, idx);
if (!b->is_fresh())
ctx.push(add_var_pos_trail(b));
ctx.push(add_var_pos_trail(b));
b->m_occs = new (get_region()) var_pos_occ(v, idx, b->m_occs);
}
}
@ -586,7 +573,7 @@ namespace bv {
}
void solver::add_def(sat::literal def, sat::literal l) {
atom* a = new (get_region()) atom();
atom* a = new (get_region()) atom(l.var());
a->m_var = l;
a->m_def = def;
insert_bv2a(l.var(), a);
@ -648,7 +635,7 @@ namespace bv {
m_bits[v_arg][idx] = lit;
TRACE("bv", tout << "add-bit: " << lit << " " << literal2expr(lit) << "\n";);
if (arg_sz > 1) {
atom* a = new (get_region()) atom();
atom* a = new (get_region()) atom(lit.var());
a->m_occs = new (get_region()) var_pos_occ(v_arg, idx);
insert_bv2a(lit.var(), a);
ctx.push(mk_atom_trail(lit.var(), *this));
@ -713,20 +700,12 @@ namespace bv {
void solver::eq_internalized(sat::bool_var b1, sat::bool_var b2, unsigned idx, theory_var v1, theory_var v2, literal lit, euf::enode* n) {
atom* a = mk_atom(b1);
// eq_atom* b = mk_eq_atom(lit.var());
if (a) {
if (!a->is_fresh())
ctx.push(add_eq_occurs_trail(a));
ctx.push(add_eq_occurs_trail(a));
auto* next = a->m_eqs;
a->m_eqs = new (get_region()) eq_occurs(b1, b2, idx, v1, v2, lit, n, next);
if (next)
next->m_prev = a->m_eqs;
#if 0
if (b) {
b->m_eqs.push_back(std::make_pair(a, a->m_eqs));
ctx.push(push_back_vector<euf::solver, svector<std::pair<bit_atom*,eq_occurs*>>>(b->m_eqs));
}
#endif
}
}

View file

@ -44,7 +44,6 @@ namespace bv {
bit_occs_trail(solver& s, atom& a): a(a), m_occs(a.m_occs) {}
virtual void undo(euf::solver& euf) {
IF_VERBOSE(1, verbose_stream() << "add back occurrences " << & a << "\n");
a.m_occs = m_occs;
}
};
@ -400,20 +399,10 @@ namespace bv {
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) {
unsigned num_atoms = 0, num_eqs = 0, num_assigned = 0, num_eq_assigned = 0, num_lit_assigned = 0;
for (auto vp : *p.m_atom) {
if (propagate_bits(vp))
++num_assigned;
++num_atoms;
}
for (auto const& eq : p.m_atom->eqs()) {
++num_eqs;
if (s().value(eq.m_literal) != l_undef)
++num_lit_assigned;
if (propagate_eq_occurs(eq)) {
++num_eq_assigned;
}
}
for (auto vp : *p.m_atom)
propagate_bits(vp);
for (auto const& eq : p.m_atom->eqs())
propagate_eq_occurs(eq);
}
else
propagate_bits(p.m_vp);
@ -669,7 +658,7 @@ namespace bv {
if (!a)
continue;
atom* new_a = new (result->get_region()) atom();
atom* new_a = new (result->get_region()) atom(i);
m_bool_var2atom.setx(i, new_a, nullptr);
for (auto vp : *a)
new_a->m_occs = new (result->get_region()) var_pos_occ(vp.first, vp.second, new_a->m_occs);
@ -800,6 +789,7 @@ namespace bv {
find_wpos(v2);
bool_var cv = consequent.var();
atom* a = get_bv2a(cv);
force_push();
if (a)
for (auto curr : *a)
if (propagate_eqc || find(curr.first) != find(v2) || curr.second != idx)

View file

@ -126,7 +126,7 @@ namespace bv {
eq_occurs_it(eq_occurs* c) : m_first(c) {}
eq_occurs operator*() { return *m_first; }
eq_occurs_it& operator++() { m_first = m_first->m_next; return *this; }
eq_occurs_it operator++(int) { eq_occurs_it tmp = *this; ++* this; return tmp; }
eq_occurs_it operator++(int) { eq_occurs_it tmp = *this; ++*this; return tmp; }
bool operator==(eq_occurs_it const& other) const { return m_first == other.m_first; }
bool operator!=(eq_occurs_it const& other) const { return !(*this == other); }
};
@ -157,16 +157,16 @@ namespace bv {
};
struct atom {
bool_var m_bv;
eq_occurs* m_eqs;
var_pos_occ * m_occs;
svector<std::pair<atom*, eq_occurs*>> m_bit2occ;
literal m_var { sat::null_literal };
literal m_def { sat::null_literal };
atom() :m_eqs(nullptr), m_occs(nullptr) {}
atom(bool_var b) :m_bv(b), m_eqs(nullptr), m_occs(nullptr) {}
~atom() { m_bit2occ.clear(); }
var_pos_it begin() const { return var_pos_it(m_occs); }
var_pos_it end() const { return var_pos_it(nullptr); }
bool is_fresh() const { return !m_occs && !m_eqs; }
eqs_iterator eqs() const { return eqs_iterator(m_eqs); }
};

View file

@ -104,7 +104,7 @@ namespace euf {
sat::literal lit;
if (!m.is_bool(e))
drat_log_node(e);
else
else
lit = attach_lit(literal(si.add_bool_var(e), false), e);
if (!m.is_bool(e) && m.get_sort(e)->get_family_id() != null_family_id) {
@ -153,6 +153,8 @@ namespace euf {
m_egraph.set_bool_var(n, v);
if (m.is_eq(e) || m.is_or(e) || m.is_and(e) || m.is_not(e))
m_egraph.set_merge_enabled(n, false);
if (!si.is_bool_op(e))
track_relevancy(lit.var());
return lit;
}

View file

@ -90,19 +90,42 @@ namespace sat {
}
bool dual_solver::operator()(solver const& s) {
m_core.reset();
m_core.append(m_units);
if (m_roots.empty())
return true;
m_solver.user_push();
m_solver.add_clause(m_roots.size(), m_roots.c_ptr(), status::input());
m_lits.reset();
for (bool_var v : m_tracked_vars)
m_lits.push_back(literal(v, l_false == s.value(m_var2ext[v])));
lbool is_sat = m_solver.check(m_lits.size(), m_lits.c_ptr());
m_core.reset();
m_core.append(m_units);
if (is_sat == l_false)
for (literal lit : m_solver.get_core())
m_core.push_back(lit2ext(lit));
TRACE("euf", m_solver.display(tout << "is-sat: " << is_sat << " core: " << m_core << "\n"););
m_core.push_back(lit2ext(lit));
if (is_sat == l_true) {
IF_VERBOSE(0, display(s, verbose_stream()));
UNREACHABLE();
}
TRACE("dual", m_solver.display(tout << "is-sat: " << is_sat << " core: " << m_core << "\n"););
m_solver.user_pop(1);
return is_sat == l_false;
}
std::ostream& dual_solver::display(solver const& s, std::ostream& out) const {
for (auto r : m_roots)
out << r << " " << m_solver.value(r) << "\n";
for (unsigned v = 0; v < m_solver.num_vars(); ++v) {
bool_var w = m_var2ext.get(v, null_bool_var);
if (w == null_bool_var)
continue;
lbool v1 = m_solver.value(v);
lbool v2 = s.value(w);
if (v1 == v2)
continue;
out << w << " " << v1 << " " << v2 << "\n";
}
return out;
}
}

View file

@ -40,6 +40,9 @@ namespace sat {
bool_var var2ext(bool_var v);
literal ext2lit(literal lit);
literal lit2ext(literal lit);
std::ostream& display(solver const& s, std::ostream& out) const;
public:
dual_solver(reslimit& l);
void push();