mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +00:00
levels take 1
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
2b6ae0070f
commit
516ca06c28
13 changed files with 99 additions and 190 deletions
|
@ -19,7 +19,7 @@ namespace polysat {
|
|||
|
||||
clause_ref clause::from_unit(signed_constraint c, p_dependency_ref d) {
|
||||
SASSERT(c->has_bvar());
|
||||
unsigned const lvl = c->level();
|
||||
unsigned const lvl = 0; // level from literal?
|
||||
sat::literal_vector lits;
|
||||
lits.push_back(c.blit());
|
||||
return clause::from_literals(lvl, std::move(d), std::move(lits));
|
||||
|
|
|
@ -54,8 +54,7 @@ namespace polysat {
|
|||
if (c->unit_clause()) {
|
||||
add_dependency(c->unit_dep());
|
||||
return;
|
||||
}
|
||||
m_level = std::max(m_level, c->level());
|
||||
}
|
||||
m_literals.push_back(c.blit());
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ namespace polysat {
|
|||
LOG_V("Adding: " << item);
|
||||
if (item.is_assignment()) {
|
||||
pvar v = item.var();
|
||||
auto c = ~cm().eq(0, m_solver->var(v) - m_solver->m_value[v]);
|
||||
auto c = ~cm().eq(m_solver->var(v) - m_solver->m_value[v]);
|
||||
cm().ensure_bvar(c.get());
|
||||
lemma.push(c.blit());
|
||||
} else {
|
||||
|
@ -226,7 +226,7 @@ namespace polysat {
|
|||
continue;
|
||||
if (m_solver->m_justification[v].level() > model_level)
|
||||
continue;
|
||||
auto diseq = ~cm().eq(lemma.level(), m_solver->var(v) - m_solver->m_value[v]);
|
||||
auto diseq = ~cm().eq(m_solver->var(v) - m_solver->m_value[v]);
|
||||
cm().ensure_bvar(diseq.get());
|
||||
lemma.push(diseq);
|
||||
}
|
||||
|
|
|
@ -53,32 +53,9 @@ namespace polysat {
|
|||
/** Add constraint to per-level storage */
|
||||
void constraint_manager::store(constraint* c) {
|
||||
LOG_V("Store constraint: " << show_deref(c));
|
||||
while (m_constraints.size() <= c->level())
|
||||
m_constraints.push_back({});
|
||||
m_constraints[c->level()].push_back(c);
|
||||
m_constraints.push_back(c);
|
||||
}
|
||||
|
||||
/** Remove the given constraint from the per-level storage (without deallocating it) */
|
||||
void constraint_manager::erase(constraint* c) {
|
||||
LOG_V("Erase constraint: " << show_deref(c));
|
||||
auto& vec = m_constraints[c->level()];
|
||||
for (unsigned i = vec.size(); i-- > 0; )
|
||||
if (vec[i] == c) {
|
||||
vec.swap(i, vec.size() - 1);
|
||||
constraint* c0 = vec.detach_back();
|
||||
SASSERT(c0 == c);
|
||||
vec.pop_back();
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
/** Change level of the given constraint, adjusting its storage position */
|
||||
void constraint_manager::set_level(constraint* c, unsigned new_lvl) {
|
||||
erase(c);
|
||||
c->m_level = new_lvl;
|
||||
store(c);
|
||||
}
|
||||
|
||||
clause* constraint_manager::store(clause_ref cl_ref) {
|
||||
clause* cl = cl_ref.get();
|
||||
|
@ -99,20 +76,6 @@ namespace polysat {
|
|||
|
||||
// Release constraints at the given level and above.
|
||||
void constraint_manager::release_level(unsigned lvl) {
|
||||
for (unsigned l = m_constraints.size(); l-- > lvl; ) {
|
||||
for (auto* c : m_constraints[l]) {
|
||||
LOG_V("Destroying constraint: " << show_deref(c));
|
||||
auto* d = c->unit_dep();
|
||||
if (d && d->is_leaf()) {
|
||||
unsigned const dep = d->leaf_value();
|
||||
SASSERT(m_external_constraints.contains(dep));
|
||||
m_external_constraints.remove(dep);
|
||||
}
|
||||
m_constraint_table.erase(c);
|
||||
erase_bvar(c);
|
||||
}
|
||||
m_constraints[l].reset();
|
||||
}
|
||||
for (unsigned l = m_clauses.size(); l-- > lvl; ) {
|
||||
for (auto const& cl : m_clauses[l]) {
|
||||
SASSERT_EQ(cl->m_ref_count, 1); // otherwise there is a leftover reference somewhere
|
||||
|
@ -137,37 +100,20 @@ namespace polysat {
|
|||
|
||||
/** Look up constraint among stored constraints. */
|
||||
constraint* constraint_manager::dedup(constraint* c1) {
|
||||
auto it = m_constraint_table.find(c1);
|
||||
if (it == m_constraint_table.end()) {
|
||||
store(c1);
|
||||
constraint* c2 = nullptr;
|
||||
if (m_constraint_table.find(c1, c2)) {
|
||||
dealloc(c1);
|
||||
return c2;
|
||||
}
|
||||
else {
|
||||
m_constraint_table.insert(c1);
|
||||
return c1;
|
||||
}
|
||||
constraint* c0 = *it;
|
||||
if (c1->level() < c0->level())
|
||||
set_level(c0, c1->level());
|
||||
dealloc(c1);
|
||||
return c0;
|
||||
}
|
||||
|
||||
void constraint_manager::gc() {
|
||||
for (auto& vec : m_constraints)
|
||||
for (int i = vec.size(); i-- > 0; ) {
|
||||
constraint* c = vec[i];
|
||||
if (!c->has_bvar()) {
|
||||
LOG_V("Destroying constraint: " << show_deref(c));
|
||||
m_constraint_table.erase(c);
|
||||
vec.swap(i, vec.size() - 1);
|
||||
vec.pop_back();
|
||||
}
|
||||
}
|
||||
DEBUG_CODE({
|
||||
for (auto const& vec : m_constraints)
|
||||
for (auto* c : vec) {
|
||||
SASSERT(c->has_bvar());
|
||||
SASSERT(m_constraint_table.contains(c));
|
||||
}
|
||||
});
|
||||
// collect used literals from lemmas and stack
|
||||
// walk constraints to remove unused.
|
||||
}
|
||||
|
||||
bool constraint_manager::should_gc() {
|
||||
|
@ -176,17 +122,17 @@ namespace polysat {
|
|||
return true;
|
||||
}
|
||||
|
||||
signed_constraint constraint_manager::eq(unsigned lvl, pdd const& p) {
|
||||
return {dedup(alloc(eq_constraint, *this, lvl, p)), true};
|
||||
signed_constraint constraint_manager::eq(pdd const& p) {
|
||||
return {dedup(alloc(eq_constraint, *this, p)), true};
|
||||
}
|
||||
|
||||
signed_constraint constraint_manager::ule(unsigned lvl, pdd const& a, pdd const& b) {
|
||||
return {dedup(alloc(ule_constraint, *this, lvl, a, b)), true};
|
||||
signed_constraint constraint_manager::ule(pdd const& a, pdd const& b) {
|
||||
return {dedup(alloc(ule_constraint, *this, a, b)), true};
|
||||
}
|
||||
|
||||
signed_constraint constraint_manager::ult(unsigned lvl, pdd const& a, pdd const& b) {
|
||||
signed_constraint constraint_manager::ult(pdd const& a, pdd const& b) {
|
||||
// a < b <=> !(b <= a)
|
||||
return ~ule(lvl, b, a);
|
||||
return ~ule(b, a);
|
||||
}
|
||||
|
||||
// To do signed comparison of bitvectors, flip the msb and do unsigned comparison:
|
||||
|
@ -205,14 +151,14 @@ namespace polysat {
|
|||
//
|
||||
// Argument: flipping the msb swaps the negative and non-negative blocks
|
||||
//
|
||||
signed_constraint constraint_manager::sle(unsigned lvl, pdd const& a, pdd const& b) {
|
||||
signed_constraint constraint_manager::sle(pdd const& a, pdd const& b) {
|
||||
auto shift = rational::power_of_two(a.power_of_2() - 1);
|
||||
return ule(lvl, a + shift, b + shift);
|
||||
return ule(a + shift, b + shift);
|
||||
}
|
||||
|
||||
signed_constraint constraint_manager::slt(unsigned lvl, pdd const& a, pdd const& b) {
|
||||
signed_constraint constraint_manager::slt(pdd const& a, pdd const& b) {
|
||||
auto shift = rational::power_of_two(a.power_of_2() - 1);
|
||||
return ult(lvl, a + shift, b + shift);
|
||||
return ult(a + shift, b + shift);
|
||||
}
|
||||
|
||||
signed_constraint inequality::as_signed_constraint() const {
|
||||
|
@ -236,7 +182,7 @@ namespace polysat {
|
|||
}
|
||||
|
||||
std::ostream& constraint::display_extra(std::ostream& out, lbool status) const {
|
||||
out << " @" << level() << " (b";
|
||||
out << " (b";
|
||||
if (has_bvar()) { out << bvar(); } else { out << "_"; }
|
||||
out << ")";
|
||||
(void)status;
|
||||
|
|
|
@ -40,10 +40,9 @@ namespace polysat {
|
|||
ptr_vector<constraint> m_bv2constraint;
|
||||
// Constraints that have a boolean variable, for deduplication
|
||||
constraint_table m_constraint_table;
|
||||
scoped_ptr_vector<constraint> m_constraints;
|
||||
|
||||
// Constraint storage per level
|
||||
|
||||
vector<scoped_ptr_vector<constraint>> m_constraints;
|
||||
// Clause storage per level
|
||||
vector<vector<clause_ref>> m_clauses;
|
||||
|
||||
// Association to external dependency values (i.e., external names for constraints)
|
||||
|
@ -56,7 +55,6 @@ namespace polysat {
|
|||
|
||||
void store(constraint* c);
|
||||
void erase(constraint* c);
|
||||
void set_level(constraint* c, unsigned new_lvl);
|
||||
|
||||
constraint* dedup(constraint* c);
|
||||
|
||||
|
@ -84,11 +82,14 @@ namespace polysat {
|
|||
signed_constraint lookup(sat::literal lit) const;
|
||||
constraint* lookup_external(unsigned dep) const { return m_external_constraints.get(dep, nullptr); }
|
||||
|
||||
signed_constraint eq(unsigned lvl, pdd const& p);
|
||||
signed_constraint ule(unsigned lvl, pdd const& a, pdd const& b);
|
||||
signed_constraint ult(unsigned lvl, pdd const& a, pdd const& b);
|
||||
signed_constraint sle(unsigned lvl, pdd const& a, pdd const& b);
|
||||
signed_constraint slt(unsigned lvl, pdd const& a, pdd const& b);
|
||||
signed_constraint eq(pdd const& p);
|
||||
signed_constraint ule(pdd const& a, pdd const& b);
|
||||
signed_constraint ult(pdd const& a, pdd const& b);
|
||||
signed_constraint sle(pdd const& a, pdd const& b);
|
||||
signed_constraint slt(pdd const& a, pdd const& b);
|
||||
|
||||
constraint *const* begin() const { return m_constraints.data(); }
|
||||
constraint *const* end() const { return m_constraints.data() + m_constraints.size(); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -114,7 +115,6 @@ namespace polysat {
|
|||
|
||||
// constraint_manager* m_manager;
|
||||
clause* m_unit_clause = nullptr; ///< If this constraint was asserted by a unit clause, we store that clause here.
|
||||
unsigned m_level; ///< Controls lifetime of the constraint object. Always a base level.
|
||||
ckind_t m_kind;
|
||||
unsigned_vector m_vars;
|
||||
/** The boolean variable associated to this constraint, if any.
|
||||
|
@ -126,8 +126,8 @@ namespace polysat {
|
|||
// TODO: replace parameter 'is_positive' everywhere by 'sign'? (also in signed_constraint)
|
||||
sat::bool_var m_bvar = sat::null_bool_var;
|
||||
|
||||
constraint(constraint_manager& m, unsigned lvl, ckind_t k):
|
||||
/*m_manager(&m),*/ m_level(lvl), m_kind(k) {}
|
||||
constraint(constraint_manager& m, ckind_t k):
|
||||
/*m_manager(&m),*/ m_kind(k) {}
|
||||
|
||||
protected:
|
||||
std::ostream& display_extra(std::ostream& out, lbool status) const;
|
||||
|
@ -160,16 +160,12 @@ namespace polysat {
|
|||
unsigned_vector const& vars() const { return m_vars; }
|
||||
unsigned var(unsigned idx) const { return m_vars[idx]; }
|
||||
bool contains_var(pvar v) const { return m_vars.contains(v); }
|
||||
unsigned level() const { return m_level; }
|
||||
bool has_bvar() const { return m_bvar != sat::null_bool_var; }
|
||||
sat::bool_var bvar() const { return m_bvar; }
|
||||
|
||||
clause* unit_clause() const { return m_unit_clause; }
|
||||
void set_unit_clause(clause* cl);
|
||||
p_dependency* unit_dep() const { return m_unit_clause ? m_unit_clause->dep() : nullptr; }
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, constraint const& c) { return c.display(out); }
|
||||
|
@ -209,7 +205,6 @@ namespace polysat {
|
|||
|
||||
sat::bool_var bvar() const { return m_constraint->bvar(); }
|
||||
sat::literal blit() const { return sat::literal(bvar(), is_negative()); }
|
||||
unsigned level() const { return m_constraint->level(); }
|
||||
constraint* get() const { return m_constraint; }
|
||||
|
||||
explicit operator bool() const { return !!m_constraint; }
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace polysat {
|
|||
|
||||
pdd m_poly;
|
||||
|
||||
eq_constraint(constraint_manager& m, unsigned lvl, pdd const& p):
|
||||
constraint(m, lvl, ckind_t::eq_t), m_poly(p) {
|
||||
eq_constraint(constraint_manager& m, pdd const& p):
|
||||
constraint(m, ckind_t::eq_t), m_poly(p) {
|
||||
m_vars.append(p.free_vars());
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,7 @@ namespace polysat {
|
|||
// (this condition might be too strict, but we use it for now to prevent looping)
|
||||
if (b.degree(v) <= r.degree(v))
|
||||
return {};
|
||||
unsigned const lvl = std::max(c1->level(), c2->level());
|
||||
signed_constraint c = cm().eq(lvl, r);
|
||||
signed_constraint c = cm().eq(r);
|
||||
LOG("resolved: " << c << " currently false? " << c.is_currently_false(s()));
|
||||
if (!c.is_currently_false(s()))
|
||||
return {};
|
||||
|
|
|
@ -131,11 +131,8 @@ namespace polysat {
|
|||
LOG("seq: " << seq);
|
||||
SASSERT(seq.size() >= 2); // otherwise has_full should have been true
|
||||
|
||||
// TODO lemma level depends on clauses used to derive it, not on levels of constraints
|
||||
unsigned lemma_lvl = 0;
|
||||
for (unsigned i : seq) {
|
||||
signed_constraint const& c = records[i].src;
|
||||
lemma_lvl = std::max(lemma_lvl, c->level());
|
||||
}
|
||||
|
||||
// Update the conflict state
|
||||
// Idea:
|
||||
|
@ -159,7 +156,7 @@ namespace polysat {
|
|||
// NB: do we really have to pass in the level to this new literal?
|
||||
// seems separating the level from the constraint is what we want
|
||||
// the level of a literal is when it was assigned. Lemmas could have unassigned literals.
|
||||
signed_constraint c = s.m_constraints.ult(lemma_lvl, lhs, rhs);
|
||||
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
||||
LOG("constraint: " << c);
|
||||
lemma.push(~c);
|
||||
// Side conditions
|
||||
|
@ -315,9 +312,9 @@ namespace polysat {
|
|||
out_neg_cond = nullptr;
|
||||
}
|
||||
else if (is_trivial)
|
||||
out_neg_cond = ~s.m_constraints.eq(0, condition_body);
|
||||
out_neg_cond = ~s.m_constraints.eq(condition_body);
|
||||
else
|
||||
out_neg_cond = s.m_constraints.eq(0, condition_body);
|
||||
out_neg_cond = s.m_constraints.eq(condition_body);
|
||||
|
||||
if (is_trivial) {
|
||||
if (!ineq.is_strict)
|
||||
|
|
|
@ -25,9 +25,8 @@ TODO: when we check that 'x' is "unary":
|
|||
(extension to arbitrary monomials for 'x' should be fairly easy too)
|
||||
|
||||
TODO:
|
||||
- resolve away the "problematic" premise (non-linear inequality etc) that is reduced by a saturation rule.
|
||||
- it would work by adding the explanations for the resolved premises to the reason clause
|
||||
- and removing the literal from the core
|
||||
- remove the "problematic" literal from the core itself such that reference counts on variable assignments are decreased.
|
||||
|
||||
--*/
|
||||
#include "math/polysat/saturation.h"
|
||||
#include "math/polysat/solver.h"
|
||||
|
@ -52,11 +51,11 @@ namespace polysat {
|
|||
return false;
|
||||
}
|
||||
|
||||
signed_constraint inf_saturate::ineq(unsigned lvl, bool is_strict, pdd const& lhs, pdd const& rhs) {
|
||||
signed_constraint inf_saturate::ineq(bool is_strict, pdd const& lhs, pdd const& rhs) {
|
||||
if (is_strict)
|
||||
return cm().ult(lvl, lhs, rhs);
|
||||
return cm().ult(lhs, rhs);
|
||||
else
|
||||
return cm().ule(lvl, lhs, rhs);
|
||||
return cm().ule(lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,13 +71,13 @@ namespace polysat {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool inf_saturate::propagate(conflict_core& core, unsigned lvl, bool is_strict, pdd const& lhs, pdd const& rhs, clause_builder& reason) {
|
||||
signed_constraint c = ineq(lvl, is_strict, lhs, rhs);
|
||||
bool inf_saturate::propagate(conflict_core& core, bool is_strict, pdd const& lhs, pdd const& rhs, clause_builder& reason) {
|
||||
signed_constraint c = ineq(is_strict, lhs, rhs);
|
||||
return propagate(core, c, reason);
|
||||
}
|
||||
|
||||
/// Add premises for Ω*(x, y)
|
||||
void inf_saturate::push_omega_bisect(clause_builder& reason, unsigned level, pdd const& x, rational x_max, pdd const& y, rational y_max) {
|
||||
void inf_saturate::push_omega_bisect(clause_builder& reason, pdd const& x, rational x_max, pdd const& y, rational y_max) {
|
||||
rational x_val, y_val;
|
||||
auto& pddm = x.manager();
|
||||
unsigned bit_size = pddm.power_of_2();
|
||||
|
@ -128,15 +127,15 @@ namespace polysat {
|
|||
// conflict resolution should be able to pick up this as a valid justification.
|
||||
// or we resort to the same extension as in the original mul_overflow code
|
||||
// where we add explicit equality propagations from the current assignment.
|
||||
auto c1 = cm().ule(level, x, pddm.mk_val(x_lo));
|
||||
auto c2 = cm().ule(level, y, pddm.mk_val(y_lo));
|
||||
auto c1 = cm().ule(x, pddm.mk_val(x_lo));
|
||||
auto c2 = cm().ule(y, pddm.mk_val(y_lo));
|
||||
reason.push(~c1);
|
||||
reason.push(~c2);
|
||||
}
|
||||
|
||||
// determine worst case upper bounds for x, y
|
||||
// then extract premises for a non-worst-case bound.
|
||||
void inf_saturate::push_omega(clause_builder& reason, unsigned level, pdd const& x, pdd const& y) {
|
||||
void inf_saturate::push_omega(clause_builder& reason, pdd const& x, pdd const& y) {
|
||||
auto& pddm = x.manager();
|
||||
unsigned bit_size = pddm.power_of_2();
|
||||
rational bound = rational::power_of_two(bit_size);
|
||||
|
@ -149,7 +148,7 @@ namespace polysat {
|
|||
y_max = s().m_viable.max_viable(y.var());
|
||||
|
||||
if (x_max * y_max >= bound)
|
||||
push_omega_bisect(reason, level, x, x_max, y, y_max);
|
||||
push_omega_bisect(reason, x, x_max, y, y_max);
|
||||
else {
|
||||
for (auto c : s().m_cjust[y.var()])
|
||||
reason.push(~c);
|
||||
|
@ -263,13 +262,12 @@ namespace polysat {
|
|||
if (!c.is_strict && s().get_value(v).is_zero())
|
||||
return false;
|
||||
|
||||
unsigned const lvl = c.src->level();
|
||||
clause_builder reason(s());
|
||||
if (!c.is_strict)
|
||||
reason.push(cm().eq(lvl, x - x.manager().mk_val(rational(0))));
|
||||
reason.push(cm().eq(x - x.manager().mk_val(rational(0))));
|
||||
reason.push(~c.as_signed_constraint());
|
||||
push_omega(reason, lvl, x, y);
|
||||
return propagate(core, lvl, c.is_strict, y, z, reason);
|
||||
push_omega(reason, x, y);
|
||||
return propagate(core, c.is_strict, y, z, reason);
|
||||
}
|
||||
|
||||
/// [y] z' <= y /\ zx > yx ==> Ω*(x,y) \/ zx > z'x
|
||||
|
@ -282,15 +280,14 @@ namespace polysat {
|
|||
if (!is_non_overflow(x, y))
|
||||
return false;
|
||||
|
||||
unsigned const lvl = std::max(yx_l_zx.src->level(), le_y.src->level());
|
||||
pdd const& z_prime = le_y.lhs;
|
||||
|
||||
clause_builder reason(s());
|
||||
reason.push(~le_y.as_signed_constraint());
|
||||
reason.push(~yx_l_zx.as_signed_constraint());
|
||||
push_omega(reason, lvl, x, y);
|
||||
push_omega(reason, x, y);
|
||||
// z'x <= zx
|
||||
return propagate(core, lvl, yx_l_zx.is_strict || le_y.is_strict, z_prime * x, z * x, reason);
|
||||
return propagate(core, yx_l_zx.is_strict || le_y.is_strict, z_prime * x, z * x, reason);
|
||||
}
|
||||
|
||||
bool inf_saturate::try_ugt_y(pvar v, conflict_core& core, inequality const& c) {
|
||||
|
@ -329,12 +326,11 @@ namespace polysat {
|
|||
pdd z = x_l_z.rhs;
|
||||
if (!is_non_overflow(a, z))
|
||||
return false;
|
||||
unsigned const lvl = std::max(x_l_z.src->level(), y_l_ax.src->level());
|
||||
clause_builder reason(s());
|
||||
reason.push(~x_l_z.as_signed_constraint());
|
||||
reason.push(~y_l_ax.as_signed_constraint());
|
||||
push_omega(reason, lvl, a, z);
|
||||
return propagate(core, lvl, x_l_z.is_strict || y_l_ax.is_strict, y, a * z, reason);
|
||||
push_omega(reason, a, z);
|
||||
return propagate(core, x_l_z.is_strict || y_l_ax.is_strict, y, a * z, reason);
|
||||
}
|
||||
|
||||
|
||||
|
@ -356,16 +352,15 @@ namespace polysat {
|
|||
bool inf_saturate::try_ugt_z(pvar z, conflict_core& core, inequality const& c, inequality const& d, pdd const& x, pdd const& y) {
|
||||
SASSERT(is_g_v(z, c));
|
||||
SASSERT(verify_YX_l_zX(z, d, x, y));
|
||||
unsigned const lvl = std::max(c.src->level(), d.src->level());
|
||||
pdd const& y_prime = c.rhs;
|
||||
if (!is_non_overflow(x, y_prime))
|
||||
return false;
|
||||
clause_builder reason(s());
|
||||
reason.push(~c.as_signed_constraint());
|
||||
reason.push(~d.as_signed_constraint());
|
||||
push_omega(reason, lvl, x, y_prime);
|
||||
push_omega(reason, x, y_prime);
|
||||
// yx <= y'x
|
||||
return propagate(core, lvl, c.is_strict || d.is_strict, y * x, y_prime * x, reason);
|
||||
return propagate(core, c.is_strict || d.is_strict, y * x, y_prime * x, reason);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,11 +38,11 @@ namespace polysat {
|
|||
class inf_saturate : public inference_engine {
|
||||
bool find_upper_bound(pvar x, signed_constraint& c, rational& bound);
|
||||
|
||||
void push_omega(clause_builder& reason, unsigned level, pdd const& x, pdd const& y);
|
||||
void push_omega_bisect(clause_builder& reason, unsigned level, pdd const& x, rational x_max, pdd const& y, rational y_max);
|
||||
signed_constraint ineq(unsigned level, bool strict, pdd const& lhs, pdd const& rhs);
|
||||
void push_omega(clause_builder& reason, pdd const& x, pdd const& y);
|
||||
void push_omega_bisect(clause_builder& reason, pdd const& x, rational x_max, pdd const& y, rational y_max);
|
||||
signed_constraint ineq(bool strict, pdd const& lhs, pdd const& rhs);
|
||||
bool propagate(conflict_core& core, signed_constraint& c, clause_builder& reason);
|
||||
bool propagate(conflict_core& core, unsigned level, bool strict, pdd const& lhs, pdd const& rhs, clause_builder& reason);
|
||||
bool propagate(conflict_core& core, bool strict, pdd const& lhs, pdd const& rhs, clause_builder& reason);
|
||||
|
||||
bool try_ugt_x(pvar v, conflict_core& core, inequality const& c);
|
||||
|
||||
|
|
|
@ -117,27 +117,27 @@ namespace polysat {
|
|||
}
|
||||
|
||||
signed_constraint solver::mk_eq(pdd const& p) {
|
||||
return m_constraints.eq(m_level, p);
|
||||
return m_constraints.eq(p);
|
||||
}
|
||||
|
||||
signed_constraint solver::mk_diseq(pdd const& p) {
|
||||
return ~m_constraints.eq(m_level, p);
|
||||
return ~m_constraints.eq(p);
|
||||
}
|
||||
|
||||
signed_constraint solver::mk_ule(pdd const& p, pdd const& q) {
|
||||
return m_constraints.ule(m_level, p, q);
|
||||
return m_constraints.ule(p, q);
|
||||
}
|
||||
|
||||
signed_constraint solver::mk_ult(pdd const& p, pdd const& q) {
|
||||
return m_constraints.ult(m_level, p, q);
|
||||
return m_constraints.ult(p, q);
|
||||
}
|
||||
|
||||
signed_constraint solver::mk_sle(pdd const& p, pdd const& q) {
|
||||
return m_constraints.sle(m_level, p, q);
|
||||
return m_constraints.sle(p, q);
|
||||
}
|
||||
|
||||
signed_constraint solver::mk_slt(pdd const& p, pdd const& q) {
|
||||
return m_constraints.slt(m_level, p, q);
|
||||
return m_constraints.slt(p, q);
|
||||
}
|
||||
|
||||
void solver::new_constraint(signed_constraint c, unsigned dep, bool activate) {
|
||||
|
@ -150,7 +150,7 @@ namespace polysat {
|
|||
if (dep != null_dependency)
|
||||
m_constraints.register_external(c.get());
|
||||
LOG("New constraint: " << c);
|
||||
m_original.push_back(c);
|
||||
|
||||
#if ENABLE_LINEAR_SOLVER
|
||||
m_linear_solver.new_constraint(*c.get());
|
||||
#endif
|
||||
|
@ -308,8 +308,6 @@ namespace polysat {
|
|||
}
|
||||
m_trail.pop_back();
|
||||
}
|
||||
pop_constraints(m_original);
|
||||
pop_constraints(m_redundant);
|
||||
m_constraints.release_level(m_level + 1);
|
||||
SASSERT(m_level == target_level);
|
||||
for (unsigned j = replay.size(); j-- > 0; ) {
|
||||
|
@ -319,13 +317,6 @@ namespace polysat {
|
|||
}
|
||||
}
|
||||
|
||||
void solver::pop_constraints(signed_constraints& cs) {
|
||||
VERIFY(invariant(cs));
|
||||
while (!cs.empty() && cs.back()->level() > m_level) {
|
||||
deactivate_constraint(cs.back());
|
||||
cs.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void solver::add_watch(signed_constraint c) {
|
||||
SASSERT(c);
|
||||
|
@ -796,7 +787,6 @@ namespace polysat {
|
|||
if (cl->size() == 1) {
|
||||
signed_constraint c = m_constraints.lookup((*cl)[0]);
|
||||
c->set_unit_clause(cl);
|
||||
insert_constraint(m_redundant, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -804,13 +794,6 @@ namespace polysat {
|
|||
SASSERT(c);
|
||||
LOG_V("INSERTING: " << c);
|
||||
cs.push_back(c);
|
||||
for (unsigned i = cs.size() - 1; i-- > 0; ) {
|
||||
auto c1 = cs[i + 1];
|
||||
auto c2 = cs[i];
|
||||
if (c1->level() >= c2->level())
|
||||
break;
|
||||
std::swap(cs[i], cs[i+1]);
|
||||
}
|
||||
SASSERT(invariant(cs));
|
||||
}
|
||||
|
||||
|
@ -864,11 +847,8 @@ namespace polysat {
|
|||
// out << m_viable[v] << "\n";
|
||||
}
|
||||
out << "Boolean assignment:\n\t" << m_bvars << "\n";
|
||||
out << "Original:\n";
|
||||
for (auto c : m_original)
|
||||
out << "\t" << c << "\n";
|
||||
out << "Redundant:\n";
|
||||
for (auto c : m_redundant)
|
||||
out << "Constraints:\n";
|
||||
for (auto c : m_constraints)
|
||||
out << "\t" << c << "\n";
|
||||
out << "Redundant clauses:\n";
|
||||
for (auto* cl : m_redundant_clauses) {
|
||||
|
@ -906,18 +886,13 @@ namespace polysat {
|
|||
}
|
||||
|
||||
bool solver::invariant() {
|
||||
invariant(m_original);
|
||||
invariant(m_redundant);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* constraints are sorted by levels so they can be removed when levels are popped.
|
||||
* levels are gone
|
||||
*/
|
||||
bool solver::invariant(signed_constraints const& cs) {
|
||||
unsigned sz = cs.size();
|
||||
for (unsigned i = 0; i + 1 < sz; ++i)
|
||||
VERIFY(cs[i]->level() <= cs[i + 1]->level());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -925,21 +900,25 @@ namespace polysat {
|
|||
* Check that two variables of each constraint are watched.
|
||||
*/
|
||||
bool solver::wlist_invariant() {
|
||||
signed_constraints cs;
|
||||
cs.append(m_original.size(), m_original.data());
|
||||
cs.append(m_redundant.size(), m_redundant.data());
|
||||
// Skip boolean literals that aren't active yet
|
||||
// Skip boolean variables that aren't active yet
|
||||
uint_set skip;
|
||||
for (unsigned i = m_qhead; i < m_search.size(); ++i)
|
||||
if (m_search[i].is_boolean())
|
||||
skip.insert(m_search[i].lit().to_uint());
|
||||
for (auto c : cs) {
|
||||
SASSERT(c->has_bvar());
|
||||
if (skip.contains(c.blit().to_uint()))
|
||||
skip.insert(m_search[i].lit().var());
|
||||
for (auto c : m_constraints) {
|
||||
if (!c->has_bvar())
|
||||
continue;
|
||||
if (skip.contains(c->bvar()))
|
||||
continue;
|
||||
|
||||
lbool value = m_bvars.value(c->bvar());
|
||||
if (value == l_undef)
|
||||
continue;
|
||||
bool is_positive = value == l_true;
|
||||
int64_t num_watches = 0;
|
||||
signed_constraint sc(c, is_positive);
|
||||
for (auto const& wlist : m_watch) {
|
||||
auto n = std::count(wlist.begin(), wlist.end(), c);
|
||||
auto n = std::count(wlist.begin(), wlist.end(), sc);
|
||||
VERIFY(n <= 1); // no duplicates in the watchlist
|
||||
num_watches += n;
|
||||
}
|
||||
|
@ -968,10 +947,12 @@ namespace polysat {
|
|||
LOG_H1("Checking current model...");
|
||||
LOG("Assignment: " << assignments_pp(*this));
|
||||
bool all_ok = true;
|
||||
for (auto c : m_original) {
|
||||
bool ok = c.is_currently_true(*this);
|
||||
LOG((ok ? "PASS" : "FAIL") << ": " << c);
|
||||
all_ok = all_ok && ok;
|
||||
for (auto s : m_search) {
|
||||
if (s.is_boolean()) {
|
||||
bool ok = m_bvars.value(s.lit()) == l_true;
|
||||
LOG((ok ? "PASS" : "FAIL") << ": " << s.lit());
|
||||
all_ok = all_ok && ok;
|
||||
}
|
||||
}
|
||||
if (all_ok) LOG("All good!");
|
||||
return true;
|
||||
|
|
|
@ -89,8 +89,6 @@ namespace polysat {
|
|||
|
||||
// Per constraint state
|
||||
constraint_manager m_constraints;
|
||||
signed_constraints m_original;
|
||||
signed_constraints m_redundant;
|
||||
ptr_vector<clause> m_redundant_clauses;
|
||||
|
||||
svector<sat::bool_var> m_disjunctive_lemma;
|
||||
|
@ -154,7 +152,6 @@ namespace polysat {
|
|||
|
||||
void push_level();
|
||||
void pop_levels(unsigned num_levels);
|
||||
void pop_constraints(signed_constraints& cs);
|
||||
|
||||
void assign_bool(unsigned level, sat::literal lit, clause* reason, clause* lemma);
|
||||
void activate_constraint(signed_constraint c);
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace polysat {
|
|||
pdd m_lhs;
|
||||
pdd m_rhs;
|
||||
|
||||
ule_constraint(constraint_manager& m, unsigned lvl, pdd const& l, pdd const& r):
|
||||
constraint(m, lvl, ckind_t::ule_t), m_lhs(l), m_rhs(r) {
|
||||
ule_constraint(constraint_manager& m, pdd const& l, pdd const& r):
|
||||
constraint(m, ckind_t::ule_t), m_lhs(l), m_rhs(r) {
|
||||
m_vars.append(l.free_vars());
|
||||
for (auto v : r.free_vars())
|
||||
if (!m_vars.contains(v))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue