3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 10:55:50 +00:00

move constraint handler functionality to self-contained / separate classes.

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2021-04-15 13:08:25 -07:00
parent 0d78a10630
commit 5163492d5b
5 changed files with 134 additions and 117 deletions

View file

@ -215,7 +215,7 @@ namespace polysat {
bool solver::propagate(pvar v, constraint& c) {
switch (c.kind()) {
case ckind_t::eq_t:
return propagate_eq(v, c);
return c.to_eq().propagate(*this, v);
case ckind_t::ule_t:
case ckind_t::sle_t:
NOT_IMPLEMENTED_YET();
@ -225,110 +225,6 @@ namespace polysat {
return false;
}
bool solver::propagate_eq(pvar v, constraint& c) {
LOG_H3("Propagate " << m_vars[v] << " in " << c);
SASSERT(c.kind() == ckind_t::eq_t);
SASSERT(!c.vars().empty());
auto var = m_vars[v].var();
auto& vars = c.vars();
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 (!is_assigned(vars[i])) {
std::swap(vars[idx], vars[i]);
return true;
}
}
LOG("Assignments: " << m_search);
auto p = c.p().subst_val(m_search);
LOG("Substituted: " << c.p() << " := " << p);
TRACE("polysat", tout << c.p() << " := " << p << "\n";);
if (p.is_zero())
return false;
if (p.is_never_zero()) {
LOG("Conflict (never zero under current assignment)");
// we could tag constraint to allow early substitution before
// swapping watch variable in case we can detect conflict earlier.
set_conflict(c);
return false;
}
// at most one variable remains unassigned.
auto other_var = vars[1 - idx];
// SASSERT(!is_assigned(other_var));
// Detect and apply unit propagation.
if (!p.is_linear())
return false;
// a*x + b == 0
rational a = p.hi().val();
rational b = p.lo().val();
rational inv_a;
if (a.is_odd()) {
// v1 = -b * inverse(a)
unsigned sz = p.power_of_2();
VERIFY(a.mult_inverse(sz, inv_a));
rational val = mod(inv_a * -b, rational::power_of_two(sz));
m_cjust[other_var].push_back(&c);
propagate(other_var, val, c);
return false;
}
SASSERT(!b.is_odd()); // otherwise p.is_never_zero() would have been true above
// TBD
// constrain viable using condition on x
// 2*x + 2 == 0 mod 4 => x is odd
//
// We have:
// 2^j*a'*x + 2^j*b' == 0 mod m, where a' is odd (but not necessarily b')
// <=> 2^j*(a'*x + b') == 0 mod m
// <=> a'*x + b' == 0 mod (m-j)
// <=> x == -b' * inverse_{m-j}(a') mod (m-j)
// ( <=> 2^j*x == 2^j * -b' * inverse_{m-j}(a') mod m )
//
// x == c mod (m-j)
// Which x in 2^m satisfy this?
// => x \in { c + k * 2^(m-j) | k = 0, ..., 2^j - 1 }
unsigned rank_a = a.trailing_zeros(); // j
SASSERT(b == 0 || rank_a <= b.trailing_zeros());
rational aa = a / rational::power_of_two(rank_a); // a'
rational bb = b / rational::power_of_two(rank_a); // b'
rational inv_aa;
unsigned small_sz = p.power_of_2() - rank_a; // m - j
VERIFY(aa.mult_inverse(small_sz, inv_aa));
rational cc = mod(inv_aa * -bb, rational::power_of_two(small_sz));
LOG(m_vars[other_var] << " = " << cc << " + k * 2^" << small_sz);
// TODO: better way to update the BDD, e.g. construct new one (only if rank_a is small?)
vector<rational> viable;
for (rational k = rational::zero(); k < rational::power_of_two(rank_a); k += 1) {
rational val = cc + k * rational::power_of_two(small_sz);
viable.push_back(val);
}
LOG_V("still viable: " << viable);
unsigned i = 0;
for (rational r = rational::zero(); r < rational::power_of_two(p.power_of_2()); r += 1) {
while (i < viable.size() && viable[i] < r)
++i;
if (i < viable.size() && viable[i] == r)
continue;
if (is_viable(other_var, r)) {
add_non_viable(other_var, r);
}
}
LOG("TODO");
return false;
}
void solver::propagate(pvar v, rational const& val, constraint& c) {
if (is_viable(v, val)) {
m_free_vars.del_var_eh(v);
@ -645,8 +541,8 @@ namespace polysat {
constraint* c = m_conflict[0];
constraint* d = m_cjust[v].back();
if (c->is_eq() && d->is_eq()) {
pdd p = c->p();
pdd q = d->p();
pdd p = c->to_eq().p();
pdd q = d->to_eq().p();
pdd r = p;
if (!p.resolve(v, q, r))
return nullptr;
@ -668,13 +564,13 @@ namespace polysat {
bool solver::is_always_false(constraint& c) {
if (c.is_eq())
return c.p().is_never_zero();
return c.to_eq().p().is_never_zero();
return false;
}
bool solver::eval_to_false(constraint& c) {
if (c.is_eq()) {
pdd r = c.p().subst_val(m_search);
pdd r = c.to_eq().p().subst_val(m_search);
return r.is_never_zero();
}
return false;