mirror of
https://github.com/Z3Prover/z3
synced 2025-06-17 03:16:17 +00:00
fix ctx solver simplify, remove horn inequalities
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
891d0d07f8
commit
f2ecd70e65
6 changed files with 36 additions and 1811 deletions
|
@ -27,8 +27,7 @@ enum arith_solver_id {
|
||||||
AS_DIFF_LOGIC,
|
AS_DIFF_LOGIC,
|
||||||
AS_ARITH,
|
AS_ARITH,
|
||||||
AS_DENSE_DIFF_LOGIC,
|
AS_DENSE_DIFF_LOGIC,
|
||||||
AS_UTVPI,
|
AS_UTVPI
|
||||||
AS_HORN
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bound_prop_mode {
|
enum bound_prop_mode {
|
||||||
|
|
|
@ -22,7 +22,6 @@ Revision History:
|
||||||
#include"theory_arith.h"
|
#include"theory_arith.h"
|
||||||
#include"theory_dense_diff_logic.h"
|
#include"theory_dense_diff_logic.h"
|
||||||
#include"theory_diff_logic.h"
|
#include"theory_diff_logic.h"
|
||||||
#include"theory_horn_ineq.h"
|
|
||||||
#include"theory_utvpi.h"
|
#include"theory_utvpi.h"
|
||||||
#include"theory_array.h"
|
#include"theory_array.h"
|
||||||
#include"theory_array_full.h"
|
#include"theory_array_full.h"
|
||||||
|
@ -725,12 +724,6 @@ namespace smt {
|
||||||
m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params));
|
m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AS_HORN:
|
|
||||||
if (m_params.m_arith_int_only)
|
|
||||||
m_context.register_plugin(alloc(smt::theory_ihi, m_manager));
|
|
||||||
else
|
|
||||||
m_context.register_plugin(alloc(smt::theory_rhi, m_manager));
|
|
||||||
break;
|
|
||||||
case AS_UTVPI:
|
case AS_UTVPI:
|
||||||
if (m_params.m_arith_int_only)
|
if (m_params.m_arith_int_only)
|
||||||
m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager));
|
m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager));
|
||||||
|
|
|
@ -139,22 +139,32 @@ protected:
|
||||||
SASSERT(g.is_well_sorted());
|
SASSERT(g.is_well_sorted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct expr_pos {
|
||||||
|
unsigned m_parent;
|
||||||
|
unsigned m_self;
|
||||||
|
unsigned m_idx;
|
||||||
|
expr* m_expr;
|
||||||
|
expr_pos(unsigned p, unsigned s, unsigned i, expr* e):
|
||||||
|
m_parent(p), m_self(s), m_idx(i), m_expr(e)
|
||||||
|
{}
|
||||||
|
expr_pos():
|
||||||
|
m_parent(0), m_self(0), m_idx(0), m_expr(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
void reduce(expr_ref& result){
|
void reduce(expr_ref& result){
|
||||||
SASSERT(m.is_bool(result));
|
SASSERT(m.is_bool(result));
|
||||||
ptr_vector<expr> todo;
|
|
||||||
ptr_vector<expr> names;
|
ptr_vector<expr> names;
|
||||||
svector<bool> is_checked;
|
svector<expr_pos> todo;
|
||||||
svector<unsigned> parent_ids, self_ids;
|
|
||||||
expr_ref_vector fresh_vars(m), trail(m);
|
expr_ref_vector fresh_vars(m), trail(m);
|
||||||
expr_ref res(m), tmp(m);
|
expr_ref res(m), tmp(m);
|
||||||
obj_map<expr,std::pair<unsigned, expr*> > cache;
|
obj_map<expr, expr_pos> cache;
|
||||||
unsigned id = 1;
|
unsigned id = 1, child_id = 0;
|
||||||
expr_ref n2(m), fml(m);
|
expr_ref n2(m), fml(m);
|
||||||
unsigned path_id = 0, self_pos = 0;
|
unsigned parent_pos = 0, self_pos = 0, self_idx = 0;
|
||||||
app * a;
|
app * a;
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
std::pair<unsigned,expr*> path_r;
|
expr_pos path_r;
|
||||||
ptr_vector<expr> found;
|
|
||||||
expr_ref_vector args(m);
|
expr_ref_vector args(m);
|
||||||
expr_ref n = mk_fresh(id, m.mk_bool_sort());
|
expr_ref n = mk_fresh(id, m.mk_bool_sort());
|
||||||
trail.push_back(n);
|
trail.push_back(n);
|
||||||
|
@ -163,26 +173,25 @@ protected:
|
||||||
tmp = m.mk_not(m.mk_iff(fml, n));
|
tmp = m.mk_not(m.mk_iff(fml, n));
|
||||||
m_solver.assert_expr(tmp);
|
m_solver.assert_expr(tmp);
|
||||||
|
|
||||||
todo.push_back(fml);
|
todo.push_back(expr_pos(0,0,0,fml));
|
||||||
names.push_back(n);
|
names.push_back(n);
|
||||||
is_checked.push_back(false);
|
|
||||||
parent_ids.push_back(0);
|
|
||||||
self_ids.push_back(0);
|
|
||||||
m_solver.push();
|
m_solver.push();
|
||||||
|
|
||||||
while (!todo.empty() && !m_cancel) {
|
while (!todo.empty() && !m_cancel) {
|
||||||
expr_ref res(m);
|
expr_ref res(m);
|
||||||
args.reset();
|
args.reset();
|
||||||
expr* e = todo.back();
|
expr* e = todo.back().m_expr;
|
||||||
unsigned pos = parent_ids.back();
|
self_pos = todo.back().m_self;
|
||||||
|
parent_pos = todo.back().m_parent;
|
||||||
|
self_idx = todo.back().m_idx;
|
||||||
n = names.back();
|
n = names.back();
|
||||||
bool checked = is_checked.back();
|
|
||||||
|
|
||||||
if (cache.contains(e)) {
|
if (cache.contains(e)) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (m.is_bool(e) && !checked && simplify_bool(n, res)) {
|
if (m.is_bool(e) && simplify_bool(n, res)) {
|
||||||
TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";);
|
TRACE("ctx_solver_simplify_tactic",
|
||||||
|
tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!is_app(e)) {
|
if (!is_app(e)) {
|
||||||
|
@ -191,45 +200,31 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
a = to_app(e);
|
a = to_app(e);
|
||||||
if (!is_checked.back()) {
|
|
||||||
self_ids.back() = ++path_id;
|
|
||||||
is_checked.back() = true;
|
|
||||||
}
|
|
||||||
self_pos = self_ids.back();
|
|
||||||
sz = a->get_num_args();
|
sz = a->get_num_args();
|
||||||
|
|
||||||
n2 = 0;
|
n2 = 0;
|
||||||
|
|
||||||
found.reset(); // arguments already simplified.
|
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
expr* arg = a->get_arg(i);
|
expr* arg = a->get_arg(i);
|
||||||
if (cache.find(arg, path_r) && !found.contains(arg)) {
|
if (cache.find(arg, path_r)) {
|
||||||
//
|
//
|
||||||
// This is a single traversal version of the context
|
// This is a single traversal version of the context
|
||||||
// simplifier. It simplifies only the first occurrence of
|
// simplifier. It simplifies only the first occurrence of
|
||||||
// a sub-term with respect to the context.
|
// a sub-term with respect to the context.
|
||||||
//
|
//
|
||||||
|
|
||||||
found.push_back(arg);
|
if (path_r.m_parent == self_pos && path_r.m_idx == i) {
|
||||||
if (m.is_bool(arg)) {
|
args.push_back(path_r.m_expr);
|
||||||
res = local_simplify(a, n, id, i);
|
|
||||||
TRACE("ctx_solver_simplify_tactic",
|
|
||||||
tout << "Already cached: " << path_r.first << " " << mk_pp(arg, m) << " |-> " << mk_pp(res, m) << "\n";);
|
|
||||||
args.push_back(res);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
args.push_back(arg);
|
args.push_back(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!n2 && !found.contains(arg)) {
|
else if (!n2) {
|
||||||
n2 = mk_fresh(id, m.get_sort(arg));
|
n2 = mk_fresh(id, m.get_sort(arg));
|
||||||
trail.push_back(n2);
|
trail.push_back(n2);
|
||||||
todo.push_back(arg);
|
todo.push_back(expr_pos(self_pos, child_id++, i, arg));
|
||||||
parent_ids.push_back(self_pos);
|
|
||||||
self_ids.push_back(0);
|
|
||||||
names.push_back(n2);
|
names.push_back(n2);
|
||||||
args.push_back(n2);
|
args.push_back(n2);
|
||||||
is_checked.push_back(false);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
args.push_back(arg);
|
args.push_back(arg);
|
||||||
|
@ -247,22 +242,16 @@ protected:
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (res) {
|
if (res) {
|
||||||
cache.insert(e, std::make_pair(pos, res));
|
cache.insert(e, expr_pos(parent_pos, self_pos, self_idx, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("ctx_solver_simplify_tactic",
|
|
||||||
tout << mk_pp(e, m) << " checked: " << checked << " cached: " << mk_pp(res?res.get():e, m) << "\n";);
|
|
||||||
|
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
parent_ids.pop_back();
|
|
||||||
self_ids.pop_back();
|
|
||||||
names.pop_back();
|
names.pop_back();
|
||||||
is_checked.pop_back();
|
|
||||||
m_solver.pop(1);
|
m_solver.pop(1);
|
||||||
}
|
}
|
||||||
if (!m_cancel) {
|
if (!m_cancel) {
|
||||||
VERIFY(cache.find(fml, path_r));
|
VERIFY(cache.find(fml, path_r));
|
||||||
result = path_r.second;
|
result = path_r.m_expr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,32 +292,6 @@ protected:
|
||||||
return expr_ref(m.mk_app(fn, m_arith.mk_numeral(rational(id++), true)), m);
|
return expr_ref(m.mk_app(fn, m_arith.mk_numeral(rational(id++), true)), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) {
|
|
||||||
SASSERT(index < a->get_num_args());
|
|
||||||
SASSERT(m.is_bool(a->get_arg(index)));
|
|
||||||
expr_ref n2(m), result(m), tmp(m);
|
|
||||||
n2 = mk_fresh(id, m.get_sort(a->get_arg(index)));
|
|
||||||
ptr_buffer<expr> args;
|
|
||||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
|
||||||
if (i == index) {
|
|
||||||
args.push_back(n2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
args.push_back(a->get_arg(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result);
|
|
||||||
m_solver.push();
|
|
||||||
tmp = m.mk_eq(result, n);
|
|
||||||
m_solver.assert_expr(tmp);
|
|
||||||
if (!simplify_bool(n2, result)) {
|
|
||||||
result = a->get_arg(index);
|
|
||||||
}
|
|
||||||
m_solver.pop(1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tactic * mk_ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p) {
|
tactic * mk_ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p) {
|
||||||
|
|
|
@ -1,236 +0,0 @@
|
||||||
/*++
|
|
||||||
Copyright (c) 2013 Microsoft Corporation
|
|
||||||
|
|
||||||
Module Name:
|
|
||||||
|
|
||||||
theory_horn_ineq.h
|
|
||||||
|
|
||||||
Author:
|
|
||||||
|
|
||||||
Nikolaj Bjorner (nbjorner) 2013-04-18
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
The implementaton is derived from theory_diff_logic.
|
|
||||||
|
|
||||||
--*/
|
|
||||||
#include "theory_horn_ineq.h"
|
|
||||||
#include "theory_horn_ineq_def.h"
|
|
||||||
|
|
||||||
namespace smt {
|
|
||||||
|
|
||||||
template class theory_horn_ineq<ihi_ext>;
|
|
||||||
template class theory_horn_ineq<rhi_ext>;
|
|
||||||
|
|
||||||
// similar to test_diff_logic:
|
|
||||||
|
|
||||||
horn_ineq_tester::horn_ineq_tester(ast_manager& m): m(m), a(m) {}
|
|
||||||
|
|
||||||
bool horn_ineq_tester::operator()(expr* e) {
|
|
||||||
m_todo.reset();
|
|
||||||
m_pols.reset();
|
|
||||||
pos_mark.reset();
|
|
||||||
neg_mark.reset();
|
|
||||||
m_todo.push_back(e);
|
|
||||||
m_pols.push_back(l_true);
|
|
||||||
while (!m_todo.empty()) {
|
|
||||||
expr* e = m_todo.back();
|
|
||||||
lbool p = m_pols.back();
|
|
||||||
m_todo.pop_back();
|
|
||||||
m_pols.pop_back();
|
|
||||||
switch (p) {
|
|
||||||
case l_true:
|
|
||||||
if (pos_mark.is_marked(e)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pos_mark.mark(e, true);
|
|
||||||
break;
|
|
||||||
case l_false:
|
|
||||||
if (neg_mark.is_marked(e)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
neg_mark.mark(e, true);
|
|
||||||
break;
|
|
||||||
case l_undef:
|
|
||||||
if (pos_mark.is_marked(e) && neg_mark.is_marked(e)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pos_mark.mark(e, true);
|
|
||||||
neg_mark.mark(e, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!test_expr(p, e)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<std::pair<expr*,rational> > const& horn_ineq_tester::get_linearization() const {
|
|
||||||
return m_terms;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool horn_ineq_tester::test_expr(lbool p, expr* e) {
|
|
||||||
expr* e1, *e2, *e3;
|
|
||||||
if (is_var(e)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!is_app(e)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
app* ap = to_app(e);
|
|
||||||
if (m.is_and(ap) || m.is_or(ap)) {
|
|
||||||
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
|
|
||||||
m_todo.push_back(ap->get_arg(i));
|
|
||||||
m_pols.push_back(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m.is_not(e, e1)) {
|
|
||||||
m_todo.push_back(e);
|
|
||||||
m_pols.push_back(~p);
|
|
||||||
}
|
|
||||||
else if (m.is_ite(e, e1, e2, e3)) {
|
|
||||||
m_todo.push_back(e1);
|
|
||||||
m_pols.push_back(l_undef);
|
|
||||||
m_todo.push_back(e2);
|
|
||||||
m_pols.push_back(p);
|
|
||||||
m_todo.push_back(e3);
|
|
||||||
m_pols.push_back(p);
|
|
||||||
}
|
|
||||||
else if (m.is_iff(e, e1, e2)) {
|
|
||||||
m_todo.push_back(e1);
|
|
||||||
m_pols.push_back(l_undef);
|
|
||||||
m_todo.push_back(e2);
|
|
||||||
m_pols.push_back(l_undef);
|
|
||||||
m_todo.push_back(e2);
|
|
||||||
}
|
|
||||||
else if (m.is_implies(e, e1, e2)) {
|
|
||||||
m_todo.push_back(e1);
|
|
||||||
m_pols.push_back(~p);
|
|
||||||
m_todo.push_back(e2);
|
|
||||||
m_pols.push_back(p);
|
|
||||||
}
|
|
||||||
else if (m.is_eq(e, e1, e2)) {
|
|
||||||
return linearize(e1, e2) == diff;
|
|
||||||
}
|
|
||||||
else if (m.is_true(e) || m.is_false(e)) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
else if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1) ||
|
|
||||||
a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) {
|
|
||||||
if (p == l_false) {
|
|
||||||
std::swap(e2, e1);
|
|
||||||
}
|
|
||||||
classify_t cl = linearize(e1, e2);
|
|
||||||
switch(p) {
|
|
||||||
case l_undef:
|
|
||||||
return cl == diff;
|
|
||||||
case l_true:
|
|
||||||
case l_false:
|
|
||||||
return cl == horn || cl == diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!is_uninterp_const(e)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool horn_ineq_tester::operator()(unsigned num_fmls, expr* const* fmls) {
|
|
||||||
for (unsigned i = 0; i < num_fmls; ++i) {
|
|
||||||
if (!(*this)(fmls[i])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e) {
|
|
||||||
m_terms.reset();
|
|
||||||
m_terms.push_back(std::make_pair(e, rational(1)));
|
|
||||||
return linearize();
|
|
||||||
}
|
|
||||||
|
|
||||||
horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e1, expr* e2) {
|
|
||||||
m_terms.reset();
|
|
||||||
m_terms.push_back(std::make_pair(e1, rational(1)));
|
|
||||||
m_terms.push_back(std::make_pair(e2, rational(-1)));
|
|
||||||
return linearize();
|
|
||||||
}
|
|
||||||
|
|
||||||
horn_ineq_tester::classify_t horn_ineq_tester::linearize() {
|
|
||||||
|
|
||||||
m_weight.reset();
|
|
||||||
m_coeff_map.reset();
|
|
||||||
|
|
||||||
while (!m_terms.empty()) {
|
|
||||||
expr* e1, *e2;
|
|
||||||
rational num;
|
|
||||||
rational mul = m_terms.back().second;
|
|
||||||
expr* e = m_terms.back().first;
|
|
||||||
m_terms.pop_back();
|
|
||||||
if (a.is_add(e)) {
|
|
||||||
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
|
||||||
m_terms.push_back(std::make_pair(to_app(e)->get_arg(i), mul));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (a.is_mul(e, e1, e2) && a.is_numeral(e1, num)) {
|
|
||||||
m_terms.push_back(std::make_pair(e2, mul*num));
|
|
||||||
}
|
|
||||||
else if (a.is_mul(e, e2, e1) && a.is_numeral(e1, num)) {
|
|
||||||
m_terms.push_back(std::make_pair(e2, mul*num));
|
|
||||||
}
|
|
||||||
else if (a.is_sub(e, e1, e2)) {
|
|
||||||
m_terms.push_back(std::make_pair(e1, mul));
|
|
||||||
m_terms.push_back(std::make_pair(e2, -mul));
|
|
||||||
}
|
|
||||||
else if (a.is_uminus(e, e1)) {
|
|
||||||
m_terms.push_back(std::make_pair(e1, -mul));
|
|
||||||
}
|
|
||||||
else if (a.is_numeral(e, num)) {
|
|
||||||
m_weight += num*mul;
|
|
||||||
}
|
|
||||||
else if (a.is_to_real(e, e1)) {
|
|
||||||
m_terms.push_back(std::make_pair(e1, mul));
|
|
||||||
}
|
|
||||||
else if (!is_uninterp_const(e)) {
|
|
||||||
return non_horn;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned num_negative = 0;
|
|
||||||
unsigned num_positive = 0;
|
|
||||||
bool is_unit_pos = true, is_unit_neg = true;
|
|
||||||
obj_map<expr, rational>::iterator it = m_coeff_map.begin();
|
|
||||||
obj_map<expr, rational>::iterator end = m_coeff_map.end();
|
|
||||||
for (; it != end; ++it) {
|
|
||||||
rational r = it->m_value;
|
|
||||||
if (r.is_zero()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_terms.push_back(std::make_pair(it->m_key, r));
|
|
||||||
if (r.is_pos()) {
|
|
||||||
is_unit_pos = is_unit_pos && r.is_one();
|
|
||||||
num_positive++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
is_unit_neg = is_unit_neg && r.is_minus_one();
|
|
||||||
num_negative++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (num_negative <= 1 && is_unit_pos && is_unit_neg && num_positive <= 1) {
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
if (num_positive <= 1 && is_unit_pos) {
|
|
||||||
return horn;
|
|
||||||
}
|
|
||||||
if (num_negative <= 1 && is_unit_neg) {
|
|
||||||
return co_horn;
|
|
||||||
}
|
|
||||||
return non_horn;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,328 +0,0 @@
|
||||||
/*++
|
|
||||||
Copyright (c) 2013 Microsoft Corporation
|
|
||||||
|
|
||||||
Module Name:
|
|
||||||
|
|
||||||
theory_horn_ineq.h
|
|
||||||
|
|
||||||
Abstract:
|
|
||||||
|
|
||||||
A*x <= weight + D*x, coefficients to A and D are non-negative,
|
|
||||||
D is a diagonal matrix.
|
|
||||||
Coefficients to weight may have both signs.
|
|
||||||
|
|
||||||
Label variables by weight.
|
|
||||||
Select inequality that is not satisfied.
|
|
||||||
Set delta(LHS) := 0
|
|
||||||
Set delta(RHS(x)) := weight(x) - b
|
|
||||||
Propagate weight increment through inequalities.
|
|
||||||
|
|
||||||
Author:
|
|
||||||
|
|
||||||
Nikolaj Bjorner (nbjorner) 2013-04-18
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
The implementaton is derived from theory_diff_logic.
|
|
||||||
|
|
||||||
--*/
|
|
||||||
|
|
||||||
#ifndef _THEORY_HORN_INEQ_H_
|
|
||||||
#define _THEORY_HORN_INEQ_H_
|
|
||||||
|
|
||||||
#include"rational.h"
|
|
||||||
#include"inf_rational.h"
|
|
||||||
#include"inf_int_rational.h"
|
|
||||||
#include"inf_eps_rational.h"
|
|
||||||
#include"smt_theory.h"
|
|
||||||
#include"arith_decl_plugin.h"
|
|
||||||
#include"smt_justification.h"
|
|
||||||
#include"map.h"
|
|
||||||
#include"smt_params.h"
|
|
||||||
#include"arith_eq_adapter.h"
|
|
||||||
#include"smt_model_generator.h"
|
|
||||||
#include"numeral_factory.h"
|
|
||||||
#include"smt_clause.h"
|
|
||||||
|
|
||||||
namespace smt {
|
|
||||||
|
|
||||||
class horn_ineq_tester {
|
|
||||||
ast_manager& m;
|
|
||||||
arith_util a;
|
|
||||||
ptr_vector<expr> m_todo;
|
|
||||||
svector<lbool> m_pols;
|
|
||||||
ast_mark pos_mark, neg_mark;
|
|
||||||
obj_map<expr, rational> m_coeff_map;
|
|
||||||
rational m_weight;
|
|
||||||
vector<std::pair<expr*, rational> > m_terms;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum classify_t {
|
|
||||||
co_horn,
|
|
||||||
horn,
|
|
||||||
diff,
|
|
||||||
non_horn
|
|
||||||
};
|
|
||||||
horn_ineq_tester(ast_manager& m);
|
|
||||||
|
|
||||||
// test if formula is in the Horn inequality fragment:
|
|
||||||
bool operator()(expr* fml);
|
|
||||||
bool operator()(unsigned num_fmls, expr* const* fmls);
|
|
||||||
|
|
||||||
// linearize inequality/equality
|
|
||||||
classify_t linearize(expr* e);
|
|
||||||
classify_t linearize(expr* e1, expr* e2);
|
|
||||||
|
|
||||||
// retrieve linearization
|
|
||||||
vector<std::pair<expr*,rational> > const& get_linearization() const;
|
|
||||||
rational const& get_weight() const { return m_weight; }
|
|
||||||
private:
|
|
||||||
bool test_expr(lbool p, expr* e);
|
|
||||||
classify_t linearize();
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
class theory_horn_ineq : public theory, private Ext {
|
|
||||||
|
|
||||||
typedef typename Ext::numeral numeral;
|
|
||||||
typedef typename Ext::inf_numeral inf_numeral;
|
|
||||||
typedef literal explanation;
|
|
||||||
typedef theory_var th_var;
|
|
||||||
typedef svector<th_var> th_var_vector;
|
|
||||||
typedef unsigned clause_id;
|
|
||||||
typedef vector<std::pair<th_var, rational> > coeffs;
|
|
||||||
|
|
||||||
class clause;
|
|
||||||
class graph;
|
|
||||||
class assignment_trail;
|
|
||||||
class parent_trail;
|
|
||||||
|
|
||||||
class atom {
|
|
||||||
protected:
|
|
||||||
bool_var m_bvar;
|
|
||||||
bool m_true;
|
|
||||||
int m_pos;
|
|
||||||
int m_neg;
|
|
||||||
public:
|
|
||||||
atom(bool_var bv, int pos, int neg) :
|
|
||||||
m_bvar(bv), m_true(false),
|
|
||||||
m_pos(pos), m_neg(neg) {}
|
|
||||||
~atom() {}
|
|
||||||
bool_var get_bool_var() const { return m_bvar; }
|
|
||||||
bool is_true() const { return m_true; }
|
|
||||||
void assign_eh(bool is_true) { m_true = is_true; }
|
|
||||||
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
|
|
||||||
int get_pos() const { return m_pos; }
|
|
||||||
int get_neg() const { return m_neg; }
|
|
||||||
std::ostream& display(theory_horn_ineq const& th, std::ostream& out) const;
|
|
||||||
};
|
|
||||||
typedef svector<atom> atoms;
|
|
||||||
|
|
||||||
struct scope {
|
|
||||||
unsigned m_atoms_lim;
|
|
||||||
unsigned m_asserted_atoms_lim;
|
|
||||||
unsigned m_asserted_qhead_old;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct stats {
|
|
||||||
unsigned m_num_conflicts;
|
|
||||||
unsigned m_num_assertions;
|
|
||||||
unsigned m_num_core2th_eqs;
|
|
||||||
unsigned m_num_core2th_diseqs;
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
memset(this, 0, sizeof(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
stats() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
stats m_stats;
|
|
||||||
smt_params m_params;
|
|
||||||
arith_util a;
|
|
||||||
arith_eq_adapter m_arith_eq_adapter;
|
|
||||||
th_var m_zero_int; // cache the variable representing the zero variable.
|
|
||||||
th_var m_zero_real; // cache the variable representing the zero variable.
|
|
||||||
|
|
||||||
graph* m_graph;
|
|
||||||
atoms m_atoms;
|
|
||||||
unsigned_vector m_asserted_atoms; // set of asserted atoms
|
|
||||||
unsigned m_asserted_qhead;
|
|
||||||
u_map<unsigned> m_bool_var2atom;
|
|
||||||
svector<scope> m_scopes;
|
|
||||||
|
|
||||||
double m_agility;
|
|
||||||
bool m_lia;
|
|
||||||
bool m_lra;
|
|
||||||
bool m_non_horn_ineq_exprs;
|
|
||||||
|
|
||||||
horn_ineq_tester m_test;
|
|
||||||
|
|
||||||
|
|
||||||
arith_factory * m_factory;
|
|
||||||
rational m_delta;
|
|
||||||
rational m_lambda;
|
|
||||||
|
|
||||||
|
|
||||||
// Set a conflict due to a negative cycle.
|
|
||||||
void set_neg_cycle_conflict();
|
|
||||||
|
|
||||||
// Create a new theory variable.
|
|
||||||
virtual th_var mk_var(enode* n);
|
|
||||||
|
|
||||||
virtual th_var mk_var(expr* n);
|
|
||||||
|
|
||||||
void compute_delta();
|
|
||||||
|
|
||||||
void found_non_horn_ineq_expr(expr * n);
|
|
||||||
|
|
||||||
bool is_interpreted(app* n) const {
|
|
||||||
return n->get_family_id() == get_family_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
theory_horn_ineq(ast_manager& m);
|
|
||||||
|
|
||||||
virtual ~theory_horn_ineq();
|
|
||||||
|
|
||||||
virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_horn_ineq, get_manager()); }
|
|
||||||
|
|
||||||
virtual char const * get_name() const { return "horn-inequality-logic"; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
\brief See comment in theory::mk_eq_atom
|
|
||||||
*/
|
|
||||||
virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); }
|
|
||||||
|
|
||||||
virtual void init(context * ctx);
|
|
||||||
|
|
||||||
virtual bool internalize_atom(app * atom, bool gate_ctx);
|
|
||||||
|
|
||||||
virtual bool internalize_term(app * term);
|
|
||||||
|
|
||||||
virtual void internalize_eq_eh(app * atom, bool_var v);
|
|
||||||
|
|
||||||
virtual void assign_eh(bool_var v, bool is_true);
|
|
||||||
|
|
||||||
virtual void new_eq_eh(th_var v1, th_var v2) {
|
|
||||||
m_arith_eq_adapter.new_eq_eh(v1, v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool use_diseqs() const { return true; }
|
|
||||||
|
|
||||||
virtual void new_diseq_eh(th_var v1, th_var v2) {
|
|
||||||
m_arith_eq_adapter.new_diseq_eh(v1, v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void push_scope_eh();
|
|
||||||
|
|
||||||
virtual void pop_scope_eh(unsigned num_scopes);
|
|
||||||
|
|
||||||
virtual void restart_eh() {
|
|
||||||
m_arith_eq_adapter.restart_eh();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void relevant_eh(app* e) {}
|
|
||||||
|
|
||||||
virtual void init_search_eh() {
|
|
||||||
m_arith_eq_adapter.init_search_eh();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual final_check_status final_check_eh();
|
|
||||||
|
|
||||||
virtual bool is_shared(th_var v) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool can_propagate() {
|
|
||||||
SASSERT(m_asserted_qhead <= m_asserted_atoms.size());
|
|
||||||
return m_asserted_qhead != m_asserted_atoms.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void propagate();
|
|
||||||
|
|
||||||
virtual justification * why_is_diseq(th_var v1, th_var v2) {
|
|
||||||
UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void reset_eh();
|
|
||||||
|
|
||||||
virtual void init_model(model_generator & m);
|
|
||||||
|
|
||||||
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
|
||||||
|
|
||||||
virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void display(std::ostream & out) const;
|
|
||||||
|
|
||||||
virtual void collect_statistics(::statistics & st) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
virtual void new_eq_eh(th_var v1, th_var v2, justification& j) {
|
|
||||||
m_stats.m_num_core2th_eqs++;
|
|
||||||
new_eq_or_diseq(true, v1, v2, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) {
|
|
||||||
m_stats.m_num_core2th_diseqs++;
|
|
||||||
new_eq_or_diseq(false, v1, v2, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
void negate(coeffs& coeffs, rational& weight);
|
|
||||||
numeral mk_weight(bool is_real, bool is_strict, rational const& w) const;
|
|
||||||
void mk_coeffs(vector<std::pair<expr*,rational> >const& terms, coeffs& coeffs, rational& w);
|
|
||||||
|
|
||||||
void del_atoms(unsigned old_size);
|
|
||||||
|
|
||||||
void propagate_core();
|
|
||||||
|
|
||||||
bool propagate_atom(atom const& a);
|
|
||||||
|
|
||||||
th_var mk_term(app* n);
|
|
||||||
|
|
||||||
th_var mk_num(app* n, rational const& r);
|
|
||||||
|
|
||||||
bool is_consistent() const;
|
|
||||||
|
|
||||||
th_var expand(bool pos, th_var v, rational & k);
|
|
||||||
|
|
||||||
void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just);
|
|
||||||
|
|
||||||
th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; }
|
|
||||||
|
|
||||||
th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); }
|
|
||||||
|
|
||||||
void inc_conflicts();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rhi_ext {
|
|
||||||
typedef inf_rational inf_numeral;
|
|
||||||
typedef inf_eps_rational<inf_rational> numeral;
|
|
||||||
numeral m_epsilon;
|
|
||||||
numeral m_minus_infty;
|
|
||||||
rhi_ext() : m_epsilon(inf_rational(rational(), true)), m_minus_infty(rational(-1),inf_rational()) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ihi_ext {
|
|
||||||
typedef rational inf_numeral;
|
|
||||||
typedef inf_eps_rational<rational> numeral;
|
|
||||||
numeral m_epsilon;
|
|
||||||
numeral m_minus_infty;
|
|
||||||
ihi_ext() : m_epsilon(rational(1)), m_minus_infty(rational(-1),rational(0)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef theory_horn_ineq<rhi_ext> theory_rhi;
|
|
||||||
typedef theory_horn_ineq<ihi_ext> theory_ihi;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _THEORY_HORN_INEQ_H_ */
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue