3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-18 02:16:40 +00:00

fix solution generation for quantified integer arithmetic. Added unit tests

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2012-10-28 17:55:11 -07:00
parent d909852e99
commit ff4b9daf1a
6 changed files with 418 additions and 352 deletions

View file

@ -367,16 +367,6 @@ namespace qe {
simplify(result);
}
expr_ref mk_idiv(expr* a, numeral const & k) {
if (k.is_one()) {
return expr_ref(a, m);
}
expr_ref result(m);
result = m_arith.mk_idiv(a, m_arith.mk_numeral(k, true));
simplify(result);
return result;
}
expr* mk_numeral(numeral const& k, bool is_int = true) { return m_arith.mk_numeral(k, is_int); }
expr* mk_numeral(int k, bool is_int) { return mk_numeral(numeral(k),is_int); }
@ -1699,6 +1689,40 @@ public:
private:
/**
\brief Compute least upper/greatest lower bounds for x.
Assume:
(not (= k 0))
(<= 0 (mod m k))
(< (mod m k) (abs k))
(= m (+ (* k (div m k)) (mod m k)))
i.e.
k * (e div k) + (e mod k) = e
When k is positive, least upper bound
for x such that: k*x <= e is e div k
When k is negative, greatest lower bound
for x such that k*x <= e is e div k
k * (e div k) + (e mod k) = e
*/
expr_ref mk_idiv(expr* e, numeral k) {
SASSERT(!k.is_zero());
arith_util& a = m_util.m_arith;
if (k.is_one()) {
return expr_ref(e, m);
}
if (k.is_minus_one()) {
return expr_ref(a.mk_uminus(e), m);
}
SASSERT(a.is_int(e));
return expr_ref(a.mk_idiv(e, a.mk_numeral(k, true)), m);
}
void get_def(contains_app& contains_x, unsigned v, expr* fml, expr_ref& def) {
app* x = contains_x.x();
x_subst x_t(m_util);
@ -1730,35 +1754,30 @@ public:
// a*x + term <= 0
expr_ref term(bounds.exprs(is_strict, !is_lower)[i], m);
rational a = bounds.coeffs(is_strict, !is_lower)[i];
if (x_t.get_term()) {
// a*(c*x' + s) + term <= 0
// term <- a*s + term
// a <- a*c
term = m_util.mk_add(m_util.mk_mul(a,x_t.get_term()), term);
a = a * x_t.get_coeff();
// x := coeff * x' + s
// solve instead for
// a*coeff*x' + term + a*s <= 0
TRACE("qe", tout << x_t.get_coeff() << "* " << mk_pp(x,m) << " + "
<< mk_pp(x_t.get_term(), m) << "\n";);
SASSERT(x_t.get_coeff().is_pos());
term = m_util.mk_add(term, m_util.mk_mul(a, x_t.get_term()));
a = a * x_t.get_coeff();
}
TRACE("qe", tout << a << "* " << mk_pp(x,m) << " + " << mk_pp(term, m) << " <= 0\n";);
SASSERT(a.is_int());
if (is_lower) {
// a*x + t <= 0
// <=
// x <= -t div a
SASSERT(a.is_pos());
term = m_util.mk_idiv(m_util.mk_uminus(term), a);
}
else {
// -a*x + t <= 0
// <=>
// t <= a*x
// <=
// ((div t a) + 1) <= x
term = m_util.mk_idiv(term, abs(a));
if (!(abs(a).is_one())) {
term = m_util.mk_add(term, m_util.mk_one(x));
}
}
terms.push_back(term);
SASSERT(is_lower == a.is_pos());
TRACE("qe", tout << is_lower << " " << a << " " << mk_pp(term, m) << "\n";);
// a*x + t <= 0
// <=
// x <= -t div a + 1
term = m_util.mk_uminus(term);
term = mk_idiv(term, a);
terms.push_back(term);
TRACE("qe", tout << "a: " << a << " term: " << mk_pp(term, m) << "\n";);
}
is_strict = true;
sz = bounds.size(is_strict, !is_lower);
@ -1788,14 +1807,11 @@ public:
}
if (x_t.get_term()) {
//
// x = x_t.get_coeff()*x' + x_t.get_term()
// =>
// x' = (x - x_t.get_term()) div x_t.get_coeff()
//
def = m_util.mk_idiv(m_util.mk_sub(def, x_t.get_term()), x_t.get_coeff());
// x := coeff * x + s
TRACE("qe", tout << x_t.get_coeff() << "* " << mk_pp(x,m) << " + "
<< mk_pp(x_t.get_term(), m) << "\n";);
def = m_util.mk_add(m_util.mk_mul(x_t.get_coeff(), def), x_t.get_term());
}
m_util.simplify(def);
return;
}
@ -1822,25 +1838,39 @@ public:
// assert v => (x <= t_i)
//
SASSERT(v < bounds.size(is_strict, is_lower));
expr_ref t(bounds.exprs(is_strict, is_lower)[v], m);
def = bounds.exprs(is_strict, is_lower)[v];
rational a = bounds.coeffs(is_strict, is_lower)[v];
t = x_t.mk_term(a, t);
a = x_t.mk_coeff(a);
def = t;
if (a.is_pos()) {
def = m_util.mk_uminus(def);
}
if (x_t.get_term()) {
def = m_util.mk_idiv(m_util.mk_sub(def, x_t.get_term()), x_t.get_coeff());
// x := coeff * x' + s
// solve instead for
// a*coeff*x' + term + a*s <= 0
TRACE("qe", tout << x_t.get_coeff() << "* " << mk_pp(x,m) << " + "
<< mk_pp(x_t.get_term(), m) << "\n";);
SASSERT(x_t.get_coeff().is_pos());
def = m_util.mk_add(def, m_util.mk_mul(a, x_t.get_term()));
a = a * x_t.get_coeff();
}
if (!a.is_one()) {
def = m_util.mk_idiv(def, a);
SASSERT(a.is_int());
SASSERT(is_lower != a.is_pos());
// a*x + t <= 0
// <=
// x <= -t div a
def = m_util.mk_uminus(def);
def = mk_idiv(def, a);
if (x_t.get_term()) {
// x := coeff * x + s
def = m_util.mk_add(m_util.mk_mul(x_t.get_coeff(), def), x_t.get_term());
}
m_util.simplify(def);
TRACE("qe", tout << "TBD: " << a << " " << mk_pp(t, m) << "\n";);
TRACE("qe", tout << "TBD: " << a << " " << mk_pp(def, m) << "\n";);
}
expr_ref mk_not(expr* e) {