3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-02 02:48:47 +00:00
This commit is contained in:
Nikolaj Bjorner 2021-12-11 08:41:04 -08:00
parent 9c3489ba4b
commit 83efb1413a
10 changed files with 99 additions and 57 deletions

View file

@ -308,9 +308,8 @@ namespace polysat {
for (auto const& c : s.m_viable.get_constraints(v)) for (auto const& c : s.m_viable.get_constraints(v))
insert(c); insert(c);
for (auto* engine : ex_engines) if (try_explain(v))
if (engine->try_explain(v, *this)) return true;
return true;
// No value resolution method was successful => fall back to saturation and variable elimination // No value resolution method was successful => fall back to saturation and variable elimination
while (s.inc()) { while (s.inc()) {
@ -345,6 +344,13 @@ namespace polysat {
return false; return false;
} }
bool conflict::try_explain(pvar v) {
for (auto* engine : ex_engines)
if (engine->try_explain(v, *this))
return true;
return false;
}
void conflict::set_mark(signed_constraint c) { void conflict::set_mark(signed_constraint c) {
if (c->is_marked()) if (c->is_marked())
return; return;

View file

@ -110,6 +110,7 @@ namespace polysat {
bool try_eliminate(pvar v); bool try_eliminate(pvar v);
bool try_saturate(pvar v); bool try_saturate(pvar v);
bool try_explain(pvar v);
using const_iterator = conflict_iterator; using const_iterator = conflict_iterator;
const_iterator begin() const; const_iterator begin() const;

View file

@ -202,6 +202,21 @@ namespace polysat {
return ~ule(b, a); return ~ule(b, a);
} }
bool signed_constraint::is_eq() const {
if (is_positive())
return m_constraint->is_eq();
else
return m_constraint->is_diseq();
}
pdd const& signed_constraint::eq() const {
SASSERT(is_eq());
if (is_positive())
return m_constraint->to_ule().lhs();
else
return m_constraint->to_ule().rhs();
}
/** /**
* encode that the i'th bit of p is 1. * encode that the i'th bit of p is 1.
* It holds if p << (K - i - 1) >= 2^{K-1}, where K is the bit-width. * It holds if p << (K - i - 1) >= 2^{K-1}, where K is the bit-width.

View file

@ -159,6 +159,7 @@ namespace polysat {
bool operator!=(constraint const& other) const { return !operator==(other); } bool operator!=(constraint const& other) const { return !operator==(other); }
virtual bool is_eq() const { return false; } virtual bool is_eq() const { return false; }
virtual bool is_diseq() const { return false; }
bool is_ule() const { return m_kind == ckind_t::ule_t; } bool is_ule() const { return m_kind == ckind_t::ule_t; }
bool is_mul_ovfl() const { return m_kind == ckind_t::mul_ovfl_t; } bool is_mul_ovfl() const { return m_kind == ckind_t::mul_ovfl_t; }
ckind_t kind() const { return m_kind; } ckind_t kind() const { return m_kind; }
@ -253,6 +254,9 @@ namespace polysat {
constraint& operator*() { return *m_constraint; } constraint& operator*() { return *m_constraint; }
constraint const& operator*() const { return *m_constraint; } constraint const& operator*() const { return *m_constraint; }
bool is_eq() const;
pdd const& eq() const;
signed_constraint& operator=(std::nullptr_t) { m_constraint = nullptr; return *this; } signed_constraint& operator=(std::nullptr_t) { m_constraint = nullptr; return *this; }

View file

@ -24,8 +24,8 @@ namespace polysat {
LOG_H3("Resolving upon v" << v); LOG_H3("Resolving upon v" << v);
LOG("c1: " << c1); LOG("c1: " << c1);
LOG("c2: " << c2); LOG("c2: " << c2);
pdd a = c1->to_ule().p(); pdd a = c1.eq();
pdd b = c2->to_ule().p(); pdd b = c2.eq();
pdd r = a; pdd r = a;
if (!a.resolve(v, b, r) && !b.resolve(v, a, r)) if (!a.resolve(v, b, r) && !b.resolve(v, a, r))
return {}; return {};
@ -40,30 +40,19 @@ namespace polysat {
return c; return c;
} }
bool ex_polynomial_superposition::is_positive_equality_over(pvar v, signed_constraint const& c) {
return c.is_positive() && c->is_eq() && c->contains_var(v);
}
// c2 ... constraint that is currently false // c2 ... constraint that is currently false
// Try to replace it with a new false constraint (derived from superposition with a true constraint) // Try to replace it with a new false constraint (derived from superposition with a true constraint)
lbool ex_polynomial_superposition::find_replacement(signed_constraint c2, pvar v, conflict& core) { lbool ex_polynomial_superposition::find_replacement(signed_constraint c2, pvar v, conflict& core) {
vector<signed_constraint> premises; vector<signed_constraint> premises;
// TBD: replacement can be obtained from stack not just core.
// see test_l5. Exposes unsoundness bug: a new consequence is derived
// after some variable decision was already processed. Then the
// behavior of evaluating literals "is_currently_true" and bvalue
// uses the full search stack
#if 1
for (auto si : s.m_search) { for (auto si : s.m_search) {
if (!si.is_boolean()) if (!si.is_boolean())
continue; continue;
auto c1 = s.lit2cnstr(si.lit()); auto c1 = s.lit2cnstr(si.lit());
if (!c1->contains_var(v))
#else continue;
for (auto c1 : core) { if (!c1.is_eq())
#endif
if (!is_positive_equality_over(v, c1))
continue; continue;
if (!c1.is_currently_true(s)) if (!c1.is_currently_true(s))
continue; continue;
@ -107,7 +96,9 @@ namespace polysat {
// TODO: can try multiple replacements at once; then the c2 loop needs to be done only once... (requires some reorganization for storing the premises) // TODO: can try multiple replacements at once; then the c2 loop needs to be done only once... (requires some reorganization for storing the premises)
lbool ex_polynomial_superposition::try_explain1(pvar v, conflict& core) { lbool ex_polynomial_superposition::try_explain1(pvar v, conflict& core) {
for (auto c2 : core) { for (auto c2 : core) {
if (!is_positive_equality_over(v, c2)) if (!c2->contains_var(v))
continue;
if (!c2.is_eq())
continue; continue;
if (!c2.is_currently_false(s)) if (!c2.is_currently_false(s))
continue; continue;
@ -124,52 +115,68 @@ namespace polysat {
} }
void ex_polynomial_superposition::reduce_by(pvar v, conflict& core) { void ex_polynomial_superposition::reduce_by(pvar v, conflict& core) {
//return;
bool progress = true; bool progress = true;
while (progress) { while (progress) {
progress = false; progress = false;
for (auto c : core) { for (auto c : core) {
if (is_positive_equality_over(v, c) && c.is_currently_true(s) && reduce_by(v, c, core)) { if (!c->contains_var(v))
progress = true; continue;
break; if (!c.is_eq())
} continue;
#if 0
if (!c.is_currently_true(s))
continue;
#endif
if (!reduce_by(v, c, core))
continue;
progress = true;
break;
} }
} }
} }
bool ex_polynomial_superposition::reduce_by(pvar v, signed_constraint eq, conflict& core) { bool ex_polynomial_superposition::reduce_by(pvar v, signed_constraint eq, conflict& core) {
pdd p = eq->to_ule().p(); pdd p = eq.eq();
LOG("using v" << v << " " << eq);
for (auto c : core) { for (auto c : core) {
if (c == eq) if (c == eq)
continue; continue;
if (is_positive_equality_over(v, c)) if (!c->contains_var(v))
continue; continue;
if (c.is_eq())
continue;
LOG("try-reduce: " << c << " " << c.is_currently_false(s));
#if 0
if (!c.is_currently_false(s)) if (!c.is_currently_false(s))
continue; continue;
if (c->is_ule()) { #endif
auto lhs = c->to_ule().lhs(); if (!c->is_ule())
auto rhs = c->to_ule().rhs(); continue;
auto a = lhs.reduce(v, p); auto lhs = c->to_ule().lhs();
auto b = rhs.reduce(v, p); auto rhs = c->to_ule().rhs();
if (a == lhs && b == rhs) auto a = lhs.reduce(v, p);
continue; auto b = rhs.reduce(v, p);
auto c2 = s.ule(a, b); if (a == lhs && b == rhs)
if (!c.is_positive()) continue;
c2 = ~c2; auto c2 = s.ule(a, b);
SASSERT(c2.is_currently_false(s)); if (!c.is_positive())
if (!c2->has_bvar() || l_undef == c2.bvalue(s)) c2 = ~c2;
core.keep(c2); // adds propagation of c to the search stack if (!c2.is_currently_false(s))
core.reset(); continue;
LOG_H3("Polynomial superposition " << eq << " " << c << " reduced to " << c2); SASSERT(c2.is_currently_false(s));
if (c2.bvalue(s) == l_false) { if (!c2->has_bvar() || l_undef == c2.bvalue(s))
core.insert(eq); core.keep(c2); // adds propagation of c to the search stack
core.insert(c); core.reset();
core.insert(~c2); LOG_H3("Polynomial superposition " << eq << " " << c << " reduced to " << c2);
return false; if (c2.bvalue(s) == l_false) {
} core.insert(eq);
core.set(c2); core.insert(c);
return true; core.insert(~c2);
return false;
} }
core.set(c2);
return true;
} }
return false; return false;
} }

View file

@ -33,7 +33,6 @@ namespace polysat {
class ex_polynomial_superposition : public explainer { class ex_polynomial_superposition : public explainer {
private: private:
bool is_positive_equality_over(pvar v, signed_constraint const& c);
signed_constraint resolve1(pvar v, signed_constraint c1, signed_constraint c2); signed_constraint resolve1(pvar v, signed_constraint c1, signed_constraint c2);
lbool find_replacement(signed_constraint c2, pvar v, conflict& core); lbool find_replacement(signed_constraint c2, pvar v, conflict& core);
void reduce_by(pvar v, conflict& core); void reduce_by(pvar v, conflict& core);

View file

@ -134,6 +134,8 @@ namespace polysat {
//std::cout << "Already true " << conseq.is_currently_true(s) << "\n"; //std::cout << "Already true " << conseq.is_currently_true(s) << "\n";
SASSERT(premise.is_currently_true(s)); SASSERT(premise.is_currently_true(s));
SASSERT(bound * p.val() > max);
SASSERT((bound - 1) * p.val() <= max);
clause_builder cb(s); clause_builder cb(s);
cb.push_new(~sc); cb.push_new(~sc);
cb.push_new(~premise); cb.push_new(~premise);

View file

@ -462,9 +462,15 @@ namespace polysat {
// This case corresponds to a propagation of conflict_var, except it's not explicitly on the stack. // This case corresponds to a propagation of conflict_var, except it's not explicitly on the stack.
VERIFY(m_viable.resolve(v, m_conflict)); VERIFY(m_viable.resolve(v, m_conflict));
// TBD: saturate resulting conflict to get better lemmas. // TBD: saturate resulting conflict to get better lemmas.
LOG("try-saturate"); LOG("try-eliminate v" << v);
m_conflict.try_saturate(v); if (m_conflict.try_explain(v))
LOG("end-try-saturate"); ;
else if (m_conflict.try_eliminate(v))
;
else
m_conflict.try_saturate(v);
LOG("end-try-eliminate v");
} }
search_iterator search_it(m_search); search_iterator search_it(m_search);

View file

@ -41,7 +41,8 @@ namespace polysat {
unsigned hash() const override; unsigned hash() const override;
bool operator==(constraint const& other) const override; bool operator==(constraint const& other) const override;
bool is_eq() const override { return m_rhs.is_zero(); } bool is_eq() const override { return m_rhs.is_zero(); }
pdd const& p() const { SASSERT(is_eq()); return m_lhs; } bool is_diseq() const override { return m_lhs.is_one(); }
// pdd const& p() const { SASSERT(is_eq()); return m_lhs; }
}; };
} }

View file

@ -170,6 +170,7 @@ namespace polysat {
* and division with coeff are valid. Is there a more relaxed scheme? * and division with coeff are valid. Is there a more relaxed scheme?
*/ */
bool viable::refine_viable(pvar v, rational const& val) { bool viable::refine_viable(pvar v, rational const& val) {
//return true;
auto* e = m_non_units[v]; auto* e = m_non_units[v];
if (!e) if (!e)
return true; return true;
@ -408,7 +409,7 @@ namespace polysat {
} }
while (e != first); while (e != first);
core.set_bailout(); // core.set_bailout();
for (auto c : core) { for (auto c : core) {
if (c.bvalue(s) == l_false) { if (c.bvalue(s) == l_false) {
core.reset(); core.reset();