mirror of
https://github.com/Z3Prover/z3
synced 2025-05-12 02:04:43 +00:00
Add propagate/narrow for ule_constraint (#5214)
* Add helper to check whether pdd is univariate and linear * Reorganize propagate/narrow of eq_constraint * Implement propagate/narrow for ule constraints * Also push trail instruction in push_viable
This commit is contained in:
parent
12444c7e8b
commit
2fac9e6e66
6 changed files with 111 additions and 51 deletions
|
@ -14,6 +14,7 @@ Author:
|
|||
|
||||
#include "math/polysat/constraint.h"
|
||||
#include "math/polysat/solver.h"
|
||||
#include "math/polysat/log.h"
|
||||
|
||||
namespace polysat {
|
||||
|
||||
|
@ -22,6 +23,21 @@ namespace polysat {
|
|||
}
|
||||
|
||||
bool ule_constraint::propagate(solver& s, pvar v) {
|
||||
LOG_H3("Propagate " << s.m_vars[v] << " in " << *this);
|
||||
SASSERT(!vars().empty());
|
||||
unsigned idx = 0;
|
||||
if (vars()[idx] != v)
|
||||
idx = 1;
|
||||
SASSERT(v == vars()[idx]);
|
||||
// find other watch variable.
|
||||
for (unsigned i = vars().size(); i-- > 2; ) {
|
||||
if (!s.is_assigned(vars()[i])) {
|
||||
std::swap(vars()[idx], vars()[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
narrow(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -30,14 +46,77 @@ namespace polysat {
|
|||
}
|
||||
|
||||
void ule_constraint::narrow(solver& s) {
|
||||
LOG("Assignment: " << s.m_search);
|
||||
auto p = lhs().subst_val(s.m_search);
|
||||
LOG("Substituted LHS: " << lhs() << " := " << p);
|
||||
auto q = rhs().subst_val(s.m_search);
|
||||
LOG("Substituted RHS: " << rhs() << " := " << q);
|
||||
|
||||
if (is_always_false(p, q)) {
|
||||
s.set_conflict(*this);
|
||||
return;
|
||||
}
|
||||
if (p.is_val() && q.is_val()) {
|
||||
SASSERT(p.val() <= q.val());
|
||||
return;
|
||||
}
|
||||
|
||||
pvar v = null_var;
|
||||
rational a, b, c, d;
|
||||
if (p.is_unilinear() && q.is_unilinear() && p.var() == q.var()) {
|
||||
// a*x + b <=u c*x + d
|
||||
v = p.var();
|
||||
a = p.hi().val();
|
||||
b = p.lo().val();
|
||||
c = q.hi().val();
|
||||
d = q.lo().val();
|
||||
}
|
||||
else if (p.is_unilinear() && q.is_val()) {
|
||||
// a*x + b <=u d
|
||||
v = p.var();
|
||||
a = p.hi().val();
|
||||
b = p.lo().val();
|
||||
c = rational::zero();
|
||||
d = q.val();
|
||||
}
|
||||
else if (p.is_val() && q.is_unilinear()) {
|
||||
// b <=u c*x + d
|
||||
v = q.var();
|
||||
a = rational::zero();
|
||||
b = p.val();
|
||||
c = q.hi().val();
|
||||
d = q.lo().val();
|
||||
}
|
||||
if (v != null_var) {
|
||||
bddv const& x = s.var2bits(v).var();
|
||||
bdd xs = (a * x + b <= c * x + d);
|
||||
s.push_cjust(v, this);
|
||||
s.intersect_viable(v, xs);
|
||||
|
||||
rational val;
|
||||
if (s.find_viable(v, val) == dd::find_t::singleton) {
|
||||
s.propagate(v, val, *this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: other cheap constraints possible?
|
||||
}
|
||||
|
||||
bool ule_constraint::is_always_false(pdd const& lhs, pdd const& rhs) {
|
||||
// TODO: other conditions (e.g. when forbidden interval would be full)
|
||||
return lhs.is_val() && rhs.is_val() && !(lhs.val() <= rhs.val());
|
||||
}
|
||||
|
||||
bool ule_constraint::is_always_false() {
|
||||
return false;
|
||||
return is_always_false(lhs(), rhs());
|
||||
}
|
||||
|
||||
bool ule_constraint::is_currently_false(solver& s) {
|
||||
return false;
|
||||
auto p = lhs().subst_val(s.m_search);
|
||||
auto q = rhs().subst_val(s.m_search);
|
||||
return is_always_false(p, q);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue