mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
Fix integration of propagate_from_containing_slice
This commit is contained in:
parent
dfb200a3c9
commit
aa1285288e
6 changed files with 137 additions and 56 deletions
|
@ -387,11 +387,11 @@ namespace polysat {
|
|||
}
|
||||
|
||||
void core::propagate_assignment(pvar v, rational const& value, dependency dep) {
|
||||
TRACE("bv", tout << "propagate assignment v" << v << " := " << value << "\n");
|
||||
TRACE("bv", tout << "propagate assignment v" << v << " := " << value << " justified by " << dep << "\n");
|
||||
// verbose_stream() << "propagate assignment v" << v << " := " << value << " justified by " << dep << "\n";
|
||||
SASSERT(!is_assigned(v));
|
||||
if (!m_viable.assign(v, value)) {
|
||||
if (!m_viable.assign(v, value, dep)) {
|
||||
auto deps = m_viable.explain();
|
||||
deps.push_back(dep);
|
||||
verbose_stream() << "non-viable assignment v" << v << " == " << value << " <- " << deps << "\n";
|
||||
s.set_conflict(deps, "non-viable assignment");
|
||||
return;
|
||||
|
@ -532,7 +532,7 @@ namespace polysat {
|
|||
};
|
||||
|
||||
auto& value = m_constraint_index[index.id].value;
|
||||
TRACE("bv", tout << "assignment " << index.id << " " << m_constraint_index[index.id].sc << " := " << value << " sign: " << sign << "\n");
|
||||
TRACE("bv", tout << "assignment cid=" << index.id << " " << m_constraint_index[index.id].sc << " := " << value << " sign: " << sign << "\n");
|
||||
|
||||
if (value != l_undef &&
|
||||
((value == l_false && !sign) || (value == l_true && sign))) {
|
||||
|
|
|
@ -17,11 +17,17 @@ Author:
|
|||
#include "util/trail.h"
|
||||
#include "util/sat_literal.h"
|
||||
|
||||
namespace euf {
|
||||
class enode;
|
||||
}
|
||||
|
||||
namespace polysat {
|
||||
|
||||
using pdd = dd::pdd;
|
||||
using pvar = unsigned;
|
||||
using theory_var = int;
|
||||
using enode_pair = std::pair<euf::enode*, euf::enode*>;
|
||||
|
||||
struct constraint_id {
|
||||
unsigned id = UINT_MAX;
|
||||
bool is_null() const { return id == UINT_MAX; }
|
||||
|
@ -60,6 +66,8 @@ namespace polysat {
|
|||
offset_slice(pvar child, unsigned offset) : child(child), offset(offset) {}
|
||||
};
|
||||
|
||||
// parent[X:offset] = child
|
||||
// where X = offset + size(child) - 1
|
||||
struct offset_claim : public offset_slice {
|
||||
pvar parent;
|
||||
offset_claim() = default;
|
||||
|
@ -69,22 +77,25 @@ namespace polysat {
|
|||
|
||||
class dependency {
|
||||
struct axiom_t {};
|
||||
std::variant<axiom_t, sat::bool_var, theory_var_pair, offset_claim, fixed_claim> m_data;
|
||||
std::variant<axiom_t, sat::bool_var, theory_var_pair, enode_pair, offset_claim, fixed_claim> m_data;
|
||||
dependency(): m_data(axiom_t()) {}
|
||||
public:
|
||||
dependency(sat::bool_var v) : m_data(v){}
|
||||
dependency(theory_var v1, theory_var v2) : m_data(std::make_pair(v1, v2)) {}
|
||||
dependency(theory_var v1, theory_var v2) : m_data(std::make_pair(v1, v2)) {}
|
||||
dependency(euf::enode* n1, euf::enode* n2) : m_data(std::make_pair(n1, n2)) {}
|
||||
dependency(offset_claim const& c) : m_data(c) {}
|
||||
dependency(fixed_claim const& c): m_data(c) {}
|
||||
static dependency axiom() { return dependency(); }
|
||||
bool is_null() const { return is_bool_var() && *std::get_if<sat::bool_var>(&m_data) == sat::null_bool_var; }
|
||||
bool is_axiom() const { return std::holds_alternative<axiom_t>(m_data); }
|
||||
bool is_eq() const { return std::holds_alternative<theory_var_pair>(m_data); }
|
||||
bool is_enode_eq() const { return std::holds_alternative<enode_pair>(m_data); }
|
||||
bool is_bool_var() const { return std::holds_alternative<sat::bool_var>(m_data); }
|
||||
bool is_offset_claim() const { return std::holds_alternative<offset_claim>(m_data); }
|
||||
bool is_fixed_claim() const { return std::holds_alternative<fixed_claim>(m_data); }
|
||||
sat::bool_var bool_var() const { SASSERT(is_bool_var()); return *std::get_if<sat::bool_var>(&m_data); }
|
||||
theory_var_pair eq() const { SASSERT(is_eq()); return *std::get_if<theory_var_pair>(&m_data); }
|
||||
enode_pair enode_eq() const { SASSERT(is_enode_eq()); return *std::get_if<enode_pair>(&m_data); }
|
||||
offset_claim offset() const { return *std::get_if<offset_claim>(&m_data); }
|
||||
fixed_claim fixed() const { return *std::get_if<fixed_claim>(&m_data); }
|
||||
};
|
||||
|
@ -100,6 +111,8 @@ namespace polysat {
|
|||
return out << d.bool_var();
|
||||
else if (d.is_eq())
|
||||
return out << "tv" << d.eq().first << " == tv" << d.eq().second;
|
||||
else if (d.is_enode_eq())
|
||||
return out << "enode " << d.enode_eq().first << " == enode " << d.enode_eq().second;
|
||||
else if (d.is_offset_claim()) {
|
||||
auto offs = d.offset();
|
||||
return out << "v" << offs.child << " == v" << offs.parent << " offset " << offs.offset;
|
||||
|
@ -125,6 +138,10 @@ namespace polysat {
|
|||
using fixed_bits_vector = vector<fixed_slice>;
|
||||
|
||||
struct fixed_slice_extra : public fixed_slice {
|
||||
// pvar child;
|
||||
// unsigned offset = 0;
|
||||
// unsigned length = 0;
|
||||
// rational value;
|
||||
unsigned level = 0; // level when sub-slice was fixed to value
|
||||
dependency dep = null_dependency;
|
||||
fixed_slice_extra() = default;
|
||||
|
@ -134,9 +151,13 @@ namespace polysat {
|
|||
using fixed_slice_extra_vector = vector<fixed_slice_extra>;
|
||||
|
||||
struct offset_slice_extra : public offset_slice {
|
||||
unsigned level = 0; // level when variable was fixed to value
|
||||
// pvar child;
|
||||
// unsigned offset;
|
||||
unsigned level = 0; // level when child was fixed to value
|
||||
dependency dep = null_dependency; // justification for fixed value
|
||||
rational value; // fixed value of child
|
||||
offset_slice_extra() = default;
|
||||
offset_slice_extra(pvar child, unsigned offset, unsigned level) : offset_slice(child, offset), level(level) {}
|
||||
offset_slice_extra(pvar child, unsigned offset, unsigned level, dependency dep, rational value) : offset_slice(child, offset), level(level), dep(std::move(dep)), value(std::move(value)) {}
|
||||
};
|
||||
using offset_slice_extra_vector = vector<offset_slice_extra>;
|
||||
|
||||
|
@ -172,7 +193,7 @@ namespace polysat {
|
|||
virtual void get_bitvector_super_slices(pvar v, offset_slices& out) = 0;
|
||||
virtual void get_fixed_bits(pvar v, fixed_bits_vector& fixed_slice) = 0;
|
||||
virtual void get_fixed_sub_slices(pvar v, fixed_slice_extra_vector& fixed_slice, offset_slice_extra_vector& subslices) = 0;
|
||||
virtual pdd mk_ite(signed_constraint const& sc, pdd const& p, pdd const& q) = 0;
|
||||
virtual pdd mk_ite(signed_constraint const& sc, pdd const& p, pdd const& q) = 0;
|
||||
virtual pdd mk_zero_extend(unsigned sz, pdd const& p) = 0;
|
||||
virtual unsigned level(dependency const& d) = 0;
|
||||
};
|
||||
|
|
|
@ -83,12 +83,13 @@ namespace polysat {
|
|||
return e;
|
||||
}
|
||||
|
||||
bool viable::assign(pvar v, rational const& value) {
|
||||
bool viable::assign(pvar v, rational const& value, dependency dep) {
|
||||
m_var = v;
|
||||
m_explain_kind = explain_t::none;
|
||||
m_num_bits = c.size(v);
|
||||
m_fixed_bits.init(v);
|
||||
m_explain.reset();
|
||||
m_assign_dep = null_dependency;
|
||||
init_overlaps(v);
|
||||
bool first = true;
|
||||
while (true) {
|
||||
|
@ -99,6 +100,7 @@ namespace polysat {
|
|||
continue;
|
||||
m_explain.push_back({ e, value });
|
||||
m_explain_kind = explain_t::assignment;
|
||||
m_assign_dep = dep;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +126,7 @@ namespace polysat {
|
|||
m_fixed_bits.init(v);
|
||||
init_overlaps(v);
|
||||
m_explain_kind = explain_t::none;
|
||||
m_assign_dep = null_dependency;
|
||||
|
||||
for (unsigned rounds = 0; rounds < 10; ) {
|
||||
entry* n = find_overlap(lo);
|
||||
|
@ -558,9 +561,9 @@ namespace polysat {
|
|||
}
|
||||
|
||||
/*
|
||||
* Explain why the current variable is not viable or
|
||||
* or why it can only have a single value.
|
||||
*/
|
||||
* Explain why the current variable is not viable or
|
||||
* or why it can only have a single value.
|
||||
*/
|
||||
dependency_vector viable::explain() {
|
||||
dependency_vector result;
|
||||
auto last = m_explain.back();
|
||||
|
@ -635,20 +638,32 @@ namespace polysat {
|
|||
if (m_explain_kind == explain_t::assignment) {
|
||||
// there is just one entry
|
||||
SASSERT(m_explain.size() == 1);
|
||||
SASSERT(!m_assign_dep.is_null());
|
||||
explain_entry(last.e);
|
||||
|
||||
// assignment conflict and propagation from containing slice depends on concrete values,
|
||||
// so we also need the evaluations of linear terms
|
||||
SASSERT(!c.is_assigned(m_var)); // assignment of m_var is justified by m_assign_dep
|
||||
auto index = last.e->constraint_index;
|
||||
if (!index.is_null())
|
||||
result.append(c.explain_weak_eval(c.get_constraint(index)));
|
||||
|
||||
auto exp = propagate_from_containing_slice(last.e, last.value, result);
|
||||
// verbose_stream() << "exp is " << exp << "\n";
|
||||
if (!exp.is_null()) {
|
||||
result.clear();
|
||||
result.push_back(exp);
|
||||
}
|
||||
// 'result' so far contains explanation for entry and its weak evaluation
|
||||
switch (propagate_from_containing_slice(last.e, last.value, result)) {
|
||||
case l_true:
|
||||
// propagated interval onto subslice
|
||||
result = m_containing_slice_deps;
|
||||
break;
|
||||
case l_false:
|
||||
// conflict (projected interval is full)
|
||||
result = m_containing_slice_deps;
|
||||
break;
|
||||
case l_undef:
|
||||
// unable to propagate interval to containing slice
|
||||
// fallback explanation uses assignment of m_var
|
||||
result.push_back(m_assign_dep);
|
||||
break;
|
||||
};
|
||||
}
|
||||
unmark();
|
||||
if (c.inconsistent())
|
||||
|
@ -656,20 +671,32 @@ namespace polysat {
|
|||
return result;
|
||||
}
|
||||
|
||||
dependency viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps) {
|
||||
/*
|
||||
* l_true: successfully projected interval onto subslice
|
||||
* l_false: also successfully projected interval onto subslice, resulted in full interval
|
||||
* l_undef: failed
|
||||
*
|
||||
* In case of l_true/l_false, conflict will be in m_containing_slice_deps.
|
||||
*/
|
||||
lbool viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps) {
|
||||
verbose_stream() << "\n\n\n\n\n\nNon-viable assignment for v" << m_var << " size " << c.size(m_var) << "\n";
|
||||
display_one(verbose_stream() << "entry: ", e) << "\n";
|
||||
verbose_stream() << "value " << value << "\n";
|
||||
// verbose_stream() << "m_overlaps " << m_overlaps << "\n";
|
||||
m_fixed_bits.display(verbose_stream() << "fixed: ") << "\n";
|
||||
|
||||
// TODO: each of subslices corresponds to one in fixed, but may occur with different pvars
|
||||
// for each offset/length with pvar we need to do the projection only once.
|
||||
fixed_slice_extra_vector fixed;
|
||||
offset_slice_extra_vector subslices;
|
||||
c.s.get_fixed_sub_slices(m_var, fixed, subslices); // TODO: move into m_fixed bits?
|
||||
|
||||
TRACE("bv", c.display(tout));
|
||||
|
||||
// this case occurs if e-graph merges e.g. nodes "x - 2" and "3";
|
||||
// polysat will see assignment "x = 5" but no fixed bits
|
||||
if (subslices.empty())
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
|
||||
unsigned max_level = 0;
|
||||
for (auto const& slice : subslices)
|
||||
|
@ -688,19 +715,19 @@ namespace polysat {
|
|||
});
|
||||
|
||||
for (auto const& slice : subslices)
|
||||
if (auto d = propagate_from_containing_slice(e, value, e_deps, fixed, slice); !d.is_null())
|
||||
return d;
|
||||
return null_dependency;
|
||||
if (auto r = propagate_from_containing_slice(e, value, e_deps, fixed, slice); r != l_undef)
|
||||
return r;
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
dependency viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, fixed_slice_extra_vector const& fixed, offset_slice_extra const& slice) {
|
||||
lbool viable::propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, fixed_slice_extra_vector const& fixed, offset_slice_extra const& slice) {
|
||||
pvar w = slice.child;
|
||||
unsigned offset = slice.offset;
|
||||
unsigned w_level = slice.level; // level where value of w was fixed
|
||||
if (w == m_var)
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
if (w == e->var)
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
|
||||
// verbose_stream() << "v" << m_var << " size " << c.size(m_var) << ", v" << w << " size " << c.size(w) << " offset " << offset << " level " << w_level << "\n";
|
||||
|
||||
|
@ -725,7 +752,7 @@ namespace polysat {
|
|||
// wwwwwwwww
|
||||
unsigned const v_sz = e->bit_width;
|
||||
if (offset >= v_sz)
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
|
||||
unsigned const w_sz = c.size(w);
|
||||
unsigned const z_sz = offset;
|
||||
|
@ -744,9 +771,8 @@ namespace polysat {
|
|||
verbose_stream() << "propagate interval " << v_ivl << " from v" << m_var << " to v" << w << "[" << y_sz << "]" << "\n";
|
||||
});
|
||||
|
||||
dependency_vector deps;
|
||||
deps.append(e_deps); // explains e
|
||||
deps.push_back(offset_claim{m_var, slice}); // explains m_var[...] = w
|
||||
dependency_vector& deps = m_containing_slice_deps;
|
||||
deps.reset();
|
||||
|
||||
r_interval ivl = v_ivl;
|
||||
|
||||
|
@ -756,6 +782,8 @@ namespace polysat {
|
|||
while (remaining_x_sz > 0 && !ivl.is_empty() && !ivl.is_full()) {
|
||||
unsigned remaining_x_end = remaining_x_sz + x_off;
|
||||
// find next fixed slice (prefer lower level)
|
||||
// sort fixed claims by bound (upper: decreasing, lower: increasing), then by merge-level (prefer lower merge level), ignore merge level higher than var? (or just max?)
|
||||
// note that we might choose multiple overlapping ones, if they allow to make more progress?
|
||||
fixed_slice_extra best;
|
||||
unsigned best_end = 0;
|
||||
SASSERT(best_end < x_off); // because y_sz != 0
|
||||
|
@ -819,7 +847,7 @@ namespace polysat {
|
|||
}
|
||||
|
||||
if (ivl.is_empty())
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
|
||||
// chop off z-part
|
||||
unsigned remaining_z_sz = z_sz;
|
||||
|
@ -886,24 +914,44 @@ namespace polysat {
|
|||
}
|
||||
|
||||
if (ivl.is_empty())
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
|
||||
IF_VERBOSE(3, {
|
||||
verbose_stream() << "=> v" << w << "[" << y_sz << "] not in " << ivl << "\n";
|
||||
});
|
||||
|
||||
deps.append(e_deps); // explains e
|
||||
deps.push_back(offset_claim{m_var, slice}); // explains m_var[...] = w
|
||||
|
||||
if (ivl.is_full()) {
|
||||
pdd zero = c.var2pdd(m_var).zero();
|
||||
auto sc = cs.ult(zero, zero); // false
|
||||
return c.propagate(sc, deps, "propagate from containing slice (conflict)");
|
||||
// deps is a conflict
|
||||
return l_false;
|
||||
}
|
||||
else {
|
||||
// proper interval
|
||||
auto sc = ~cs.ult(w_shift * (c.var(w) - ivl.lo()), w_shift * (ivl.hi() - ivl.lo()));
|
||||
return c.propagate(sc, deps, "propagate from containing slice");
|
||||
SASSERT(ivl.is_proper() && !ivl.is_empty());
|
||||
// deps => 2^w_shift w not in ivl
|
||||
signed_constraint sc = ~cs.ult(w_shift * (c.var(w) - ivl.lo()), w_shift * (ivl.hi() - ivl.lo()));
|
||||
dependency d = c.propagate(sc, deps, "propagate from containing slice");
|
||||
|
||||
verbose_stream() << "v" << w << " value " << slice.value << "\n";
|
||||
verbose_stream() << "v" << w << " value-dep " << slice.dep << "\n";
|
||||
|
||||
if (ivl.contains(slice.value)) {
|
||||
// the conflict is projected interval + fixed value
|
||||
deps.reset();
|
||||
deps.push_back(d);
|
||||
deps.push_back(slice.dep);
|
||||
return l_true;
|
||||
}
|
||||
else {
|
||||
// interval propagation worked but it doesn't conflict the currently assigned value
|
||||
// TODO: also skip propagation of the signed constraint in this case?
|
||||
return l_undef;
|
||||
}
|
||||
}
|
||||
|
||||
return null_dependency;
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1120,6 +1168,7 @@ namespace polysat {
|
|||
}
|
||||
|
||||
// verbose_stream() << "v" << v << " " << sc << " " << ne->interval << "\n";
|
||||
TRACE("bv", tout << "v" << v << " " << sc << " " << ne->interval << "\n"; display_one(tout, ne) << "\n");
|
||||
|
||||
if (ne->interval.is_currently_empty()) {
|
||||
m_alloc.push_back(ne);
|
||||
|
|
|
@ -115,8 +115,10 @@ namespace polysat {
|
|||
|
||||
bool intersect(pvar v, entry* e);
|
||||
|
||||
dependency propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps);
|
||||
dependency propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, fixed_slice_extra_vector const& fixed, offset_slice_extra const& slice);
|
||||
lbool propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps);
|
||||
lbool propagate_from_containing_slice(entry* e, rational const& value, dependency_vector const& e_deps, fixed_slice_extra_vector const& fixed, offset_slice_extra const& slice);
|
||||
dependency_vector m_containing_slice_deps;
|
||||
|
||||
static r_interval chop_off_upper(r_interval const& i, unsigned Ny, unsigned Nz, rational const* y_fixed_value = nullptr);
|
||||
static r_interval chop_off_lower(r_interval const& i, unsigned Ny, unsigned Nz, rational const* z_fixed_value = nullptr);
|
||||
|
||||
|
@ -149,6 +151,7 @@ namespace polysat {
|
|||
|
||||
pvar m_var = null_var;
|
||||
explain_t m_explain_kind = explain_t::none;
|
||||
dependency m_assign_dep = null_dependency;
|
||||
unsigned m_num_bits = 0;
|
||||
fixed_bits m_fixed_bits;
|
||||
offset_slices m_overlaps;
|
||||
|
@ -167,25 +170,24 @@ namespace polysat {
|
|||
find_t find_viable(pvar v, rational& out_val);
|
||||
|
||||
/*
|
||||
* Explain the current variable is not viable or signleton.
|
||||
*/
|
||||
* Explain the current variable is not viable or singleton.
|
||||
*/
|
||||
dependency_vector explain();
|
||||
|
||||
/*
|
||||
* Register constraint at index 'idx' as unitary in v.
|
||||
*/
|
||||
* Register constraint at index 'idx' as unitary in v.
|
||||
*/
|
||||
find_t add_unitary(pvar v, constraint_id, rational& value);
|
||||
|
||||
/*
|
||||
* Ensure data-structures tracking variable v.
|
||||
*/
|
||||
* Ensure data-structures tracking variable v.
|
||||
*/
|
||||
void ensure_var(pvar v);
|
||||
|
||||
/*
|
||||
* Check if assignment is viable.
|
||||
*/
|
||||
bool assign(pvar v, rational const& value);
|
||||
|
||||
* Check if assignment is viable.
|
||||
*/
|
||||
bool assign(pvar v, rational const& value, dependency dep);
|
||||
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace polysat {
|
|||
|
||||
// walk the e-graph to retrieve fixed sub-slices along with justifications,
|
||||
// as well as pvars that correspond to these sub-slices.
|
||||
void solver::get_fixed_sub_slices(pvar pv, fixed_slice_extra_vector& fixed, offset_slice_extra_vector& subslices) {
|
||||
void solver::get_fixed_sub_slices(pvar pv, fixed_slice_extra_vector& fixed, offset_slice_extra_vector& pvars) {
|
||||
#define GET_FIXED_SUB_SLICES_DISPLAY 1
|
||||
auto consume_slice = [&](euf::enode* n, unsigned offset) -> bool {
|
||||
euf::enode* r = n->get_root();
|
||||
|
@ -141,7 +141,8 @@ namespace polysat {
|
|||
unsigned level = merge_level(n, r);
|
||||
|
||||
euf::theory_var u = n->get_th_var(get_id());
|
||||
dependency dep = (u == euf::null_theory_var) ? dependency::axiom() : dependency(u, w); // TODO: probably need an enode_pair instead?
|
||||
// dependency dep = (u == euf::null_theory_var || u == w) ? dependency::axiom() : dependency(u, w); // TODO: probably need an enode_pair instead?
|
||||
dependency dep = dependency(n, r);
|
||||
|
||||
#if GET_FIXED_SUB_SLICES_DISPLAY
|
||||
verbose_stream() << " " << value << "[" << length << "]@" << offset;
|
||||
|
@ -168,9 +169,13 @@ namespace polysat {
|
|||
verbose_stream() << " node " << ctx.bpp(sib);
|
||||
verbose_stream() << " tv " << s;
|
||||
verbose_stream() << " merge-level " << p_level;
|
||||
verbose_stream() << " assigned? " << m_core.get_assignment().contains(p.var());
|
||||
if (m_core.get_assignment().contains(p.var()))
|
||||
verbose_stream() << " value " << m_core.get_assignment().value(p.var());
|
||||
verbose_stream() << "\n";
|
||||
#endif
|
||||
subslices.push_back(offset_slice_extra(p.var(), offset, p_level));
|
||||
dependency d = dependency(r, sib);
|
||||
pvars.push_back(offset_slice_extra(p.var(), offset, p_level, d, value));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -154,6 +154,11 @@ namespace polysat {
|
|||
auto const& offs = d.offset();
|
||||
explain_slice(offs.child, offs.parent, offs.offset, consume);
|
||||
}
|
||||
else if (d.is_enode_eq()) {
|
||||
auto const [n1, n2] = d.enode_eq();
|
||||
VERIFY(n1->get_root() == n2->get_root());
|
||||
eqs.push_back(euf::enode_pair(n1, n2));
|
||||
}
|
||||
else {
|
||||
auto const [v1, v2] = d.eq();
|
||||
euf::enode* const n1 = var2enode(v1);
|
||||
|
@ -169,7 +174,6 @@ namespace polysat {
|
|||
for (auto d : deps)
|
||||
explain_dep(d, eqs, core);
|
||||
|
||||
|
||||
IF_VERBOSE(10,
|
||||
verbose_stream() << "explain\n";
|
||||
for (auto lit : core)
|
||||
|
@ -270,7 +274,7 @@ namespace polysat {
|
|||
}
|
||||
|
||||
void solver::propagate_eq(pvar pv, rational const& val, dependency const& d) {
|
||||
auto v = m_pddvar2var[pv];
|
||||
theory_var v = m_pddvar2var[pv];
|
||||
auto a = var2enode(v);
|
||||
auto bval = bv.mk_numeral(val, get_bv_size(v));
|
||||
ctx.internalize(bval);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue