mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +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:
parent
d909852e99
commit
ff4b9daf1a
6 changed files with 418 additions and 352 deletions
|
@ -1,87 +0,0 @@
|
|||
#include "arith_decl_plugin.h"
|
||||
#include "qe.h"
|
||||
#include "ast_pp.h"
|
||||
#include "smtparser.h"
|
||||
#include "reg_decl_plugins.h"
|
||||
|
||||
|
||||
static void test_defs(ast_manager& m, expr* _fml) {
|
||||
arith_util a(m);
|
||||
app_ref x(m);
|
||||
qe::def_vector defs(m);
|
||||
expr_ref fml(_fml, m);
|
||||
x = m.mk_const(symbol("x"), a.mk_int());
|
||||
app* vars[1] = { x.get() };
|
||||
front_end_params fparams;
|
||||
qe::expr_quant_elim qelim(m, fparams);
|
||||
lbool result = qelim.first_elim(1, vars, fml, defs);
|
||||
std::cout << mk_pp(_fml, m) << "\n--->\n";
|
||||
std::cout << mk_pp(fml, m) << "\n";
|
||||
for (unsigned i = 0; i < defs.size(); ++i) {
|
||||
std::cout << defs.var(i)->get_name() << " "
|
||||
<< mk_pp(defs.def(i), m) << "\n";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
static void test_defs_all(ast_manager& m, expr* _fml) {
|
||||
arith_util a(m);
|
||||
app_ref x(m);
|
||||
expr_ref fml(_fml, m), fml0(_fml, m);
|
||||
x = m.mk_const(symbol("x"), a.mk_int());
|
||||
app* vars[1] = { x.get() };
|
||||
front_end_params fparams;
|
||||
qe::expr_quant_elim qelim(m, fparams);
|
||||
lbool result = l_true;
|
||||
while (result == l_true) {
|
||||
fml = fml0;
|
||||
qe::def_vector defs(m);
|
||||
result = qelim.first_elim(1, vars, fml, defs);
|
||||
std::cout << result << "\n";
|
||||
std::cout << mk_pp(fml, m) << "\n";
|
||||
for (unsigned i = 0; i < defs.size(); ++i) {
|
||||
std::cout << defs.var(i)->get_name() << " "
|
||||
<< mk_pp(defs.def(i), m) << "\n";
|
||||
}
|
||||
fml0 = m.mk_and(fml0, m.mk_not(fml));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_defs(char const* str) {
|
||||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
scoped_ptr<smtlib::parser> parser = smtlib::parser::create(m);
|
||||
parser->initialize_smtlib();
|
||||
std::ostringstream buffer;
|
||||
buffer << "(benchmark presburger :status unknown :logic AUFLIA "
|
||||
<< ":extrafuns ((x Int) (y Int) (z Int))\n"
|
||||
<< ":formula " << str << ")";
|
||||
parser->parse_string(buffer.str().c_str());
|
||||
smtlib::benchmark* b = parser->get_benchmark();
|
||||
smtlib::theory::expr_iterator it = b->begin_formulas();
|
||||
smtlib::theory::expr_iterator end = b->end_formulas();
|
||||
for (; it != end; ++it) {
|
||||
test_defs(m, *it);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qe_defs() {
|
||||
enable_trace("qe");
|
||||
test_defs("(and (<= (* 2 x) y) (>= (* 3 x) z) (<= (* 4 x) (* 2 z)) (= (mod x 2) 0))");
|
||||
|
||||
return;
|
||||
test_defs("(and (<= (* 2 x) y) (>= (* 3 x) z) (= (mod x 2) 0))");
|
||||
test_defs("(and (<= (* 2 x) y) (= (mod x 2) 0))");
|
||||
test_defs("(= (* 2 x) y)");
|
||||
test_defs("(or (< x 0) (> x 1))");
|
||||
test_defs("(or (< x y) (> x y))");
|
||||
test_defs("(= x y)");
|
||||
test_defs("(<= x y)");
|
||||
test_defs("(>= x y)");
|
||||
test_defs("(and (<= (+ x y) 0) (<= (+ x z) 0))");
|
||||
test_defs("(and (<= (+ x y) 0) (<= (+ (* 2 x) z) 0))");
|
||||
test_defs("(and (<= (+ (* 3 x) y) 0) (<= (+ (* 2 x) z) 0))");
|
||||
test_defs("(and (>= x y) (>= x z))");
|
||||
test_defs("(< x y)");
|
||||
test_defs("(> x y)");
|
||||
}
|
|
@ -8,39 +8,82 @@
|
|||
#include "expr_replacer.h"
|
||||
#include "smt_solver.h"
|
||||
#include "reg_decl_plugins.h"
|
||||
#include "smtparser.h"
|
||||
#include "expr_abstract.h"
|
||||
#include "model_smt2_pp.h"
|
||||
|
||||
static void validate_quant_solution(ast_manager& m, app* x, expr* fml, expr* t, expr* new_fml) {
|
||||
static void validate_quant_solution(ast_manager& m, expr* fml, expr* guard, qe::def_vector const& defs) {
|
||||
// verify:
|
||||
// new_fml <=> fml[t/x]
|
||||
// new_fml => fml[t/x]
|
||||
scoped_ptr<expr_replacer> rep = mk_expr_simp_replacer(m);
|
||||
app_ref_vector xs(m);
|
||||
expr_substitution sub(m);
|
||||
sub.insert(x, t);
|
||||
for (unsigned i = 0; i < defs.size(); ++i) {
|
||||
xs.push_back(m.mk_const(defs.var(i)));
|
||||
sub.insert(xs.back(), defs.def(i));
|
||||
}
|
||||
rep->set_substitution(&sub);
|
||||
expr_ref fml1(fml, m);
|
||||
(*rep)(fml1);
|
||||
expr_ref tmp(m);
|
||||
tmp = m.mk_not(m.mk_iff(new_fml, fml1));
|
||||
tmp = m.mk_not(m.mk_implies(guard, fml1));
|
||||
front_end_params fp;
|
||||
smt::solver solver(m, fp);
|
||||
solver.assert_expr(tmp);
|
||||
lbool res = solver.check();
|
||||
std::cout << res << "\n";
|
||||
//SASSERT(res == l_false);
|
||||
if (res != l_false) {
|
||||
std::cout << "Validation failed: " << res << "\n";
|
||||
std::cout << mk_pp(tmp, m) << "\n";
|
||||
model_ref model;
|
||||
solver.get_model(model);
|
||||
model_smt2_pp(std::cout, m, *model, 0);
|
||||
fatal_error(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void validate_quant_solutions(app* x, expr* fml, expr_ref_vector& guards) {
|
||||
return;
|
||||
// quant_elim option got removed...
|
||||
// verify:
|
||||
// fml <=> guard_1 \/ guard_2 \/ ...
|
||||
ast_manager& m = guards.get_manager();
|
||||
expr_ref tmp(m), fml2(m);
|
||||
tmp = m.mk_or(guards.size(), guards.c_ptr());
|
||||
expr* _x = x;
|
||||
std::cout << mk_pp(fml, m) << "\n";
|
||||
expr_abstract(m, 0, 1, &_x, fml, fml2);
|
||||
std::cout << mk_pp(fml2, m) << "\n";
|
||||
symbol name(x->get_decl()->get_name());
|
||||
sort* s = m.get_sort(x);
|
||||
fml2 = m.mk_exists(1, &s, &name, fml2);
|
||||
std::cout << mk_pp(fml2, m) << "\n";
|
||||
tmp = m.mk_not(m.mk_iff(fml2, tmp));
|
||||
std::cout << mk_pp(tmp, m) << "\n";
|
||||
front_end_params fp;
|
||||
smt::solver solver(m, fp);
|
||||
solver.assert_expr(tmp);
|
||||
lbool res = solver.check();
|
||||
std::cout << "checked\n";
|
||||
SASSERT(res == l_false);
|
||||
if (res != l_false) {
|
||||
std::cout << res << "\n";
|
||||
fatal_error(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_quant_solver(ast_manager& m, app* x, expr* fml) {
|
||||
front_end_params params;
|
||||
params.m_quant_elim = true;
|
||||
qe::expr_quant_elim qe(m, params);
|
||||
expr_ref_vector terms(m);
|
||||
expr_ref_vector fmls(m);
|
||||
bool success = qe.solve_for_var(x, fml, terms, fmls);
|
||||
qe::guarded_defs defs(m);
|
||||
bool success = qe.solve_for_var(x, fml, defs);
|
||||
std::cout << "------------------------\n";
|
||||
std::cout << mk_pp(fml, m) << "\n";
|
||||
if (success) {
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
std::cout << mk_pp(x, m) << " = " << mk_pp(terms[i].get(), m) << "\n" << mk_pp(fmls[i].get(), m) << "\n";
|
||||
validate_quant_solution(m, x, fml, terms[i].get(), fmls[i].get());
|
||||
if (success) {
|
||||
defs.display(std::cout);
|
||||
for (unsigned i = 0; i < defs.size(); ++i) {
|
||||
validate_quant_solution(m, fml, defs.guard(i), defs.defs(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -48,32 +91,18 @@ static void test_quant_solver(ast_manager& m, app* x, expr* fml) {
|
|||
}
|
||||
}
|
||||
|
||||
static void test_quant_solver_rec(ast_manager& m, unsigned num_vars, app* const* xs, expr* fml) {
|
||||
if (num_vars == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_quant_solver(ast_manager& m, unsigned sz, app*const* xs, expr* fml) {
|
||||
front_end_params params;
|
||||
params.m_quant_elim = true;
|
||||
qe::expr_quant_elim qe(m, params);
|
||||
expr_ref_vector fmls(m), ors(m), terms(m);
|
||||
app* x = xs[0];
|
||||
bool success = qe.solve_for_var(x, fml, terms, fmls);
|
||||
qe::guarded_defs defs(m);
|
||||
bool success = qe.solve_for_vars(sz, xs, fml, defs);
|
||||
std::cout << "------------------------\n";
|
||||
std::cout << mk_pp(fml, m) << "\n";
|
||||
if (success) {
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
std::cout << mk_pp(x, m) << " = " << mk_pp(terms[i].get(), m) << "\n" << mk_pp(fmls[i].get(), m) << "\n";
|
||||
validate_quant_solution(m, x, fml, terms[i].get(), fmls[i].get());
|
||||
ors.reset();
|
||||
if (m.is_or(fmls[i].get())) {
|
||||
ors.append(to_app(fmls[i].get())->get_num_args(), to_app(fmls[i].get())->get_args());
|
||||
}
|
||||
else {
|
||||
ors.push_back(fmls[i].get());
|
||||
}
|
||||
for (unsigned j = 0; j < ors.size(); ++j) {
|
||||
test_quant_solver_rec(m, num_vars-1, xs+1, ors[j].get());
|
||||
}
|
||||
if (success) {
|
||||
defs.display(std::cout);
|
||||
for (unsigned i = 0; i < defs.size(); ++i) {
|
||||
validate_quant_solution(m, fml, defs.guard(i), defs.defs(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -82,65 +111,107 @@ static void test_quant_solver_rec(ast_manager& m, unsigned num_vars, app* const*
|
|||
}
|
||||
|
||||
|
||||
static expr_ref parse_fml(ast_manager& m, char const* str) {
|
||||
expr_ref result(m);
|
||||
reg_decl_plugins(m);
|
||||
scoped_ptr<smtlib::parser> parser = smtlib::parser::create(m);
|
||||
parser->initialize_smtlib();
|
||||
std::ostringstream buffer;
|
||||
buffer << "(benchmark presburger :status unknown :logic AUFLIA "
|
||||
<< ":extrafuns ((x Int) (y Int) (z Int) (a Int) (b Int))\n"
|
||||
<< ":formula " << str << ")";
|
||||
parser->parse_string(buffer.str().c_str());
|
||||
smtlib::benchmark* b = parser->get_benchmark();
|
||||
smtlib::theory::expr_iterator it = b->begin_formulas();
|
||||
smtlib::theory::expr_iterator end = b->end_formulas();
|
||||
SASSERT(it != b->end_formulas());
|
||||
result = *it;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void test_quant_solver(ast_manager& m, app* x, char const* str) {
|
||||
expr_ref fml = parse_fml(m, str);
|
||||
test_quant_solver(m, x, fml);
|
||||
}
|
||||
|
||||
static void test_quant_solver(ast_manager& m, unsigned sz, app*const* xs, char const* str) {
|
||||
expr_ref fml = parse_fml(m, str);
|
||||
test_quant_solver(m, sz, xs, fml);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void test_quant_solve1() {
|
||||
ast_manager m;
|
||||
arith_util ar(m);
|
||||
|
||||
reg_decl_plugins(m);
|
||||
sort* i = ar.mk_int();
|
||||
app_ref x(m.mk_const(symbol("x"),i), m);
|
||||
app_ref y(m.mk_const(symbol("y"),i), m);
|
||||
app_ref a(m.mk_const(symbol("a"),i), m);
|
||||
app_ref b(m.mk_const(symbol("b"),i), m);
|
||||
expr_ref n2(ar.mk_numeral(rational(2), true), m);
|
||||
expr_ref n3(ar.mk_numeral(rational(3), true), m);
|
||||
expr_ref n4(ar.mk_numeral(rational(4), true), m);
|
||||
expr_ref n10(ar.mk_numeral(rational(10), true), m);
|
||||
expr_ref n20(ar.mk_numeral(rational(20), true), m);
|
||||
expr_ref x2(ar.mk_mul(n2, x), m);
|
||||
expr_ref x3(ar.mk_mul(n3, x), m);
|
||||
expr_ref fml1(m), fml2(m), fml3(m), fml4(m);
|
||||
expr_ref fml(m), t1(m), t2(m);
|
||||
|
||||
fml1 = m.mk_eq(x, a);
|
||||
fml2 = ar.mk_lt(x, a);
|
||||
fml3 = ar.mk_gt(x, a);
|
||||
fml4 = m.mk_and(ar.mk_lt(x, a), ar.mk_lt(x, b));
|
||||
expr_ref fml5(m.mk_and(ar.mk_gt(x, a), ar.mk_lt(x, b)), m);
|
||||
expr_ref fml6(ar.mk_le(x, a), m);
|
||||
expr_ref fml7(ar.mk_ge(x, a), m);
|
||||
expr_ref fml8(ar.mk_lt(ar.mk_mul(n2, x), a), m);
|
||||
expr_ref fml9(m.mk_eq(ar.mk_mul(n2, x), a), m);
|
||||
|
||||
test_quant_solver(m, x.get(), fml1.get());
|
||||
test_quant_solver(m, x.get(), fml2.get());
|
||||
test_quant_solver(m, x.get(), fml3.get());
|
||||
test_quant_solver(m, x.get(), fml4.get());
|
||||
test_quant_solver(m, x.get(), fml5.get());
|
||||
test_quant_solver(m, x.get(), fml6.get());
|
||||
test_quant_solver(m, x.get(), fml7.get());
|
||||
test_quant_solver(m, x.get(), fml8.get());
|
||||
test_quant_solver(m, x.get(), fml9.get());
|
||||
|
||||
fml = ar.mk_lt(x2, a); test_quant_solver(m, x.get(), fml.get());
|
||||
fml = ar.mk_gt(x2, a); test_quant_solver(m, x.get(), fml.get());
|
||||
fml = ar.mk_le(x2, a); test_quant_solver(m, x.get(), fml.get());
|
||||
fml = ar.mk_ge(x2, a); test_quant_solver(m, x.get(), fml.get());
|
||||
app_ref xr(m.mk_const(symbol("x"),i), m);
|
||||
app_ref yr(m.mk_const(symbol("y"),i), m);
|
||||
app* x = xr.get();
|
||||
app* y = yr.get();
|
||||
app* xy[2] = { x, y };
|
||||
|
||||
|
||||
fml = m.mk_and(ar.mk_lt(a, ar.mk_mul(n3,x)), ar.mk_lt(ar.mk_mul(n3,x), b));
|
||||
test_quant_solver(m, x.get(), fml.get());
|
||||
test_quant_solver(m, x, "(and (<= x y) (= (mod x 2) 0))");
|
||||
test_quant_solver(m, x, "(and (<= (* 2 x) y) (= (mod x 2) 0))");
|
||||
test_quant_solver(m, x, "(and (>= x y) (= (mod x 2) 0))");
|
||||
test_quant_solver(m, x, "(and (>= (* 2 x) y) (= (mod x 2) 0))");
|
||||
test_quant_solver(m, x, "(and (<= (* 2 x) y) (>= x z) (= (mod x 2) 0))");
|
||||
test_quant_solver(m, x, "(and (<= (* 2 x) y) (>= (* 3 x) z) (= (mod x 2) 0))");
|
||||
|
||||
test_quant_solver(m, x, "(>= (* 2 x) a)");
|
||||
|
||||
test_quant_solver(m, x, "(<= (* 2 x) a)");
|
||||
test_quant_solver(m, x, "(< (* 2 x) a)");
|
||||
test_quant_solver(m, x, "(= (* 2 x) a)");
|
||||
test_quant_solver(m, x, "(< (* 2 x) a)");
|
||||
test_quant_solver(m, x, "(> (* 2 x) a)");
|
||||
|
||||
|
||||
test_quant_solver(m, x, "(and (<= a x) (<= (* 2 x) b))");
|
||||
|
||||
test_quant_solver(m, x, "(and (<= a x) (<= x b))");
|
||||
test_quant_solver(m, x, "(and (<= (* 2 a) x) (<= x b))");
|
||||
test_quant_solver(m, x, "(and (<= (* 2 a) x) (<= (* 2 x) b))");
|
||||
test_quant_solver(m, x, "(and (<= a x) (<= (* 3 x) b))");
|
||||
test_quant_solver(m, x, "(and (<= (* 3 a) x) (<= x b))");
|
||||
test_quant_solver(m, x, "(and (<= (* 3 a) x) (<= (* 3 x) b))");
|
||||
|
||||
test_quant_solver(m, x, "(and (< a (* 3 x)) (< (* 3 x) b))");
|
||||
|
||||
test_quant_solver(m, x, "(< (* 3 x) a)");
|
||||
test_quant_solver(m, x, "(= (* 3 x) a)");
|
||||
test_quant_solver(m, x, "(< (* 3 x) a)");
|
||||
test_quant_solver(m, x, "(> (* 3 x) a)");
|
||||
test_quant_solver(m, x, "(<= (* 3 x) a)");
|
||||
test_quant_solver(m, x, "(>= (* 3 x) a)");
|
||||
|
||||
test_quant_solver(m, x, "(<= (* 2 x) a)");
|
||||
test_quant_solver(m, x, "(or (= (* 2 x) y) (= (+ (* 2 x) 1) y))");
|
||||
test_quant_solver(m, x, "(= x a)");
|
||||
test_quant_solver(m, x, "(< x a)");
|
||||
test_quant_solver(m, x, "(> x a)");
|
||||
test_quant_solver(m, x, "(and (> x a) (< x b))");
|
||||
test_quant_solver(m, x, "(and (> x a) (< x b))");
|
||||
test_quant_solver(m, x, "(<= x a)");
|
||||
test_quant_solver(m, x, "(>= x a)");
|
||||
test_quant_solver(m, x, "(and (<= (* 2 x) y) (= (mod x 2) 0))");
|
||||
test_quant_solver(m, x, "(= (* 2 x) y)");
|
||||
test_quant_solver(m, x, "(or (< x 0) (> x 1))");
|
||||
test_quant_solver(m, x, "(or (< x y) (> x y))");
|
||||
test_quant_solver(m, x, "(= x y)");
|
||||
test_quant_solver(m, x, "(<= x y)");
|
||||
test_quant_solver(m, x, "(>= x y)");
|
||||
test_quant_solver(m, x, "(and (<= (+ x y) 0) (<= (+ x z) 0))");
|
||||
test_quant_solver(m, x, "(and (<= (+ x y) 0) (<= (+ (* 2 x) z) 0))");
|
||||
test_quant_solver(m, x, "(and (<= (+ (* 3 x) y) 0) (<= (+ (* 2 x) z) 0))");
|
||||
test_quant_solver(m, x, "(and (>= x y) (>= x z))");
|
||||
test_quant_solver(m, x, "(< x y)");
|
||||
test_quant_solver(m, x, "(> x y)");
|
||||
|
||||
test_quant_solver(m, 2, xy, "(and (<= (- (* 2 y) b) (+ (* 3 x) a)) (<= (- (* 2 x) a) (+ (* 4 y) b)))");
|
||||
|
||||
t1 = ar.mk_sub(ar.mk_mul(n2,y),b);
|
||||
t2 = ar.mk_add(ar.mk_mul(n3,x),a);
|
||||
fml1 = ar.mk_le(t1, t2);
|
||||
t1 = ar.mk_sub(ar.mk_mul(n2,x),a);
|
||||
t2 = ar.mk_add(ar.mk_mul(n4,y),b);
|
||||
fml2 = ar.mk_le(t1,t2);
|
||||
fml = m.mk_and(fml1, fml2);
|
||||
app* xy[2] = { x.get(), y.get() };
|
||||
test_quant_solver_rec(m, 2, xy, fml.get());
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue