mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
testing utvpi
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
fbe4af6336
commit
21b0a4fcbb
|
@ -597,7 +597,7 @@ namespace pdr {
|
|||
expr_ref fml = pm.mk_and(conj);
|
||||
th_rewriter rw(m);
|
||||
rw(fml);
|
||||
if (ctx.is_dl()) {
|
||||
if (ctx.is_dl() || ctx.is_utvpi()) {
|
||||
hoist_non_bool_if(fml);
|
||||
}
|
||||
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
|
||||
|
@ -1359,9 +1359,10 @@ namespace pdr {
|
|||
bool m_is_bool_arith;
|
||||
bool m_has_arith;
|
||||
bool m_is_dl;
|
||||
bool m_is_utvpi;
|
||||
public:
|
||||
classifier_proc(ast_manager& m, datalog::rule_set& rules):
|
||||
m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false) {
|
||||
m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false), m_is_utvpi(false) {
|
||||
classify(rules);
|
||||
}
|
||||
void operator()(expr* e) {
|
||||
|
@ -1407,6 +1408,7 @@ namespace pdr {
|
|||
|
||||
bool is_dl() const { return m_is_dl; }
|
||||
|
||||
bool is_utvpi() const { return m_is_utvpi; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1427,6 +1429,7 @@ namespace pdr {
|
|||
mark.reset();
|
||||
|
||||
m_is_dl = false;
|
||||
m_is_utvpi = false;
|
||||
if (m_has_arith) {
|
||||
ptr_vector<expr> forms;
|
||||
for (it = rules.begin(); it != end; ++it) {
|
||||
|
@ -1438,6 +1441,11 @@ namespace pdr {
|
|||
}
|
||||
}
|
||||
m_is_dl = is_difference_logic(m, forms.size(), forms.c_ptr());
|
||||
#if 0
|
||||
if (!m_is_dl) {
|
||||
m_is_utvpi = is_utvpi_logic(m, forms.size(), forms.c_ptr());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1561,6 +1569,11 @@ namespace pdr {
|
|||
m_fparams.m_arith_mode = AS_DIFF_LOGIC;
|
||||
m_fparams.m_arith_expand_eqs = true;
|
||||
}
|
||||
else if (classify.is_utvpi()) {
|
||||
IF_VERBOSE(1, verbose_stream() << "UTVPI\n";);
|
||||
m_fparams.m_arith_mode = AS_UTVPI;
|
||||
m_fparams.m_arith_expand_eqs = true;
|
||||
}
|
||||
}
|
||||
if (!use_mc && m_params.use_inductive_generalizer()) {
|
||||
m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0));
|
||||
|
|
|
@ -367,7 +367,7 @@ namespace pdr {
|
|||
expr_ref get_answer();
|
||||
|
||||
bool is_dl() const { return m_fparams.m_arith_mode == AS_DIFF_LOGIC; }
|
||||
|
||||
bool is_utvpi() const { return m_fparams.m_arith_mode == AS_UTVPI; }
|
||||
|
||||
void collect_statistics(statistics& st) const;
|
||||
void reset_statistics();
|
||||
|
|
|
@ -216,6 +216,9 @@ namespace pdr {
|
|||
}
|
||||
res = m.mk_not(res);
|
||||
th_rewriter rw(m);
|
||||
params_ref params;
|
||||
params.set_bool("gcd_rounding", true);
|
||||
rw.updt_params(params);
|
||||
proof_ref pr(m);
|
||||
expr_ref tmp(m);
|
||||
rw(res, tmp, pr);
|
||||
|
|
|
@ -383,26 +383,32 @@ namespace pdr {
|
|||
fl.get_lemmas(pr, bs, lemmas);
|
||||
safe.elim_proxies(lemmas);
|
||||
fl.simplify_lemmas(lemmas); // redundant?
|
||||
if (m_fparams.m_arith_mode == AS_DIFF_LOGIC &&
|
||||
!is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) {
|
||||
IF_VERBOSE(1,
|
||||
verbose_stream() << "not diff\n";
|
||||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
||||
});
|
||||
extract_subset_core(safe);
|
||||
return;
|
||||
|
||||
bool outside_of_logic =
|
||||
(m_fparams.m_arith_mode == AS_DIFF_LOGIC &&
|
||||
!is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) ||
|
||||
(m_fparams.m_arith_mode == AS_UTVPI &&
|
||||
!is_utvpi_logic(m, lemmas.size(), lemmas.c_ptr()));
|
||||
|
||||
if (outside_of_logic) {
|
||||
IF_VERBOSE(1,
|
||||
verbose_stream() << "not diff\n";
|
||||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
||||
});
|
||||
extract_subset_core(safe);
|
||||
}
|
||||
else {
|
||||
|
||||
IF_VERBOSE(2,
|
||||
verbose_stream() << "Lemmas\n";
|
||||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
||||
});
|
||||
|
||||
m_core->reset();
|
||||
m_core->append(lemmas);
|
||||
}
|
||||
|
||||
|
||||
IF_VERBOSE(2,
|
||||
verbose_stream() << "Lemmas\n";
|
||||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
||||
});
|
||||
|
||||
m_core->reset();
|
||||
m_core->append(lemmas);
|
||||
}
|
||||
|
||||
lbool prop_solver::check_assumptions(const expr_ref_vector & atoms) {
|
||||
|
|
|
@ -70,6 +70,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
vector<std::pair<expr*, rational> > const& utvpi_tester::get_linearization() const {
|
||||
SASSERT(m_terms.size() <= 2);
|
||||
return m_terms;
|
||||
}
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace smt {
|
|||
|
||||
virtual bool internalize_term(app * term);
|
||||
|
||||
virtual void internalize_eq_eh(app * atom, bool_var v) {}
|
||||
virtual void internalize_eq_eh(app * atom, bool_var v);
|
||||
|
||||
virtual void assign_eh(bool_var v, bool is_true);
|
||||
|
||||
|
@ -258,6 +258,14 @@ namespace smt {
|
|||
|
||||
private:
|
||||
|
||||
rational mk_value(theory_var v);
|
||||
|
||||
void validate_model();
|
||||
|
||||
bool eval(expr* e);
|
||||
|
||||
rational eval_num(expr* e);
|
||||
|
||||
bool check_z_consistency();
|
||||
|
||||
virtual void new_eq_eh(th_var v1, th_var v2, justification& j) {
|
||||
|
|
|
@ -228,7 +228,10 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::found_non_utvpi_expr(expr* n) {
|
||||
if (!m_non_utvpi_exprs) {
|
||||
TRACE("utvpi", tout << "found non horn logic expression:\n" << mk_pp(n, get_manager()) << "\n";);
|
||||
std::stringstream msg;
|
||||
msg << "found non utvpi logic expression:\n" << mk_pp(n, get_manager()) << "\n";
|
||||
TRACE("utvpi", tout << msg.str(););
|
||||
warning_msg(msg.str().c_str());
|
||||
get_context().push_trail(value_trail<context, bool>(m_non_utvpi_exprs));
|
||||
m_non_utvpi_exprs = true;
|
||||
}
|
||||
|
@ -277,6 +280,24 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::internalize_eq_eh(app * atom, bool_var v) {
|
||||
context & ctx = get_context();
|
||||
app * lhs = to_app(atom->get_arg(0));
|
||||
app * rhs = to_app(atom->get_arg(1));
|
||||
if (a.is_numeral(rhs)) {
|
||||
std::swap(rhs, lhs);
|
||||
}
|
||||
if (!a.is_numeral(rhs)) {
|
||||
return;
|
||||
}
|
||||
if (a.is_add(lhs) || a.is_sub(lhs)) {
|
||||
// force axioms for (= (+ x y) k)
|
||||
// this is necessary because (+ x y) is not expressible as a utvpi term.
|
||||
m_arith_eq_adapter.mk_axioms(ctx.get_enode(lhs), ctx.get_enode(rhs));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::internalize_atom(app * n, bool) {
|
||||
context & ctx = get_context();
|
||||
|
@ -291,7 +312,7 @@ namespace smt {
|
|||
}
|
||||
bool is_strict = a.is_gt(n) || a.is_lt(n);
|
||||
|
||||
bool cl = m_test.linearize(e1, e2);
|
||||
bool cl = m_test.linearize(e1, e2);
|
||||
if (!cl) {
|
||||
found_non_utvpi_expr(n);
|
||||
return false;
|
||||
|
@ -324,8 +345,6 @@ namespace smt {
|
|||
bool theory_utvpi<Ext>::internalize_term(app * term) {
|
||||
bool result = null_theory_var != mk_term(term);
|
||||
CTRACE("utvpi", !result, tout << "Did not internalize " << mk_pp(term, get_manager()) << "\n";);
|
||||
TRACE("utvpi", tout << "Terms may not be internalized " << mk_pp(term, get_manager()) << "\n";);
|
||||
found_non_utvpi_expr(term);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -478,6 +497,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
theory_var theory_utvpi<Ext>::mk_term(app* n) {
|
||||
TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";);
|
||||
context& ctx = get_context();
|
||||
|
||||
bool cl = m_test.linearize(n);
|
||||
|
@ -485,7 +505,7 @@ namespace smt {
|
|||
found_non_utvpi_expr(n);
|
||||
return null_theory_var;
|
||||
}
|
||||
|
||||
|
||||
coeffs coeffs;
|
||||
rational w;
|
||||
mk_coeffs(m_test.get_linearization(), coeffs, w);
|
||||
|
@ -495,7 +515,14 @@ namespace smt {
|
|||
if (coeffs.size() == 1 && coeffs[0].second.is_one()) {
|
||||
return coeffs[0].first;
|
||||
}
|
||||
th_var target = mk_var(ctx.mk_enode(n, false, false, true));
|
||||
if (coeffs.size() == 2) {
|
||||
// do not create an alias.
|
||||
return null_theory_var;
|
||||
}
|
||||
for (unsigned i = 0; i < n->get_num_args(); ++i) {
|
||||
mk_term(to_app(n->get_arg(i)));
|
||||
}
|
||||
th_var target = mk_var(ctx.mk_enode(n, false, false, true));
|
||||
coeffs.push_back(std::make_pair(target, rational(-1)));
|
||||
|
||||
VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal)));
|
||||
|
@ -520,7 +547,7 @@ namespace smt {
|
|||
v = mk_var(ctx.mk_enode(n, false, false, true));
|
||||
// v = k: v <= k k <= v
|
||||
coeffs coeffs;
|
||||
coeffs.push_back(std::make_pair(v, rational(1)));
|
||||
coeffs.push_back(std::make_pair(v, rational(-1)));
|
||||
VERIFY(enable_edge(add_ineq(coeffs, numeral(r), null_literal)));
|
||||
coeffs.back().second.neg();
|
||||
VERIFY(enable_edge(add_ineq(coeffs, numeral(-r), null_literal)));
|
||||
|
@ -633,17 +660,102 @@ namespace smt {
|
|||
m.register_factory(m_factory);
|
||||
// TBD: enforce strong or tight coherence?
|
||||
compute_delta();
|
||||
DEBUG_CODE(validate_model(););
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
model_value_proc * theory_utvpi<Ext>::mk_value(enode * n, model_generator & mg) {
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
void theory_utvpi<Ext>::validate_model() {
|
||||
context& ctx = get_context();
|
||||
unsigned sz = m_atoms.size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
bool_var b = m_atoms[i].get_bool_var();
|
||||
bool ok = true;
|
||||
expr* e = ctx.bool_var2expr(b);
|
||||
switch(ctx.get_assignment(b)) {
|
||||
case l_true:
|
||||
ok = eval(e);
|
||||
break;
|
||||
case l_false:
|
||||
ok = !eval(e);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::eval(expr* e) {
|
||||
expr* e1, *e2;
|
||||
if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) {
|
||||
return eval_num(e1) <= eval_num(e2);
|
||||
}
|
||||
if (a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) {
|
||||
return eval_num(e1) < eval_num(e2);
|
||||
}
|
||||
if (get_manager().is_eq(e, e1, e2)) {
|
||||
return eval_num(e1) == eval_num(e2);
|
||||
}
|
||||
TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
rational theory_utvpi<Ext>::eval_num(expr* e) {
|
||||
rational r;
|
||||
expr* e1, *e2;
|
||||
if (a.is_numeral(e, r)) {
|
||||
return r;
|
||||
}
|
||||
if (a.is_sub(e, e1, e2)) {
|
||||
return eval_num(e1) - eval_num(e2);
|
||||
}
|
||||
if (a.is_add(e)) {
|
||||
r.reset();
|
||||
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||
r += eval_num(to_app(e)->get_arg(i));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
if (a.is_mul(e)) {
|
||||
r = rational(1);
|
||||
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||
r *= eval_num(to_app(e)->get_arg(i));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
if (a.is_uminus(e, e1)) {
|
||||
return -eval_num(e1);
|
||||
}
|
||||
if (a.is_to_real(e, e1)) {
|
||||
return eval_num(e1);
|
||||
}
|
||||
if (is_uninterp_const(e)) {
|
||||
return mk_value(mk_var(e));
|
||||
}
|
||||
TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";);
|
||||
UNREACHABLE();
|
||||
return rational(0);
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
rational theory_utvpi<Ext>::mk_value(th_var v) {
|
||||
SASSERT(v != null_theory_var);
|
||||
numeral val1 = m_graph.get_assignment(to_var(v));
|
||||
numeral val2 = m_graph.get_assignment(neg(to_var(v)));
|
||||
numeral val = val1 - val2;
|
||||
rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational());
|
||||
num = num/rational(2);
|
||||
return num;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
model_value_proc * theory_utvpi<Ext>::mk_value(enode * n, model_generator & mg) {
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
rational num = mk_value(v);
|
||||
num = ceil(num);
|
||||
TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";);
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner())));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue