mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
merged with unstable
This commit is contained in:
commit
3a0947b3ba
413 changed files with 31618 additions and 17204 deletions
|
@ -408,7 +408,7 @@ void asserted_formulas::apply_quasi_macros() {
|
|||
TRACE("before_quasi_macros", display(tout););
|
||||
expr_ref_vector new_exprs(m_manager);
|
||||
proof_ref_vector new_prs(m_manager);
|
||||
quasi_macros proc(m_manager, m_macro_manager, *m_bsimp, m_simplifier);
|
||||
quasi_macros proc(m_manager, m_macro_manager, m_simplifier);
|
||||
while (proc(m_asserted_formulas.size() - m_asserted_qhead,
|
||||
m_asserted_formulas.c_ptr() + m_asserted_qhead,
|
||||
m_asserted_formula_prs.c_ptr() + m_asserted_qhead,
|
||||
|
@ -653,7 +653,7 @@ void asserted_formulas::propagate_values() {
|
|||
// will be (silently) eliminated, and models produced by Z3 will not contain them.
|
||||
flush_cache();
|
||||
}
|
||||
TRACE("propagate_values", tout << "afer:\n"; display(tout););
|
||||
TRACE("propagate_values", tout << "after:\n"; display(tout););
|
||||
}
|
||||
|
||||
void asserted_formulas::propagate_booleans() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
char const * g_pattern_database =
|
||||
static char const * g_pattern_database =
|
||||
"(benchmark patterns \n"
|
||||
" :status unknown \n"
|
||||
" :logic ALL \n"
|
||||
|
|
|
@ -311,4 +311,4 @@
|
|||
(= (?is (?select (?select (?asElems e) a) i)
|
||||
(?elemtype (?typeof a))) 1)
|
||||
:pats { (?select (?select (?asElems e) a) i) })
|
||||
)
|
||||
)
|
||||
|
|
|
@ -21,8 +21,10 @@ Revision History:
|
|||
|
||||
#include"vector.h"
|
||||
#include"heap.h"
|
||||
#include"statistics.h"
|
||||
#include"trace.h"
|
||||
#include"warning.h"
|
||||
#include"uint_set.h"
|
||||
|
||||
typedef int dl_var;
|
||||
|
||||
|
@ -118,7 +120,7 @@ const edge_id null_edge_id = -1;
|
|||
|
||||
template<typename Ext>
|
||||
class dl_graph {
|
||||
struct statistics {
|
||||
struct stats {
|
||||
unsigned m_propagation_cost;
|
||||
unsigned m_implied_literal_cost;
|
||||
unsigned m_num_implied_literals;
|
||||
|
@ -131,16 +133,16 @@ class dl_graph {
|
|||
m_num_helpful_implied_literals = 0;
|
||||
m_num_relax = 0;
|
||||
}
|
||||
statistics() { reset(); }
|
||||
void display(std::ostream& out) const {
|
||||
out << "num. prop. steps. " << m_propagation_cost << "\n";
|
||||
out << "num. impl. steps. " << m_implied_literal_cost << "\n";
|
||||
out << "num. impl. lits. " << m_num_implied_literals << "\n";
|
||||
out << "num. impl. conf lits. " << m_num_helpful_implied_literals << "\n";
|
||||
out << "num. bound relax. " << m_num_relax << "\n";
|
||||
stats() { reset(); }
|
||||
void collect_statistics(::statistics& st) const {
|
||||
st.update("dl prop steps", m_propagation_cost);
|
||||
st.update("dl impl steps", m_implied_literal_cost);
|
||||
st.update("dl impl lits", m_num_implied_literals);
|
||||
st.update("dl impl conf lits", m_num_helpful_implied_literals);
|
||||
st.update("dl bound relax", m_num_relax);
|
||||
}
|
||||
};
|
||||
statistics m_stats;
|
||||
stats m_stats;
|
||||
typedef typename Ext::numeral numeral;
|
||||
typedef typename Ext::explanation explanation;
|
||||
typedef vector<numeral> assignment;
|
||||
|
@ -264,7 +266,6 @@ class dl_graph {
|
|||
m_assignment[e.get_target()] - m_assignment[e.get_source()] <= e.get_weight();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// An assignment is feasible if all edges are feasible.
|
||||
bool is_feasible() const {
|
||||
|
@ -306,14 +307,6 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
// Update the assignment of variable v, that is,
|
||||
// m_assignment[v] += inc
|
||||
// This method also stores the old value of v in the assignment stack.
|
||||
void acc_assignment(dl_var v, const numeral & inc) {
|
||||
TRACE("diff_logic_bug", tout << "update v: " << v << " += " << inc << " m_assignment[v] " << m_assignment[v] << "\n";);
|
||||
m_assignment_stack.push_back(assignment_trail(v, m_assignment[v]));
|
||||
m_assignment[v] += inc;
|
||||
}
|
||||
|
||||
// Restore the assignment using the information in m_assignment_stack.
|
||||
// This method is called when make_feasible fails.
|
||||
|
@ -472,8 +465,9 @@ public:
|
|||
m_bw(m_mark) {
|
||||
}
|
||||
|
||||
void display_statistics(std::ostream& out) const {
|
||||
m_stats.display(out);
|
||||
|
||||
void collect_statistics(::statistics& st) const {
|
||||
m_stats.collect_statistics(st);
|
||||
}
|
||||
|
||||
// Create/Initialize a variable with the given id.
|
||||
|
@ -655,10 +649,8 @@ public:
|
|||
throw default_exception("edges are not inconsistent");
|
||||
}
|
||||
|
||||
#if 1
|
||||
// experimental feature:
|
||||
// allow theory to introduce shortcut lemmas.
|
||||
prune_edges(edges, f);
|
||||
#endif
|
||||
|
||||
for (unsigned i = 0; i < edges.size(); ++i) {
|
||||
edge const& e = m_edges[edges[i]];
|
||||
|
@ -752,7 +744,6 @@ public:
|
|||
f.new_edge(src, dst, idx2-idx1+1, edges.begin()+idx1);
|
||||
}
|
||||
|
||||
|
||||
// Create a new scope.
|
||||
// That is, save the number of edges in the graph.
|
||||
void push() {
|
||||
|
@ -829,6 +820,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Update the assignment of variable v, that is,
|
||||
// m_assignment[v] += inc
|
||||
// This method also stores the old value of v in the assignment stack.
|
||||
void acc_assignment(dl_var v, const numeral & inc) {
|
||||
TRACE("diff_logic_bug", tout << "update v: " << v << " += " << inc << " m_assignment[v] " << m_assignment[v] << "\n";);
|
||||
m_assignment_stack.push_back(assignment_trail(v, m_assignment[v]));
|
||||
m_assignment[v] += inc;
|
||||
}
|
||||
|
||||
|
||||
struct every_var_proc {
|
||||
bool operator()(dl_var v) const {
|
||||
return true;
|
||||
|
@ -839,6 +840,36 @@ public:
|
|||
display_core(out, every_var_proc());
|
||||
}
|
||||
|
||||
void display_agl(std::ostream & out) const {
|
||||
uint_set vars;
|
||||
typename edges::const_iterator it = m_edges.begin();
|
||||
typename edges::const_iterator end = m_edges.end();
|
||||
for (; it != end; ++it) {
|
||||
edge const& e = *it;
|
||||
if (e.is_enabled()) {
|
||||
vars.insert(e.get_source());
|
||||
vars.insert(e.get_target());
|
||||
}
|
||||
}
|
||||
out << "digraph "" {\n";
|
||||
|
||||
unsigned n = m_assignment.size();
|
||||
for (unsigned v = 0; v < n; v++) {
|
||||
if (vars.contains(v)) {
|
||||
out << "\"" << v << "\" [label=\"" << v << ":" << m_assignment[v] << "\"]\n";
|
||||
}
|
||||
}
|
||||
it = m_edges.begin();
|
||||
for (; it != end; ++it) {
|
||||
edge const& e = *it;
|
||||
if (e.is_enabled()) {
|
||||
out << "\"" << e.get_source() << "\"->\"" << e.get_target() << "\"[label=\"" << e.get_weight() << "\"]\n";
|
||||
}
|
||||
}
|
||||
|
||||
out << "}\n";
|
||||
}
|
||||
|
||||
template<typename FilterAssignmentProc>
|
||||
void display_core(std::ostream & out, FilterAssignmentProc p) const {
|
||||
display_edges(out);
|
||||
|
@ -1002,6 +1033,38 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void compute_zero_succ(dl_var v, int_vector& succ) {
|
||||
unsigned n = m_assignment.size();
|
||||
m_dfs_time.reset();
|
||||
m_dfs_time.resize(n, -1);
|
||||
m_dfs_time[v] = 0;
|
||||
succ.push_back(v);
|
||||
numeral gamma;
|
||||
for (unsigned i = 0; i < succ.size(); ++i) {
|
||||
v = succ[i];
|
||||
edge_id_vector & edges = m_out_edges[v];
|
||||
typename edge_id_vector::iterator it = edges.begin();
|
||||
typename edge_id_vector::iterator end = edges.end();
|
||||
for (; it != end; ++it) {
|
||||
edge_id e_id = *it;
|
||||
edge & e = m_edges[e_id];
|
||||
if (!e.is_enabled()) {
|
||||
continue;
|
||||
}
|
||||
SASSERT(e.get_source() == v);
|
||||
set_gamma(e, gamma);
|
||||
if (gamma.is_zero()) {
|
||||
dl_var target = e.get_target();
|
||||
if (m_dfs_time[target] == -1) {
|
||||
succ.push_back(target);
|
||||
m_dfs_time[target] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
numeral get_assignment(dl_var v) const {
|
||||
return m_assignment[v];
|
||||
}
|
||||
|
@ -1643,7 +1706,3 @@ public:
|
|||
|
||||
#endif /* _DIFF_LOGIC_H_ */
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -311,7 +311,7 @@ bool expr_context_simplifier::is_false(expr* e) const {
|
|||
//
|
||||
|
||||
expr_strong_context_simplifier::expr_strong_context_simplifier(smt_params& p, ast_manager& m):
|
||||
m_manager(m), m_params(p), m_arith(m), m_id(0), m_fn(0,m), m_solver(m, p) {
|
||||
m_manager(m), m_arith(m), m_fn(0,m), m_solver(m, p) {
|
||||
sort* i_sort = m_arith.mk_int();
|
||||
m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort());
|
||||
}
|
||||
|
|
|
@ -57,9 +57,7 @@ private:
|
|||
|
||||
class expr_strong_context_simplifier {
|
||||
ast_manager& m_manager;
|
||||
smt_params & m_params;
|
||||
arith_util m_arith;
|
||||
unsigned m_id;
|
||||
func_decl_ref m_fn;
|
||||
smt::kernel m_solver;
|
||||
|
||||
|
|
|
@ -1849,11 +1849,9 @@ namespace smt {
|
|||
unsigned m_curr_max_generation; // temporary var used to store a copy of m_max_generation
|
||||
unsigned m_num_args;
|
||||
unsigned m_oreg;
|
||||
unsigned m_ireg;
|
||||
enode * m_n1;
|
||||
enode * m_n2;
|
||||
enode * m_app;
|
||||
instruction * m_alt;
|
||||
const bind * m_b;
|
||||
ptr_vector<enode> m_used_enodes;
|
||||
unsigned m_curr_used_enodes_size;
|
||||
|
|
|
@ -29,6 +29,7 @@ def_module_params(module_name='smt',
|
|||
('qi.cost', STRING, '(+ weight generation)', 'expression specifying what is the cost of a given quantifier instantiation'),
|
||||
('qi.max_multi_patterns', UINT, 0, 'specify the number of extra multi patterns'),
|
||||
('bv.reflect', BOOL, True, 'create enode for every bit-vector term'),
|
||||
('bv.enable_int2bv', BOOL, False, 'enable support for int2bv and bv2int operators'),
|
||||
('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'),
|
||||
('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination'),
|
||||
('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'),
|
||||
|
|
|
@ -26,7 +26,9 @@ enum arith_solver_id {
|
|||
AS_NO_ARITH,
|
||||
AS_DIFF_LOGIC,
|
||||
AS_ARITH,
|
||||
AS_DENSE_DIFF_LOGIC
|
||||
AS_DENSE_DIFF_LOGIC,
|
||||
AS_UTVPI,
|
||||
AS_HORN
|
||||
};
|
||||
|
||||
enum bound_prop_mode {
|
||||
|
|
|
@ -22,4 +22,5 @@ Revision History:
|
|||
void theory_bv_params::updt_params(params_ref const & _p) {
|
||||
smt_params_helper p(_p);
|
||||
m_bv_reflect = p.bv_reflect();
|
||||
m_bv_enable_int2bv2int = p.bv_enable_int2bv();
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) {
|
|||
value_set * set = get_value_set(s);
|
||||
if (set->empty()) {
|
||||
expr * val = get_some_value(s);
|
||||
SASSERT(val);
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, val);
|
||||
return val;
|
||||
|
@ -185,10 +186,16 @@ expr * datatype_factory::get_fresh_value(sort * s) {
|
|||
if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) {
|
||||
found_sibling = true;
|
||||
expr * maybe_new_arg = get_almost_fresh_value(s_arg);
|
||||
if (!maybe_new_arg) {
|
||||
maybe_new_arg = m_model.get_some_value(s_arg);
|
||||
found_sibling = false;
|
||||
}
|
||||
SASSERT(maybe_new_arg);
|
||||
args.push_back(maybe_new_arg);
|
||||
}
|
||||
else {
|
||||
expr * some_arg = m_model.get_some_value(s_arg);
|
||||
SASSERT(some_arg);
|
||||
args.push_back(some_arg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,10 +180,22 @@ public:
|
|||
value_set * set = get_value_set(s);
|
||||
bool is_new = false;
|
||||
expr * result = 0;
|
||||
sort_info* s_info = s->get_info();
|
||||
sort_size const* sz = s_info?&s_info->get_num_elements():0;
|
||||
bool has_max = false;
|
||||
Number max_size;
|
||||
if (sz && sz->is_finite() && sz->size() < UINT_MAX) {
|
||||
unsigned usz = static_cast<unsigned>(sz->size());
|
||||
max_size = Number(usz);
|
||||
has_max = true;
|
||||
}
|
||||
Number & next = set->m_next;
|
||||
while (!is_new) {
|
||||
result = mk_value(next, s, is_new);
|
||||
next++;
|
||||
if (has_max && next > max_size + set->m_next) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SASSERT(result != 0);
|
||||
return result;
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
obj_map<expr, unsigned> const & get_elems() const { return m_elems; }
|
||||
|
||||
|
||||
void insert(expr * n, unsigned generation) {
|
||||
if (m_elems.contains(n))
|
||||
return;
|
||||
|
@ -102,6 +102,14 @@ namespace smt {
|
|||
m_elems.insert(n, generation);
|
||||
SASSERT(!m_manager.is_model_value(n));
|
||||
}
|
||||
|
||||
void remove(expr * n) {
|
||||
// We can only remove n if it is in m_elems, AND m_inv was not initialized yet.
|
||||
SASSERT(m_elems.contains(n));
|
||||
SASSERT(m_inv.empty());
|
||||
m_elems.erase(n);
|
||||
m_manager.dec_ref(n);
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
obj_map<expr, unsigned>::iterator it = m_elems.begin();
|
||||
|
@ -525,6 +533,30 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
// For each instantiation_set, reemove entries that do not evaluate to values.
|
||||
void cleanup_instantiation_sets() {
|
||||
ptr_vector<expr> to_delete;
|
||||
ptr_vector<node>::const_iterator it = m_nodes.begin();
|
||||
ptr_vector<node>::const_iterator end = m_nodes.end();
|
||||
for (; it != end; ++it) {
|
||||
node * curr = *it;
|
||||
if (curr->is_root()) {
|
||||
instantiation_set * s = curr->get_instantiation_set();
|
||||
to_delete.reset();
|
||||
obj_map<expr, unsigned> const & elems = s->get_elems();
|
||||
for (obj_map<expr, unsigned>::iterator it = elems.begin(); it != elems.end(); it++) {
|
||||
expr * n = it->m_key;
|
||||
expr * n_val = eval(n, true);
|
||||
if (!m_manager.is_value(n_val))
|
||||
to_delete.push_back(n);
|
||||
}
|
||||
for (ptr_vector<expr>::iterator it = to_delete.begin(); it != to_delete.end(); it++) {
|
||||
s->remove(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_nodes(std::ostream & out) const {
|
||||
display_key2node(out, m_uvars);
|
||||
display_A_f_is(out);
|
||||
|
@ -545,6 +577,7 @@ namespace smt {
|
|||
r = 0;
|
||||
else
|
||||
r = tmp;
|
||||
TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";);
|
||||
m_eval_cache.insert(n, r);
|
||||
m_eval_cache_range.push_back(r);
|
||||
return r;
|
||||
|
@ -1047,6 +1080,7 @@ namespace smt {
|
|||
|
||||
public:
|
||||
void fix_model(expr_ref_vector & new_constraints) {
|
||||
cleanup_instantiation_sets();
|
||||
m_new_constraints = &new_constraints;
|
||||
func_decl_set partial_funcs;
|
||||
collect_partial_funcs(partial_funcs);
|
||||
|
@ -1535,8 +1569,23 @@ namespace smt {
|
|||
n1->insert_exception(m_t);
|
||||
}
|
||||
|
||||
virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) {
|
||||
// do nothing...
|
||||
virtual void populate_inst_sets(quantifier * q, auf_solver & slv, context * ctx) {
|
||||
unsigned num_vars = q->get_num_decls();
|
||||
ast_manager & m = ctx->get_manager();
|
||||
sort * s = q->get_decl_sort(num_vars - m_var_i - 1);
|
||||
if (m.is_uninterp(s)) {
|
||||
// For uninterpreted sorst, we add all terms in the context.
|
||||
// See Section 4.1 in the paper "Complete Quantifier Instantiation"
|
||||
node * S_q_i = slv.get_uvar(q, m_var_i);
|
||||
ptr_vector<enode>::const_iterator it = ctx->begin_enodes();
|
||||
ptr_vector<enode>::const_iterator end = ctx->end_enodes();
|
||||
for (; it != end; ++it) {
|
||||
enode * n = *it;
|
||||
if (ctx->is_relevant(n) && get_sort(n->get_owner()) == s) {
|
||||
S_q_i->insert(n->get_owner(), n->get_generation());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1924,7 +1973,8 @@ namespace smt {
|
|||
m_mutil.mk_add(t1, t2, r);
|
||||
}
|
||||
|
||||
bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const {
|
||||
bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) const {
|
||||
inv = false; // true if invert the sign
|
||||
TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m_manager) << " " << mk_ismt2_pp(rhs, m_manager) << "\n";);
|
||||
if (is_var(lhs) && is_ground(rhs)) {
|
||||
v = to_var(lhs);
|
||||
|
@ -1939,7 +1989,6 @@ namespace smt {
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
bool inv = false; // true if invert the sign
|
||||
expr_ref tmp(m_manager);
|
||||
if (is_var_plus_ground(lhs, inv, v, tmp) && is_ground(rhs)) {
|
||||
if (inv)
|
||||
|
@ -1959,6 +2008,11 @@ namespace smt {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const {
|
||||
bool inv;
|
||||
return is_var_and_ground(lhs, rhs, v, t, inv);
|
||||
}
|
||||
|
||||
bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) const {
|
||||
if (!is_app(n))
|
||||
return false;
|
||||
|
@ -2011,22 +2065,28 @@ namespace smt {
|
|||
if (sign) {
|
||||
bool r = is_le_ge(atom) && is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, t);
|
||||
CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n"
|
||||
<< mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";);
|
||||
<< mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";
|
||||
tout << "sign: " << sign << "\n";);
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
if (is_le_ge(atom)) {
|
||||
expr_ref tmp(m_manager);
|
||||
if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp)) {
|
||||
bool le = is_le(atom);
|
||||
bool inv = false;
|
||||
if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp, inv)) {
|
||||
if (inv)
|
||||
le = !le;
|
||||
sort * s = m_manager.get_sort(tmp);
|
||||
expr_ref one(m_manager);
|
||||
one = mk_one(s);
|
||||
if (is_le(atom))
|
||||
if (le)
|
||||
mk_add(tmp, one, t);
|
||||
else
|
||||
mk_sub(tmp, one, t);
|
||||
TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n"
|
||||
<< mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";);
|
||||
<< mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";
|
||||
tout << "sign: " << sign << "\n";);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ Revision History:
|
|||
#include"theory_arith.h"
|
||||
#include"theory_dense_diff_logic.h"
|
||||
#include"theory_diff_logic.h"
|
||||
#include"theory_horn_ineq.h"
|
||||
#include"theory_utvpi.h"
|
||||
#include"theory_array.h"
|
||||
#include"theory_array_full.h"
|
||||
#include"theory_bv.h"
|
||||
|
@ -723,6 +725,18 @@ namespace smt {
|
|||
m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params));
|
||||
}
|
||||
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:
|
||||
if (m_params.m_arith_int_only)
|
||||
m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager));
|
||||
else
|
||||
m_context.register_plugin(alloc(smt::theory_rutvpi, m_manager));
|
||||
break;
|
||||
default:
|
||||
if (m_params.m_arith_int_only)
|
||||
m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
|
||||
|
|
|
@ -23,7 +23,7 @@ Notes:
|
|||
#include"smt_kernel.h"
|
||||
#include"ast_pp.h"
|
||||
#include"mk_simplified_app.h"
|
||||
|
||||
#include"ast_util.h"
|
||||
|
||||
class ctx_solver_simplify_tactic : public tactic {
|
||||
ast_manager& m;
|
||||
|
@ -33,10 +33,14 @@ class ctx_solver_simplify_tactic : public tactic {
|
|||
arith_util m_arith;
|
||||
mk_simplified_app m_mk_app;
|
||||
func_decl_ref m_fn;
|
||||
obj_map<sort, func_decl*> m_fns;
|
||||
unsigned m_num_steps;
|
||||
volatile bool m_cancel;
|
||||
public:
|
||||
ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()):
|
||||
m(m), m_params(p), m_solver(m, m_front_p), m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0) {
|
||||
m(m), m_params(p), m_solver(m, m_front_p),
|
||||
m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0),
|
||||
m_cancel(false) {
|
||||
sort* i_sort = m_arith.mk_int();
|
||||
m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort());
|
||||
}
|
||||
|
@ -45,7 +49,13 @@ public:
|
|||
return alloc(ctx_solver_simplify_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~ctx_solver_simplify_tactic() {}
|
||||
virtual ~ctx_solver_simplify_tactic() {
|
||||
obj_map<sort, func_decl*>::iterator it = m_fns.begin(), end = m_fns.end();
|
||||
for (; it != end; ++it) {
|
||||
m.dec_ref(it->m_value);
|
||||
}
|
||||
m_fns.reset();
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_solver.updt_params(p);
|
||||
|
@ -76,23 +86,53 @@ public:
|
|||
virtual void cleanup() {
|
||||
reset_statistics();
|
||||
m_solver.reset();
|
||||
m_cancel = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
m_solver.set_cancel(f);
|
||||
m_cancel = false;
|
||||
}
|
||||
|
||||
void reduce(goal& g) {
|
||||
SASSERT(g.is_well_sorted());
|
||||
m_num_steps = 0;
|
||||
expr_ref fml(m);
|
||||
tactic_report report("ctx-solver-simplify", g);
|
||||
if (g.inconsistent())
|
||||
return;
|
||||
ptr_vector<expr> fmls;
|
||||
g.get_formulas(fmls);
|
||||
fml = m.mk_and(fmls.size(), fmls.c_ptr());
|
||||
fml = mk_and(m, fmls.size(), fmls.c_ptr());
|
||||
m_solver.push();
|
||||
reduce(fml);
|
||||
m_solver.pop(1);
|
||||
SASSERT(m_solver.get_scope_level() == 0);
|
||||
TRACE("ctx_solver_simplify_tactic",
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
tout << mk_pp(fmls[i], m) << "\n";
|
||||
}
|
||||
tout << "=>\n";
|
||||
tout << mk_pp(fml, m) << "\n";);
|
||||
DEBUG_CODE(
|
||||
{
|
||||
m_solver.push();
|
||||
expr_ref fml1(m);
|
||||
fml1 = mk_and(m, fmls.size(), fmls.c_ptr());
|
||||
fml1 = m.mk_iff(fml, fml1);
|
||||
fml1 = m.mk_not(fml1);
|
||||
m_solver.assert_expr(fml1);
|
||||
lbool is_sat = m_solver.check();
|
||||
TRACE("ctx_solver_simplify_tactic", tout << "is non-equivalence sat?: " << is_sat << "\n";);
|
||||
if (is_sat != l_false) {
|
||||
TRACE("ctx_solver_simplify_tactic",
|
||||
tout << "result is not equivalent to input\n";
|
||||
tout << mk_pp(fml1, m) << "\n";);
|
||||
UNREACHABLE();
|
||||
}
|
||||
m_solver.pop(1);
|
||||
});
|
||||
g.reset();
|
||||
g.assert_expr(fml, 0, 0);
|
||||
IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";);
|
||||
|
@ -106,21 +146,23 @@ protected:
|
|||
svector<bool> is_checked;
|
||||
svector<unsigned> parent_ids, self_ids;
|
||||
expr_ref_vector fresh_vars(m), trail(m);
|
||||
expr_ref res(m);
|
||||
obj_map<expr,std::pair<unsigned, expr*> > cache;
|
||||
expr_ref res(m), tmp(m);
|
||||
obj_map<expr,std::pair<unsigned, expr*> > cache;
|
||||
unsigned id = 1;
|
||||
expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true));
|
||||
expr* n2, *fml;
|
||||
expr_ref n2(m), fml(m);
|
||||
unsigned path_id = 0, self_pos = 0;
|
||||
app * a;
|
||||
unsigned sz;
|
||||
std::pair<unsigned,expr*> path_r;
|
||||
ptr_vector<expr> found;
|
||||
expr_ref_vector args(m);
|
||||
expr_ref n = mk_fresh(id, m.mk_bool_sort());
|
||||
trail.push_back(n);
|
||||
|
||||
fml = result.get();
|
||||
m_solver.assert_expr(m.mk_not(m.mk_iff(fml, n)));
|
||||
tmp = m.mk_not(m.mk_iff(fml, n));
|
||||
m_solver.assert_expr(tmp);
|
||||
|
||||
trail.push_back(n);
|
||||
todo.push_back(fml);
|
||||
names.push_back(n);
|
||||
is_checked.push_back(false);
|
||||
|
@ -128,9 +170,9 @@ protected:
|
|||
self_ids.push_back(0);
|
||||
m_solver.push();
|
||||
|
||||
while (!todo.empty()) {
|
||||
while (!todo.empty() && !m_cancel) {
|
||||
expr_ref res(m);
|
||||
ptr_buffer<expr> args;
|
||||
args.reset();
|
||||
expr* e = todo.back();
|
||||
unsigned pos = parent_ids.back();
|
||||
n = names.back();
|
||||
|
@ -139,11 +181,8 @@ protected:
|
|||
if (cache.contains(e)) {
|
||||
goto done;
|
||||
}
|
||||
if (!m.is_bool(e)) {
|
||||
res = e;
|
||||
goto done;
|
||||
}
|
||||
if (m.is_bool(e) && !checked && simplify_bool(n, res)) {
|
||||
TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";);
|
||||
goto done;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
|
@ -164,35 +203,35 @@ protected:
|
|||
found.reset(); // arguments already simplified.
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr* arg = a->get_arg(i);
|
||||
if (!m.is_bool(arg)) {
|
||||
args.push_back(arg);
|
||||
}
|
||||
else if (cache.find(arg, path_r) && !found.contains(arg)) {
|
||||
if (cache.find(arg, path_r) && !found.contains(arg)) {
|
||||
//
|
||||
// This is a single traversal version of the context
|
||||
// simplifier. It simplifies only the first occurrence of
|
||||
// a formula with respect to the context.
|
||||
// a sub-term with respect to the context.
|
||||
//
|
||||
|
||||
found.push_back(arg);
|
||||
if (path_r.first == self_pos) {
|
||||
TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << "\n";);
|
||||
TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";);
|
||||
args.push_back(path_r.second);
|
||||
}
|
||||
else {
|
||||
else if (m.is_bool(arg)) {
|
||||
res = local_simplify(a, n, id, i);
|
||||
TRACE("ctx_solver_simplify_tactic",
|
||||
tout << "Already cached: " << path_r.first << " " << mk_pp(res, m) << "\n";);
|
||||
tout << "Already cached: " << path_r.first << " " << mk_pp(arg, m) << " |-> " << mk_pp(res, m) << "\n";);
|
||||
args.push_back(res);
|
||||
}
|
||||
else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
else if (!n2 && !found.contains(arg)) {
|
||||
n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true));
|
||||
n2 = mk_fresh(id, m.get_sort(arg));
|
||||
trail.push_back(n2);
|
||||
todo.push_back(arg);
|
||||
parent_ids.push_back(self_pos);
|
||||
self_ids.push_back(0);
|
||||
names.push_back(n2);
|
||||
trail.push_back(n2);
|
||||
args.push_back(n2);
|
||||
is_checked.push_back(false);
|
||||
}
|
||||
|
@ -205,7 +244,8 @@ protected:
|
|||
// child needs to be visited.
|
||||
if (n2) {
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(m.mk_eq(res, n));
|
||||
tmp = m.mk_eq(res, n);
|
||||
m_solver.assert_expr(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -224,12 +264,14 @@ protected:
|
|||
is_checked.pop_back();
|
||||
m_solver.pop(1);
|
||||
}
|
||||
VERIFY(cache.find(fml, path_r));
|
||||
result = path_r.second;
|
||||
if (!m_cancel) {
|
||||
VERIFY(cache.find(fml, path_r));
|
||||
result = path_r.second;
|
||||
}
|
||||
}
|
||||
|
||||
bool simplify_bool(expr* n, expr_ref& res) {
|
||||
|
||||
expr_ref tmp(m);
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(n);
|
||||
lbool is_sat = m_solver.check();
|
||||
|
@ -240,7 +282,8 @@ protected:
|
|||
}
|
||||
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(m.mk_not(n));
|
||||
tmp = m.mk_not(n);
|
||||
m_solver.assert_expr(tmp);
|
||||
is_sat = m_solver.check();
|
||||
m_solver.pop(1);
|
||||
if (is_sat == l_false) {
|
||||
|
@ -251,11 +294,25 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
expr_ref mk_fresh(unsigned& id, sort* s) {
|
||||
func_decl* fn;
|
||||
if (m.is_bool(s)) {
|
||||
fn = m_fn;
|
||||
}
|
||||
else if (!m_fns.find(s, fn)) {
|
||||
fn = m.mk_func_decl(symbol(0xbeef101 + id), m_arith.mk_int(), s);
|
||||
m.inc_ref(fn);
|
||||
m_fns.insert(s, fn);
|
||||
}
|
||||
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);
|
||||
n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true));
|
||||
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) {
|
||||
|
@ -267,9 +324,10 @@ protected:
|
|||
}
|
||||
m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result);
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(m.mk_eq(result, n));
|
||||
tmp = m.mk_eq(result, n);
|
||||
m_solver.assert_expr(tmp);
|
||||
if (!simplify_bool(n2, result)) {
|
||||
result = a;
|
||||
result = a->get_arg(index);
|
||||
}
|
||||
m_solver.pop(1);
|
||||
return result;
|
||||
|
|
151
src/smt/tactic/unit_subsumption_tactic.cpp
Normal file
151
src/smt/tactic/unit_subsumption_tactic.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
unit_subsumption_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Simplify goal using subsumption based on unit propagation.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-9-6
|
||||
|
||||
--*/
|
||||
|
||||
#include "unit_subsumption_tactic.h"
|
||||
#include "smt_context.h"
|
||||
|
||||
struct unit_subsumption_tactic : public tactic {
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
smt_params m_fparams;
|
||||
volatile bool m_cancel;
|
||||
smt::context m_context;
|
||||
expr_ref_vector m_clauses;
|
||||
unsigned m_clause_count;
|
||||
bit_vector m_is_deleted;
|
||||
unsigned_vector m_deleted;
|
||||
|
||||
unit_subsumption_tactic(
|
||||
ast_manager& m,
|
||||
params_ref const& p):
|
||||
m(m),
|
||||
m_params(p),
|
||||
m_cancel(false),
|
||||
m_context(m, m_fparams, p),
|
||||
m_clauses(m) {
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
m_context.set_cancel_flag(f);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
set_cancel(false);
|
||||
}
|
||||
|
||||
virtual void operator()(/* in */ goal_ref const & in,
|
||||
/* out */ goal_ref_buffer & result,
|
||||
/* out */ model_converter_ref & mc,
|
||||
/* out */ proof_converter_ref & pc,
|
||||
/* out */ expr_dependency_ref & core) {
|
||||
reduce_core(in, result);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const& p) {
|
||||
m_params = p;
|
||||
// m_context.updt_params(p); does not exist.
|
||||
}
|
||||
|
||||
virtual tactic* translate(ast_manager& m) {
|
||||
return alloc(unit_subsumption_tactic, m, m_params);
|
||||
}
|
||||
|
||||
void checkpoint() {
|
||||
if (m_cancel) {
|
||||
throw tactic_exception(TACTIC_CANCELED_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
void reduce_core(goal_ref const& g, goal_ref_buffer& result) {
|
||||
init(g);
|
||||
m_context.push();
|
||||
assert_clauses(g);
|
||||
m_context.push(); // internalize assertions.
|
||||
prune_clauses();
|
||||
goal_ref r(g);
|
||||
insert_result(r);
|
||||
r->elim_true();
|
||||
result.push_back(r.get());
|
||||
m_context.pop(2);
|
||||
TRACE("unit_subsumption_tactic", g->display(tout); r->display(tout););
|
||||
}
|
||||
|
||||
void assert_clauses(goal_ref const& g) {
|
||||
for (unsigned i = 0; i < g->size(); ++i) {
|
||||
m_context.assert_expr(m.mk_iff(new_clause(), g->form(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void prune_clauses() {
|
||||
for (unsigned i = 0; i < m_clause_count; ++i) {
|
||||
prune_clause(i);
|
||||
}
|
||||
}
|
||||
|
||||
void prune_clause(unsigned i) {
|
||||
m_context.push();
|
||||
for (unsigned j = 0; j < m_clause_count; ++j) {
|
||||
if (i == j) {
|
||||
m_context.assert_expr(m.mk_not(m_clauses[j].get()));
|
||||
}
|
||||
else if (!m_is_deleted.get(j)) {
|
||||
m_context.assert_expr(m_clauses[j].get());
|
||||
}
|
||||
}
|
||||
m_context.push(); // force propagation
|
||||
bool is_unsat = m_context.inconsistent();
|
||||
m_context.pop(2);
|
||||
if (is_unsat) {
|
||||
TRACE("unit_subsumption_tactic", tout << "Removing clause " << i << "\n";);
|
||||
m_is_deleted.set(i, true);
|
||||
m_deleted.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void insert_result(goal_ref& result) {
|
||||
for (unsigned i = 0; i < m_deleted.size(); ++i) {
|
||||
result->update(m_deleted[i], m.mk_true()); // TBD proof?
|
||||
}
|
||||
}
|
||||
|
||||
void init(goal_ref const& g) {
|
||||
m_clause_count = 0;
|
||||
m_is_deleted.reset();
|
||||
m_is_deleted.resize(g->size());
|
||||
m_deleted.reset();
|
||||
}
|
||||
|
||||
expr* new_bool(unsigned& count, expr_ref_vector& v, char const* name) {
|
||||
SASSERT(count <= v.size());
|
||||
if (count == v.size()) {
|
||||
v.push_back(m.mk_fresh_const(name, m.mk_bool_sort()));
|
||||
}
|
||||
return v[count++].get();
|
||||
}
|
||||
|
||||
expr* new_clause() {
|
||||
return new_bool(m_clause_count, m_clauses, "#clause");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
tactic * mk_unit_subsumption_tactic(ast_manager & m, params_ref const & p) {
|
||||
return alloc(unit_subsumption_tactic, m, p);
|
||||
}
|
||||
|
33
src/smt/tactic/unit_subsumption_tactic.h
Normal file
33
src/smt/tactic/unit_subsumption_tactic.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
unit_subsumption_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Simplify goal using subsumption based on unit propagation.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-9-6
|
||||
|
||||
Notes:
|
||||
|
||||
Background: PDR generates several clauses that subsume each-other.
|
||||
Simplify a goal assuming it is a conjunction of clauses.
|
||||
Subsumed clauses are simplified by using unit-propagation
|
||||
It uses the smt_context for the solver.
|
||||
|
||||
--*/
|
||||
#ifndef _UNIT_SUBSUMPTION_TACTIC_H_
|
||||
#define _UNIT_SUBSUMPTION_TACTIC_H_
|
||||
#include "tactic.h"
|
||||
|
||||
tactic * mk_unit_subsumption_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
/*
|
||||
ADD_TACTIC("unit-subsume-simplify", "unit subsumption simplification.", "mk_unit_subsumption_tactic(m, p)")
|
||||
*/
|
||||
|
||||
#endif
|
|
@ -408,7 +408,7 @@ namespace smt {
|
|||
mk_axiom(eqz, upper);
|
||||
rational k;
|
||||
if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) &&
|
||||
k.is_pos() && k < rational(512)) {
|
||||
k.is_pos() && k < rational(8)) {
|
||||
rational j(0);
|
||||
#if 1
|
||||
literal_buffer lits;
|
||||
|
|
|
@ -688,7 +688,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void theory_array_base::propagate_select_to_store_parents(enode * r, enode * sel, svector<enode_pair> & todo) {
|
||||
SASSERT(r->get_root() == r);
|
||||
SASSERT(is_select(sel));
|
||||
|
@ -880,7 +880,7 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
theory_var r = mg_find(v);
|
||||
void * else_val = m_else_values[r];
|
||||
void * else_val = m_else_values[r];
|
||||
// DISABLED. It seems wrong, since different nodes can share the same
|
||||
// else_val according to the mg class.
|
||||
// SASSERT(else_val == 0 || get_context().is_relevant(UNTAG(app*, else_val)));
|
||||
|
|
|
@ -46,7 +46,6 @@ namespace smt {
|
|||
unsigned m_num_conflicts;
|
||||
unsigned m_num_assertions;
|
||||
unsigned m_num_th2core_eqs;
|
||||
unsigned m_num_th2core_prop;
|
||||
|
||||
unsigned m_num_core2th_eqs;
|
||||
unsigned m_num_core2th_diseqs;
|
||||
|
@ -59,109 +58,30 @@ namespace smt {
|
|||
}
|
||||
};
|
||||
|
||||
class dl_conflict : public simple_justification {
|
||||
public:
|
||||
dl_conflict(region & r, unsigned nls, literal const * lits): simple_justification(r, nls, lits) { }
|
||||
|
||||
virtual proof * mk_proof(conflict_resolution & cr) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
class theory_diff_logic : public theory, private Ext {
|
||||
|
||||
typedef typename Ext::numeral numeral;
|
||||
|
||||
class implied_eq_justification : public justification {
|
||||
theory_diff_logic & m_theory;
|
||||
theory_var m_v1;
|
||||
theory_var m_v2;
|
||||
unsigned m_timestamp;
|
||||
public:
|
||||
implied_eq_justification(theory_diff_logic & theory, theory_var v1, theory_var v2, unsigned ts):
|
||||
m_theory(theory),
|
||||
m_v1(v1),
|
||||
m_v2(v2),
|
||||
m_timestamp(ts) {
|
||||
}
|
||||
|
||||
virtual void get_antecedents(conflict_resolution & cr) {
|
||||
m_theory.get_eq_antecedents(m_v1, m_v2, m_timestamp, cr);
|
||||
}
|
||||
|
||||
virtual proof * mk_proof(conflict_resolution & cr) { NOT_IMPLEMENTED_YET(); return 0; }
|
||||
};
|
||||
|
||||
class implied_bound_justification : public justification {
|
||||
theory_diff_logic& m_theory;
|
||||
edge_id m_subsumed_edge;
|
||||
edge_id m_bridge_edge;
|
||||
public:
|
||||
implied_bound_justification(theory_diff_logic & theory, edge_id se, edge_id be):
|
||||
m_theory(theory),
|
||||
m_subsumed_edge(se),
|
||||
m_bridge_edge(be) {
|
||||
}
|
||||
|
||||
virtual void get_antecedents(conflict_resolution & cr) {
|
||||
m_theory.get_implied_bound_antecedents(m_bridge_edge, m_subsumed_edge, cr);
|
||||
}
|
||||
|
||||
virtual proof * mk_proof(conflict_resolution & cr) { NOT_IMPLEMENTED_YET(); return 0; }
|
||||
};
|
||||
|
||||
enum atom_kind {
|
||||
LE_ATOM,
|
||||
EQ_ATOM
|
||||
};
|
||||
|
||||
class atom {
|
||||
protected:
|
||||
atom_kind m_kind;
|
||||
bool_var m_bvar;
|
||||
bool m_true;
|
||||
int m_pos;
|
||||
int m_neg;
|
||||
public:
|
||||
atom(atom_kind k, bool_var bv) : m_kind(k), m_bvar(bv), m_true(false) {}
|
||||
virtual ~atom() {}
|
||||
atom_kind kind() const { return m_kind; }
|
||||
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; }
|
||||
virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
||||
};
|
||||
|
||||
class le_atom : public atom {
|
||||
int m_pos;
|
||||
int m_neg;
|
||||
public:
|
||||
le_atom(bool_var bv, int pos, int neg):
|
||||
atom(LE_ATOM, bv),
|
||||
atom(bool_var bv, int pos, int neg):
|
||||
m_bvar(bv), m_true(false),
|
||||
m_pos(pos),
|
||||
m_neg(neg) {
|
||||
}
|
||||
virtual ~le_atom() {}
|
||||
~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; }
|
||||
virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
||||
};
|
||||
|
||||
class eq_atom : public atom {
|
||||
app_ref m_le;
|
||||
app_ref m_ge;
|
||||
public:
|
||||
eq_atom(bool_var bv, app_ref& le, app_ref& ge):
|
||||
atom(EQ_ATOM, bv),
|
||||
m_le(le),
|
||||
m_ge(ge)
|
||||
{}
|
||||
virtual ~eq_atom() {}
|
||||
virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
||||
app* get_le() const { return m_le.get(); }
|
||||
app* get_ge() const { return m_ge.get(); }
|
||||
std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
||||
};
|
||||
|
||||
typedef ptr_vector<atom> atoms;
|
||||
|
@ -239,19 +159,7 @@ namespace smt {
|
|||
unsigned m_asserted_qhead_old;
|
||||
};
|
||||
|
||||
class theory_diff_logic_del_eh : public clause_del_eh {
|
||||
theory_diff_logic& m_super;
|
||||
public:
|
||||
theory_diff_logic_del_eh(theory_diff_logic& s) : m_super(s) {}
|
||||
virtual ~theory_diff_logic_del_eh() {}
|
||||
virtual void operator()(ast_manager&, clause* cls) {
|
||||
TRACE("dl_activity", tout << "deleting " << cls << "\n";);
|
||||
m_super.del_clause_eh(cls);
|
||||
dealloc(this);
|
||||
}
|
||||
};
|
||||
|
||||
smt_params & m_params;
|
||||
smt_params & m_params;
|
||||
arith_util m_util;
|
||||
arith_eq_adapter m_arith_eq_adapter;
|
||||
theory_diff_logic_statistics m_stats;
|
||||
|
@ -259,8 +167,6 @@ namespace smt {
|
|||
theory_var m_zero_int; // cache the variable representing the zero variable.
|
||||
theory_var m_zero_real; // cache the variable representing the zero variable.
|
||||
int_vector m_scc_id; // Cheap equality propagation
|
||||
bool m_modified_since_eq_prop; // true if new constraints were asserted
|
||||
// since last eq propagation.
|
||||
eq_prop_info_set m_eq_prop_info_set; // set of existing equality prop infos
|
||||
ptr_vector<eq_prop_info> m_eq_prop_infos;
|
||||
|
||||
|
@ -289,20 +195,14 @@ namespace smt {
|
|||
virtual theory_var mk_var(enode* n);
|
||||
|
||||
virtual theory_var mk_var(app* n);
|
||||
|
||||
void mark_as_modified_since_eq_prop();
|
||||
|
||||
void unmark_as_modified_since_eq_prop();
|
||||
|
||||
bool propagate_cheap_equalities();
|
||||
|
||||
|
||||
void compute_delta();
|
||||
|
||||
void found_non_diff_logic_expr(expr * n);
|
||||
|
||||
bool is_interpreted(app* n) const;
|
||||
|
||||
void del_clause_eh(clause* cls);
|
||||
bool is_interpreted(app* n) const {
|
||||
return get_family_id() == n->get_family_id();
|
||||
}
|
||||
|
||||
public:
|
||||
theory_diff_logic(ast_manager& m, smt_params & params):
|
||||
|
@ -312,7 +212,6 @@ namespace smt {
|
|||
m_arith_eq_adapter(*this, params, m_util),
|
||||
m_zero_int(null_theory_var),
|
||||
m_zero_real(null_theory_var),
|
||||
m_modified_since_eq_prop(false),
|
||||
m_asserted_qhead(0),
|
||||
m_num_core_conflicts(0),
|
||||
m_num_propagation_calls(0),
|
||||
|
@ -323,7 +222,7 @@ namespace smt {
|
|||
m_nc_functor(*this) {
|
||||
}
|
||||
|
||||
~theory_diff_logic() {
|
||||
virtual ~theory_diff_logic() {
|
||||
reset_eh();
|
||||
}
|
||||
|
||||
|
@ -360,7 +259,7 @@ namespace smt {
|
|||
m_arith_eq_adapter.restart_eh();
|
||||
}
|
||||
|
||||
virtual void relevant_eh(app* e);
|
||||
virtual void relevant_eh(app* e) {}
|
||||
|
||||
virtual void init_search_eh() {
|
||||
m_arith_eq_adapter.init_search_eh();
|
||||
|
|
|
@ -31,34 +31,15 @@ Revision History:
|
|||
|
||||
using namespace smt;
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
std::ostream& theory_diff_logic<Ext>::atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
||||
std::ostream& theory_diff_logic<Ext>::atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
||||
context& ctx = th.get_context();
|
||||
lbool asgn = ctx.get_assignment(m_bvar);
|
||||
//SASSERT(asgn == l_undef || ((asgn == l_true) == m_true));
|
||||
bool sign = (l_undef == asgn) || m_true;
|
||||
return out << literal(m_bvar, sign)
|
||||
<< " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " ";
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
std::ostream& theory_diff_logic<Ext>::eq_atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
||||
atom::display(th, out);
|
||||
lbool asgn = th.get_context().get_assignment(this->m_bvar);
|
||||
if (l_undef == asgn) {
|
||||
out << "unassigned\n";
|
||||
}
|
||||
else {
|
||||
out << mk_pp(m_le.get(), m_le.get_manager()) << " "
|
||||
<< mk_pp(m_ge.get(), m_ge.get_manager()) << "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
std::ostream& theory_diff_logic<Ext>::le_atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
||||
atom::display(th, out);
|
||||
lbool asgn = th.get_context().get_assignment(this->m_bvar);
|
||||
if (l_undef == asgn) {
|
||||
out << "unassigned\n";
|
||||
}
|
||||
|
@ -94,7 +75,6 @@ void theory_diff_logic<Ext>::init(context * ctx) {
|
|||
e = ctx->mk_enode(zero, false, false, true);
|
||||
SASSERT(!is_attached_to_var(e));
|
||||
m_zero_real = mk_var(e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -277,7 +257,7 @@ bool theory_diff_logic<Ext>::internalize_atom(app * n, bool gate_ctx) {
|
|||
k -= this->m_epsilon;
|
||||
}
|
||||
edge_id neg = m_graph.add_edge(target, source, k, ~l);
|
||||
le_atom * a = alloc(le_atom, bv, pos, neg);
|
||||
atom * a = alloc(atom, bv, pos, neg);
|
||||
m_atoms.push_back(a);
|
||||
m_bool_var2atom.insert(bv, a);
|
||||
|
||||
|
@ -318,7 +298,7 @@ template<typename Ext>
|
|||
void theory_diff_logic<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||
m_stats.m_num_assertions++;
|
||||
atom * a = 0;
|
||||
m_bool_var2atom.find(v, a);
|
||||
VERIFY (m_bool_var2atom.find(v, a));
|
||||
SASSERT(a);
|
||||
SASSERT(get_context().get_assignment(v) != l_undef);
|
||||
SASSERT((get_context().get_assignment(v) == l_true) == is_true);
|
||||
|
@ -330,10 +310,11 @@ void theory_diff_logic<Ext>::assign_eh(bool_var v, bool is_true) {
|
|||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::collect_statistics(::statistics & st) const {
|
||||
st.update("dl conflicts", m_stats.m_num_conflicts);
|
||||
st.update("dl propagations", m_stats.m_num_th2core_prop);
|
||||
st.update("dl asserts", m_stats.m_num_assertions);
|
||||
st.update("core->dl eqs", m_stats.m_num_core2th_eqs);
|
||||
st.update("core->dl diseqs", m_stats.m_num_core2th_diseqs);
|
||||
m_arith_eq_adapter.collect_statistics(st);
|
||||
m_graph.collect_statistics(st);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
|
@ -374,15 +355,6 @@ final_check_status theory_diff_logic<Ext>::final_check_eh() {
|
|||
// either will already be zero (as we don't do mixed constraints).
|
||||
m_graph.set_to_zero(m_zero_int, m_zero_real);
|
||||
SASSERT(is_consistent());
|
||||
|
||||
|
||||
#if 0
|
||||
TBD:
|
||||
if (propagate_cheap_equalities()) {
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_non_diff_logic_exprs) {
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
|
@ -506,61 +478,14 @@ bool theory_diff_logic<Ext>::propagate_atom(atom* a) {
|
|||
if (ctx.inconsistent()) {
|
||||
return false;
|
||||
}
|
||||
switch(a->kind()) {
|
||||
case LE_ATOM: {
|
||||
int edge_id = dynamic_cast<le_atom*>(a)->get_asserted_edge();
|
||||
if (!m_graph.enable_edge(edge_id)) {
|
||||
set_neg_cycle_conflict();
|
||||
return false;
|
||||
}
|
||||
#if 0
|
||||
if (m_params.m_arith_bound_prop != BP_NONE) {
|
||||
svector<int> subsumed;
|
||||
m_graph.find_subsumed1(edge_id, subsumed);
|
||||
for (unsigned i = 0; i < subsumed.size(); ++i) {
|
||||
int subsumed_edge_id = subsumed[i];
|
||||
literal l = m_graph.get_explanation(subsumed_edge_id);
|
||||
context & ctx = get_context();
|
||||
region& r = ctx.get_region();
|
||||
++m_stats.m_num_th2core_prop;
|
||||
ctx.assign(l, new (r) implied_bound_justification(*this, subsumed_edge_id, edge_id));
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case EQ_ATOM:
|
||||
if (!a->is_true()) {
|
||||
SASSERT(ctx.get_assignment(a->get_bool_var()) == l_false);
|
||||
// eq_atom * ea = dynamic_cast<eq_atom*>(a);
|
||||
}
|
||||
break;
|
||||
int edge_id = a->get_asserted_edge();
|
||||
if (!m_graph.enable_edge(edge_id)) {
|
||||
set_neg_cycle_conflict();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::mark_as_modified_since_eq_prop() {
|
||||
if (!m_modified_since_eq_prop) {
|
||||
get_context().push_trail(value_trail<context, bool>(m_modified_since_eq_prop));
|
||||
m_modified_since_eq_prop = true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::unmark_as_modified_since_eq_prop() {
|
||||
get_context().push_trail(value_trail<context, bool>(m_modified_since_eq_prop));
|
||||
m_modified_since_eq_prop = false;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::del_clause_eh(clause* cls) {
|
||||
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {
|
||||
|
||||
|
@ -609,7 +534,7 @@ void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges
|
|||
atom* a = 0;
|
||||
m_bool_var2atom.find(bv, a);
|
||||
SASSERT(a);
|
||||
edge_id e_id = static_cast<le_atom*>(a)->get_pos();
|
||||
edge_id e_id = a->get_pos();
|
||||
|
||||
literal_vector lits;
|
||||
for (unsigned i = 0; i < num_edges; ++i) {
|
||||
|
@ -633,11 +558,7 @@ void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges
|
|||
lits.size(), lits.c_ptr(),
|
||||
params.size(), params.c_ptr());
|
||||
}
|
||||
clause_del_eh* del_eh = alloc(theory_diff_logic_del_eh, *this);
|
||||
clause* cls = ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, del_eh);
|
||||
if (!cls) {
|
||||
dealloc(del_eh);
|
||||
}
|
||||
ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0);
|
||||
if (dump_lemmas()) {
|
||||
char const * logic = m_is_lia ? "QF_LIA" : "QF_LRA";
|
||||
ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic);
|
||||
|
@ -677,7 +598,6 @@ void theory_diff_logic<Ext>::set_neg_cycle_conflict() {
|
|||
literal_vector const& lits = m_nc_functor.get_lits();
|
||||
context & ctx = get_context();
|
||||
TRACE("arith_conflict",
|
||||
//display(tout);
|
||||
tout << "conflict: ";
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ctx.display_literal_info(tout, lits[i]);
|
||||
|
@ -802,7 +722,6 @@ theory_var theory_diff_logic<Ext>::mk_num(app* n, rational const& r) {
|
|||
|
||||
template<typename Ext>
|
||||
theory_var theory_diff_logic<Ext>::mk_var(enode* n) {
|
||||
mark_as_modified_since_eq_prop();
|
||||
theory_var v = theory::mk_var(n);
|
||||
TRACE("diff_logic_vars", tout << "mk_var: " << v << "\n";);
|
||||
m_graph.init_var(v);
|
||||
|
@ -810,10 +729,6 @@ theory_var theory_diff_logic<Ext>::mk_var(enode* n) {
|
|||
return v;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_diff_logic<Ext>::is_interpreted(app* n) const {
|
||||
return n->get_family_id() == get_family_id();
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
theory_var theory_diff_logic<Ext>::mk_var(app* n) {
|
||||
|
@ -854,7 +769,6 @@ void theory_diff_logic<Ext>::reset_eh() {
|
|||
m_asserted_atoms .reset();
|
||||
m_stats .reset();
|
||||
m_scopes .reset();
|
||||
m_modified_since_eq_prop = false;
|
||||
m_asserted_qhead = 0;
|
||||
m_num_core_conflicts = 0;
|
||||
m_num_propagation_calls = 0;
|
||||
|
@ -865,70 +779,6 @@ void theory_diff_logic<Ext>::reset_eh() {
|
|||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_diff_logic<Ext>::propagate_cheap_equalities() {
|
||||
bool result = false;
|
||||
TRACE("dl_new_eq", get_context().display(tout););
|
||||
context& ctx = get_context();
|
||||
region& reg = ctx.get_region();
|
||||
SASSERT(m_eq_prop_info_set.empty());
|
||||
SASSERT(m_eq_prop_infos.empty());
|
||||
if (m_modified_since_eq_prop) {
|
||||
m_graph.compute_zero_edge_scc(m_scc_id);
|
||||
int n = get_num_vars();
|
||||
for (theory_var v = 0; v < n; v++) {
|
||||
rational delta_r;
|
||||
theory_var x_v = expand(true, v, delta_r);
|
||||
numeral delta(delta_r);
|
||||
int scc_id = m_scc_id[x_v];
|
||||
if (scc_id != -1) {
|
||||
delta += m_graph.get_assignment(x_v);
|
||||
TRACE("eq_scc", tout << v << " " << x_v << " " << scc_id << " " << delta << "\n";);
|
||||
eq_prop_info info(scc_id, delta);
|
||||
typename eq_prop_info_set::entry * entry = m_eq_prop_info_set.find_core(&info);
|
||||
if (entry == 0) {
|
||||
eq_prop_info * new_info = alloc(eq_prop_info, scc_id, delta, v);
|
||||
m_eq_prop_info_set.insert(new_info);
|
||||
m_eq_prop_infos.push_back(new_info);
|
||||
}
|
||||
else {
|
||||
// new equality found
|
||||
theory_var r = entry->get_data()->get_root();
|
||||
|
||||
enode * n1 = get_enode(v);
|
||||
enode * n2 = get_enode(r);
|
||||
if (n1->get_root() != n2->get_root()) {
|
||||
// r may be an alias (i.e., it is not realy in the graph). So, I should expand it.
|
||||
// nsb: ??
|
||||
rational r_delta;
|
||||
theory_var x_r = expand(true, r, r_delta);
|
||||
|
||||
justification* j = new (reg) implied_eq_justification(*this, x_v, x_r, m_graph.get_timestamp());
|
||||
(void)j;
|
||||
|
||||
m_stats.m_num_th2core_eqs++;
|
||||
// TBD: get equality into core.
|
||||
|
||||
NOT_IMPLEMENTED_YET();
|
||||
// new_eq_eh(x_v, x_r, *j);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_eq_prop_info_set.reset();
|
||||
std::for_each(m_eq_prop_infos.begin(), m_eq_prop_infos.end(), delete_proc<eq_prop_info>());
|
||||
m_eq_prop_infos.reset();
|
||||
unmark_as_modified_since_eq_prop();
|
||||
}
|
||||
|
||||
TRACE("dl_new_eq", get_context().display(tout););
|
||||
SASSERT(!m_modified_since_eq_prop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::compute_delta() {
|
||||
m_delta = rational(1);
|
||||
|
@ -1001,30 +851,9 @@ bool theory_diff_logic<Ext>::is_consistent() const {
|
|||
lbool asgn = ctx.get_assignment(bv);
|
||||
if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) {
|
||||
SASSERT((asgn == l_true) == a->is_true());
|
||||
switch(a->kind()) {
|
||||
case LE_ATOM: {
|
||||
le_atom* le = dynamic_cast<le_atom*>(a);
|
||||
int edge_id = le->get_asserted_edge();
|
||||
SASSERT(m_graph.is_enabled(edge_id));
|
||||
SASSERT(m_graph.is_feasible(edge_id));
|
||||
break;
|
||||
}
|
||||
case EQ_ATOM: {
|
||||
eq_atom* ea = dynamic_cast<eq_atom*>(a);
|
||||
bool_var bv1 = ctx.get_bool_var(ea->get_le());
|
||||
bool_var bv2 = ctx.get_bool_var(ea->get_ge());
|
||||
lbool val1 = ctx.get_assignment(bv1);
|
||||
lbool val2 = ctx.get_assignment(bv2);
|
||||
if (asgn == l_true) {
|
||||
SASSERT(val1 == l_true);
|
||||
SASSERT(val2 == l_true);
|
||||
}
|
||||
else {
|
||||
SASSERT(val1 == l_false || val2 == l_false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
int edge_id = a->get_asserted_edge();
|
||||
SASSERT(m_graph.is_enabled(edge_id));
|
||||
SASSERT(m_graph.is_feasible(edge_id));
|
||||
}
|
||||
}
|
||||
return m_graph.is_feasible();
|
||||
|
@ -1087,7 +916,6 @@ void theory_diff_logic<Ext>::new_eq_or_diseq(bool is_eq, theory_var v1, theory_v
|
|||
// assign the corresponding equality literal.
|
||||
//
|
||||
|
||||
mark_as_modified_since_eq_prop();
|
||||
|
||||
app_ref eq(m), s2(m), t2(m);
|
||||
app* s1 = get_enode(s)->get_owner();
|
||||
|
@ -1142,10 +970,6 @@ void theory_diff_logic<Ext>::new_diseq_eh(theory_var v1, theory_var v2) {
|
|||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
void theory_diff_logic<Ext>::relevant_eh(app* e) {
|
||||
}
|
||||
|
||||
|
||||
struct imp_functor {
|
||||
conflict_resolution & m_cr;
|
||||
|
|
|
@ -68,14 +68,11 @@ namespace smt {
|
|||
bv_util& b() { return m_bv; }
|
||||
|
||||
class dl_value_proc : public smt::model_value_proc {
|
||||
smt::model_generator & m_mg;
|
||||
theory_dl& m_th;
|
||||
smt::enode* m_node;
|
||||
public:
|
||||
|
||||
dl_value_proc(smt::model_generator & m, theory_dl& th, smt::enode* n):
|
||||
m_mg(m), m_th(th), m_node(n)
|
||||
{ }
|
||||
dl_value_proc(theory_dl& th, smt::enode* n) : m_th(th), m_node(n) {}
|
||||
|
||||
virtual void get_dependencies(buffer<smt::model_value_dependency> & result) {}
|
||||
|
||||
|
@ -94,7 +91,7 @@ namespace smt {
|
|||
rational val;
|
||||
if (ctx.e_internalized(rep_of) && th_bv &&
|
||||
th_bv->get_fixed_value(rep_of.get(), val)) {
|
||||
result = m_th.u().mk_numeral(val.get_int64(), s);
|
||||
result = m_th.u().mk_numeral(val.get_int64(), s);
|
||||
}
|
||||
else {
|
||||
result = m_th.u().mk_numeral(0, s);
|
||||
|
@ -165,8 +162,8 @@ namespace smt {
|
|||
m.register_factory(alloc(dl_factory, m_util, m.get_model()));
|
||||
}
|
||||
|
||||
virtual smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator & m) {
|
||||
return alloc(dl_value_proc, m, *this, n);
|
||||
virtual smt::model_value_proc * mk_value(smt::enode * n) {
|
||||
return alloc(dl_value_proc, *this, n);
|
||||
}
|
||||
|
||||
virtual void apply_sort_cnstr(enode * n, sort * s) {
|
||||
|
|
236
src/smt/theory_horn_ineq.cpp
Normal file
236
src/smt/theory_horn_ineq.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*++
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
328
src/smt/theory_horn_ineq.h
Normal file
328
src/smt/theory_horn_ineq.h
Normal file
|
@ -0,0 +1,328 @@
|
|||
/*++
|
||||
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_ */
|
1166
src/smt/theory_horn_ineq_def.h
Normal file
1166
src/smt/theory_horn_ineq_def.h
Normal file
File diff suppressed because it is too large
Load diff
160
src/smt/theory_utvpi.cpp
Normal file
160
src/smt/theory_utvpi.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_utvpi.h
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||
|
||||
Revision History:
|
||||
|
||||
The implementaton is derived from theory_diff_logic.
|
||||
|
||||
--*/
|
||||
#include "theory_utvpi.h"
|
||||
#include "theory_utvpi_def.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
template class theory_utvpi<idl_ext>;
|
||||
template class theory_utvpi<rdl_ext>;
|
||||
|
||||
// similar to test_diff_logic:
|
||||
|
||||
utvpi_tester::utvpi_tester(ast_manager& m): m(m), a(m) {}
|
||||
|
||||
bool utvpi_tester::operator()(expr* e) {
|
||||
m_todo.reset();
|
||||
m_mark.reset();
|
||||
m_todo.push_back(e);
|
||||
expr* e1, *e2;
|
||||
|
||||
while (!m_todo.empty()) {
|
||||
expr* e = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
if (!m_mark.is_marked(e)) {
|
||||
m_mark.mark(e, true);
|
||||
if (is_var(e)) {
|
||||
continue;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
return false;
|
||||
}
|
||||
app* ap = to_app(e);
|
||||
if (m.is_eq(ap, e1, e2)) {
|
||||
if (!linearize(e1, e2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ap->get_family_id() == m.get_basic_family_id()) {
|
||||
continue;
|
||||
}
|
||||
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 (!linearize(e1, e2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (is_uninterp_const(e)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<std::pair<expr*, rational> > const& utvpi_tester::get_linearization() const {
|
||||
SASSERT(m_terms.size() <= 2);
|
||||
return m_terms;
|
||||
}
|
||||
|
||||
bool utvpi_tester::operator()(unsigned num_fmls, expr* const* fmls) {
|
||||
for (unsigned i = 0; i < num_fmls; ++i) {
|
||||
if (!(*this)(fmls[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool utvpi_tester::linearize(expr* e) {
|
||||
m_terms.reset();
|
||||
m_terms.push_back(std::make_pair(e, rational(1)));
|
||||
return linearize();
|
||||
}
|
||||
|
||||
bool utvpi_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();
|
||||
}
|
||||
|
||||
bool utvpi_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 false;
|
||||
}
|
||||
else {
|
||||
m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul;
|
||||
}
|
||||
}
|
||||
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 (m_terms.size() > 2) {
|
||||
return false;
|
||||
}
|
||||
if (!r.is_one() && !r.is_minus_one()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
343
src/smt/theory_utvpi.h
Normal file
343
src/smt/theory_utvpi.h
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_utvpi.h
|
||||
|
||||
Abstract:
|
||||
|
||||
use Bellman Ford traversal algorithm for UTVPI.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||
|
||||
Revision History:
|
||||
|
||||
The implementaton is derived from theory_diff_logic.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _THEORY_UTVPI_H_
|
||||
#define _THEORY_UTVPI_H_
|
||||
|
||||
#include"theory_diff_logic.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
class utvpi_tester {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
ptr_vector<expr> m_todo;
|
||||
ast_mark m_mark;
|
||||
obj_map<expr, rational> m_coeff_map;
|
||||
rational m_weight;
|
||||
vector<std::pair<expr*, rational> > m_terms;
|
||||
|
||||
public:
|
||||
utvpi_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
|
||||
bool linearize(expr* e);
|
||||
bool 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 linearize();
|
||||
};
|
||||
|
||||
template<typename Ext>
|
||||
class theory_utvpi : public theory, private Ext {
|
||||
|
||||
typedef typename Ext::numeral numeral;
|
||||
typedef theory_var th_var;
|
||||
typedef svector<th_var> th_var_vector;
|
||||
typedef vector<std::pair<th_var, rational> > coeffs;
|
||||
|
||||
class assignment_trail;
|
||||
class parent_trail;
|
||||
|
||||
struct GExt : public Ext {
|
||||
typedef std::pair<literal,unsigned> explanation;
|
||||
};
|
||||
|
||||
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; }
|
||||
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_utvpi 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();
|
||||
}
|
||||
};
|
||||
|
||||
// Functor used to collect the proofs for a conflict due to
|
||||
// a negative cycle.
|
||||
class nc_functor {
|
||||
literal_vector m_antecedents;
|
||||
unsigned_vector m_coeffs;
|
||||
theory_utvpi& m_super;
|
||||
public:
|
||||
nc_functor(theory_utvpi& s) : m_super(s) {}
|
||||
void reset() { m_antecedents.reset(); m_coeffs.reset(); }
|
||||
literal_vector const& get_lits() const { return m_antecedents; }
|
||||
unsigned_vector const& get_coeffs() const { return m_coeffs; }
|
||||
|
||||
void operator()(std::pair<literal,unsigned> const & ex) {
|
||||
if (ex.first != null_literal) {
|
||||
m_antecedents.push_back(ex.first);
|
||||
m_coeffs.push_back(ex.second);
|
||||
}
|
||||
}
|
||||
|
||||
void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {
|
||||
m_super.new_edge(src, dst, num_edges, edges);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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.
|
||||
|
||||
dl_graph<GExt> m_graph;
|
||||
nc_functor m_nc_functor;
|
||||
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_utvpi_exprs;
|
||||
|
||||
utvpi_tester m_test;
|
||||
|
||||
|
||||
arith_factory * m_factory;
|
||||
rational m_delta;
|
||||
|
||||
|
||||
// Set a conflict due to a negative cycle.
|
||||
void set_conflict();
|
||||
|
||||
void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {}
|
||||
|
||||
// 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_utvpi_expr(expr * n);
|
||||
|
||||
bool is_interpreted(app* n) const {
|
||||
return n->get_family_id() == get_family_id();
|
||||
}
|
||||
|
||||
public:
|
||||
theory_utvpi(ast_manager& m);
|
||||
|
||||
virtual ~theory_utvpi();
|
||||
|
||||
virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_utvpi, get_manager()); }
|
||||
|
||||
virtual char const * get_name() const { return "utvpi-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_stats.m_num_core2th_eqs++;
|
||||
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:
|
||||
|
||||
rational mk_value(theory_var v, bool is_int);
|
||||
|
||||
bool is_parity_ok(unsigned v) const;
|
||||
|
||||
void enforce_parity();
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
edge_id add_ineq(vector<std::pair<th_var, rational> > const& terms, numeral const& weight, literal l);
|
||||
|
||||
bool enable_edge(edge_id id);
|
||||
|
||||
th_var to_var(th_var v) const {
|
||||
return 2*v;
|
||||
}
|
||||
|
||||
th_var from_var(th_var v) const {
|
||||
return v/2;
|
||||
}
|
||||
|
||||
th_var pos(th_var v) const {
|
||||
return v & 0xFFFFFFFE;
|
||||
}
|
||||
|
||||
th_var neg(th_var v) const {
|
||||
return v | 0x1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef theory_utvpi<rdl_ext> theory_rutvpi;
|
||||
typedef theory_utvpi<idl_ext> theory_iutvpi;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _THEORY_UTVPI_H_ */
|
954
src/smt/theory_utvpi_def.h
Normal file
954
src/smt/theory_utvpi_def.h
Normal file
|
@ -0,0 +1,954 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_utvpi_def.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Implementation of UTVPI solver.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||
|
||||
Revision History:
|
||||
|
||||
1. introduce x^+ and x^-, such that 2*x := x^+ - x^-
|
||||
2. rewrite constraints as follows:
|
||||
|
||||
x - y <= k => x^+ - y^+ <= k
|
||||
y^- - x^- <= k
|
||||
|
||||
x <= k => x^+ - x^- <= 2k
|
||||
|
||||
|
||||
x + y <= k => x^+ - y^- <= k
|
||||
y^+ - x^- <= k
|
||||
|
||||
|
||||
- x - y <= k => x^- - y^+ <= k
|
||||
y^- - x^+ <= k
|
||||
|
||||
3. Solve for x^+ and x^-
|
||||
4. Check parity condition for integers (see Lahiri and Musuvathi 05)
|
||||
This checks if x^+ and x^- are in the same component but of different
|
||||
parities.
|
||||
5. Enforce parity on variables. This checks if x^+ and x^- have different
|
||||
parities. If they have different parities, the assignment to one
|
||||
of the variables is decremented (choose the variable that is not tightly
|
||||
constrained with 0).
|
||||
The process that adjusts parities converges: Suppose we break a parity
|
||||
of a different variable y while fixing x's parity. A cyclic breaking/fixing
|
||||
of parities implies there is a strongly connected component between x, y
|
||||
and the two polarities of the variables. This contradicts the test in 4.
|
||||
6. extract model for M(x) := (M(x^+)- M(x^-))/2
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _THEORY_UTVPI_DEF_H_
|
||||
#define _THEORY_UTVPI_DEF_H_
|
||||
#include "theory_utvpi.h"
|
||||
#include "heap.h"
|
||||
#include "ast_pp.h"
|
||||
#include "smt_context.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
theory_utvpi<Ext>::theory_utvpi(ast_manager& m):
|
||||
theory(m.mk_family_id("arith")),
|
||||
a(m),
|
||||
m_arith_eq_adapter(*this, m_params, a),
|
||||
m_zero_int(null_theory_var),
|
||||
m_zero_real(null_theory_var),
|
||||
m_nc_functor(*this),
|
||||
m_asserted_qhead(0),
|
||||
m_agility(0.5),
|
||||
m_lia(false),
|
||||
m_lra(false),
|
||||
m_non_utvpi_exprs(false),
|
||||
m_test(m),
|
||||
m_factory(0) {
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
theory_utvpi<Ext>::~theory_utvpi() {
|
||||
reset_eh();
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
std::ostream& theory_utvpi<Ext>::atom::display(theory_utvpi const& th, std::ostream& out) const {
|
||||
context& ctx = th.get_context();
|
||||
lbool asgn = ctx.get_assignment(m_bvar);
|
||||
bool sign = (l_undef == l_false);
|
||||
return out << literal(m_bvar, sign) << " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " ";
|
||||
if (l_undef == asgn) {
|
||||
out << "unassigned\n";
|
||||
}
|
||||
else {
|
||||
th.m_graph.display_edge(out, get_asserted_edge());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
theory_var theory_utvpi<Ext>::mk_var(enode* n) {
|
||||
th_var v = theory::mk_var(n);
|
||||
TRACE("utvpi", tout << v << " " << mk_pp(n->get_owner(), get_manager()) << "\n";);
|
||||
m_graph.init_var(to_var(v));
|
||||
m_graph.init_var(neg(to_var(v)));
|
||||
get_context().attach_th_var(n, this, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
theory_var theory_utvpi<Ext>::mk_var(expr* n) {
|
||||
context & ctx = get_context();
|
||||
enode* e = 0;
|
||||
th_var v = null_theory_var;
|
||||
m_lia |= a.is_int(n);
|
||||
m_lra |= a.is_real(n);
|
||||
if (!is_app(n)) {
|
||||
return v;
|
||||
}
|
||||
if (ctx.e_internalized(n)) {
|
||||
e = ctx.get_enode(n);
|
||||
v = e->get_th_var(get_id());
|
||||
}
|
||||
else {
|
||||
ctx.internalize(n, false);
|
||||
e = ctx.get_enode(n);
|
||||
}
|
||||
if (v == null_theory_var) {
|
||||
v = mk_var(e);
|
||||
}
|
||||
if (is_interpreted(to_app(n))) {
|
||||
found_non_utvpi_expr(n);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::reset_eh() {
|
||||
m_graph .reset();
|
||||
m_zero_int = null_theory_var;
|
||||
m_zero_real = null_theory_var;
|
||||
m_atoms .reset();
|
||||
m_asserted_atoms .reset();
|
||||
m_stats .reset();
|
||||
m_scopes .reset();
|
||||
m_asserted_qhead = 0;
|
||||
m_agility = 0.5;
|
||||
m_lia = false;
|
||||
m_lra = false;
|
||||
m_non_utvpi_exprs = false;
|
||||
theory::reset_eh();
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just) {
|
||||
rational k;
|
||||
th_var s = expand(true, v1, k);
|
||||
th_var t = expand(false, v2, k);
|
||||
context& ctx = get_context();
|
||||
ast_manager& m = get_manager();
|
||||
|
||||
if (s == t) {
|
||||
if (is_eq != k.is_zero()) {
|
||||
// conflict 0 /= k;
|
||||
inc_conflicts();
|
||||
ctx.set_conflict(&eq_just);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// Create equality ast, internalize_atom
|
||||
// assign the corresponding equality literal.
|
||||
//
|
||||
|
||||
app_ref eq(m), s2(m), t2(m);
|
||||
app* s1 = get_enode(s)->get_owner();
|
||||
app* t1 = get_enode(t)->get_owner();
|
||||
s2 = a.mk_sub(t1, s1);
|
||||
t2 = a.mk_numeral(k, m.get_sort(s2.get()));
|
||||
// t1 - s1 = k
|
||||
eq = m.mk_eq(s2.get(), t2.get());
|
||||
|
||||
TRACE("utvpi",
|
||||
tout << v1 << " .. " << v2 << "\n";
|
||||
tout << mk_pp(eq.get(), m) <<"\n";);
|
||||
|
||||
if (!internalize_atom(eq.get(), false)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
literal l(ctx.get_literal(eq.get()));
|
||||
if (!is_eq) {
|
||||
l = ~l;
|
||||
}
|
||||
ctx.assign(l, b_justification(&eq_just), false);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::inc_conflicts() {
|
||||
m_stats.m_num_conflicts++;
|
||||
if (m_params.m_arith_adaptive) {
|
||||
double g = m_params.m_arith_adaptive_propagation_threshold;
|
||||
m_agility = m_agility*g + 1 - g;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::set_conflict() {
|
||||
inc_conflicts();
|
||||
literal_vector const& lits = m_nc_functor.get_lits();
|
||||
context & ctx = get_context();
|
||||
IF_VERBOSE(2,
|
||||
verbose_stream() << "conflict:\n";
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ast_manager& m = get_manager();
|
||||
expr_ref e(m);
|
||||
ctx.literal2expr(lits[i], e);
|
||||
verbose_stream() << mk_pp(e, m) << "\n";
|
||||
}
|
||||
verbose_stream() << "\n";);
|
||||
TRACE("utvpi",
|
||||
tout << "conflict: ";
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ctx.display_literal_info(tout, lits[i]);
|
||||
}
|
||||
tout << "\n";
|
||||
);
|
||||
|
||||
if (m_params.m_arith_dump_lemmas) {
|
||||
char const * logic = m_lra ? (m_lia?"QF_LIRA":"QF_LRA") : "QF_LIA";
|
||||
ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic);
|
||||
}
|
||||
|
||||
vector<parameter> params;
|
||||
if (get_manager().proofs_enabled()) {
|
||||
params.push_back(parameter(symbol("farkas")));
|
||||
for (unsigned i = 0; i < m_nc_functor.get_coeffs().size(); ++i) {
|
||||
params.push_back(parameter(rational(m_nc_functor.get_coeffs()[i])));
|
||||
}
|
||||
}
|
||||
|
||||
ctx.set_conflict(
|
||||
ctx.mk_justification(
|
||||
ext_theory_conflict_justification(
|
||||
get_id(), ctx.get_region(),
|
||||
lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr())));
|
||||
|
||||
m_nc_functor.reset();
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::found_non_utvpi_expr(expr* n) {
|
||||
if (!m_non_utvpi_exprs) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::init(context* ctx) {
|
||||
theory::init(ctx);
|
||||
m_zero_int = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), true), false, false, true));
|
||||
m_zero_real = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), false), false, false, true));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create negated literal.
|
||||
|
||||
The negation of: E <= 0
|
||||
|
||||
-E + epsilon <= 0
|
||||
or
|
||||
-E + 1 <= 0
|
||||
*/
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::negate(coeffs& coeffs, rational& weight) {
|
||||
for (unsigned i = 0; i < coeffs.size(); ++i) {
|
||||
coeffs[i].second.neg();
|
||||
}
|
||||
weight.neg();
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
typename theory_utvpi<Ext>::numeral theory_utvpi<Ext>::mk_weight(bool is_real, bool is_strict, rational const& w) const {
|
||||
if (is_strict) {
|
||||
return numeral(w) + (is_real?Ext::m_epsilon:numeral(1));
|
||||
}
|
||||
else {
|
||||
return numeral(w);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::mk_coeffs(vector<std::pair<expr*,rational> > const& terms, coeffs& coeffs, rational& w) {
|
||||
coeffs.reset();
|
||||
w = m_test.get_weight();
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
coeffs.push_back(std::make_pair(mk_var(terms[i].first), terms[i].second));
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
if (!a.is_le(n) && !a.is_ge(n) && !a.is_lt(n) && !a.is_gt(n)) {
|
||||
found_non_utvpi_expr(n);
|
||||
return false;
|
||||
}
|
||||
SASSERT(!ctx.b_internalized(n));
|
||||
expr* e1 = n->get_arg(0), *e2 = n->get_arg(1);
|
||||
if (a.is_ge(n) || a.is_gt(n)) {
|
||||
std::swap(e1, e2);
|
||||
}
|
||||
bool is_strict = a.is_gt(n) || a.is_lt(n);
|
||||
|
||||
bool cl = m_test.linearize(e1, e2);
|
||||
if (!cl) {
|
||||
found_non_utvpi_expr(n);
|
||||
return false;
|
||||
}
|
||||
|
||||
rational w;
|
||||
coeffs coeffs;
|
||||
mk_coeffs(m_test.get_linearization(), coeffs, w);
|
||||
bool_var bv = ctx.mk_bool_var(n);
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
literal l(bv);
|
||||
numeral w1 = mk_weight(a.is_real(e1), is_strict, w);
|
||||
edge_id pos = add_ineq(coeffs, w1, l);
|
||||
negate(coeffs, w);
|
||||
numeral w2 = mk_weight(a.is_real(e1), !is_strict, w);
|
||||
edge_id neg = add_ineq(coeffs, w2, ~l);
|
||||
m_bool_var2atom.insert(bv, m_atoms.size());
|
||||
m_atoms.push_back(atom(bv, pos, neg));
|
||||
|
||||
TRACE("utvpi",
|
||||
tout << mk_pp(n, get_manager()) << "\n";
|
||||
m_graph.display_edge(tout << "pos: ", pos);
|
||||
m_graph.display_edge(tout << "neg: ", neg);
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
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";);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||
m_stats.m_num_assertions++;
|
||||
unsigned idx = m_bool_var2atom.find(v);
|
||||
SASSERT(get_context().get_assignment(v) != l_undef);
|
||||
SASSERT((get_context().get_assignment(v) == l_true) == is_true);
|
||||
m_atoms[idx].assign_eh(is_true);
|
||||
m_asserted_atoms.push_back(idx);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::push_scope_eh() {
|
||||
theory::push_scope_eh();
|
||||
m_graph.push();
|
||||
m_scopes.push_back(scope());
|
||||
scope & s = m_scopes.back();
|
||||
s.m_atoms_lim = m_atoms.size();
|
||||
s.m_asserted_atoms_lim = m_asserted_atoms.size();
|
||||
s.m_asserted_qhead_old = m_asserted_qhead;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::pop_scope_eh(unsigned num_scopes) {
|
||||
unsigned lvl = m_scopes.size();
|
||||
SASSERT(num_scopes <= lvl);
|
||||
unsigned new_lvl = lvl - num_scopes;
|
||||
scope & s = m_scopes[new_lvl];
|
||||
del_atoms(s.m_atoms_lim);
|
||||
m_asserted_atoms.shrink(s.m_asserted_atoms_lim);
|
||||
m_asserted_qhead = s.m_asserted_qhead_old;
|
||||
m_scopes.shrink(new_lvl);
|
||||
m_graph.pop(num_scopes);
|
||||
theory::pop_scope_eh(num_scopes);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
final_check_status theory_utvpi<Ext>::final_check_eh() {
|
||||
SASSERT(is_consistent());
|
||||
if (can_propagate()) {
|
||||
propagate();
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
else if (!check_z_consistency()) {
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
else if (m_non_utvpi_exprs) {
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
else {
|
||||
return FC_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::check_z_consistency() {
|
||||
int_vector scc_id;
|
||||
m_graph.compute_zero_edge_scc(scc_id);
|
||||
|
||||
unsigned sz = get_num_vars();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
enode* e = get_enode(i);
|
||||
if (!a.is_int(e->get_owner())) {
|
||||
continue;
|
||||
}
|
||||
th_var v1 = to_var(i);
|
||||
th_var v2 = neg(v1);
|
||||
rational r1 = m_graph.get_assignment(v1).get_rational();
|
||||
rational r2 = m_graph.get_assignment(v2).get_rational();
|
||||
SASSERT(r1.is_int());
|
||||
SASSERT(r2.is_int());
|
||||
if (r1.is_even() == r2.is_even()) {
|
||||
continue;
|
||||
}
|
||||
if (scc_id[v1] != scc_id[v2]) {
|
||||
continue;
|
||||
}
|
||||
if (scc_id[v1] == -1) {
|
||||
continue;
|
||||
}
|
||||
// they are in the same SCC and have different parities => contradiction.
|
||||
m_nc_functor.reset();
|
||||
VERIFY(m_graph.find_shortest_zero_edge_path(v1, v2, UINT_MAX, m_nc_functor));
|
||||
VERIFY(m_graph.find_shortest_zero_edge_path(v2, v1, UINT_MAX, m_nc_functor));
|
||||
IF_VERBOSE(1, verbose_stream() << "parity conflict " << mk_pp(e->get_owner(), get_manager()) << "\n";);
|
||||
set_conflict();
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::display(std::ostream& out) const {
|
||||
for (unsigned i = 0; i < m_atoms.size(); ++i) {
|
||||
m_atoms[i].display(*this, out); out << "\n";
|
||||
}
|
||||
m_graph.display(out);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::collect_statistics(::statistics& st) const {
|
||||
st.update("utvpi conflicts", m_stats.m_num_conflicts);
|
||||
st.update("utvpi asserts", m_stats.m_num_assertions);
|
||||
st.update("core->utvpi eqs", m_stats.m_num_core2th_eqs);
|
||||
st.update("core->utvpi diseqs", m_stats.m_num_core2th_diseqs);
|
||||
m_arith_eq_adapter.collect_statistics(st);
|
||||
m_graph.collect_statistics(st);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::del_atoms(unsigned old_size) {
|
||||
typename atoms::iterator begin = m_atoms.begin() + old_size;
|
||||
typename atoms::iterator it = m_atoms.end();
|
||||
while (it != begin) {
|
||||
--it;
|
||||
m_bool_var2atom.erase(it->get_bool_var());
|
||||
}
|
||||
m_atoms.shrink(old_size);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::propagate() {
|
||||
bool consistent = true;
|
||||
while (consistent && can_propagate()) {
|
||||
unsigned idx = m_asserted_atoms[m_asserted_qhead];
|
||||
m_asserted_qhead++;
|
||||
consistent = propagate_atom(m_atoms[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::propagate_atom(atom const& a) {
|
||||
context& ctx = get_context();
|
||||
TRACE("utvpi", a.display(*this, tout); tout << "\n";);
|
||||
if (ctx.inconsistent()) {
|
||||
return false;
|
||||
}
|
||||
int edge_id = a.get_asserted_edge();
|
||||
if (!enable_edge(edge_id)) {
|
||||
m_graph.traverse_neg_cycle2(m_params.m_arith_stronger_lemmas, m_nc_functor);
|
||||
set_conflict();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!cl) {
|
||||
found_non_utvpi_expr(n);
|
||||
return null_theory_var;
|
||||
}
|
||||
|
||||
coeffs coeffs;
|
||||
rational w;
|
||||
mk_coeffs(m_test.get_linearization(), coeffs, w);
|
||||
if (coeffs.empty()) {
|
||||
return mk_num(n, w);
|
||||
}
|
||||
if (coeffs.size() == 1 && coeffs[0].second.is_one()) {
|
||||
return coeffs[0].first;
|
||||
}
|
||||
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)));
|
||||
negate(coeffs, w);
|
||||
VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal)));
|
||||
return target;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
theory_var theory_utvpi<Ext>::mk_num(app* n, rational const& r) {
|
||||
theory_var v = null_theory_var;
|
||||
context& ctx = get_context();
|
||||
if (r.is_zero()) {
|
||||
v = a.is_int(n)?m_zero_int:m_zero_real;
|
||||
}
|
||||
else if (ctx.e_internalized(n)) {
|
||||
enode* e = ctx.get_enode(n);
|
||||
v = e->get_th_var(get_id());
|
||||
SASSERT(v != null_theory_var);
|
||||
}
|
||||
else {
|
||||
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)));
|
||||
VERIFY(enable_edge(add_ineq(coeffs, numeral(r), null_literal)));
|
||||
coeffs.back().second.neg();
|
||||
VERIFY(enable_edge(add_ineq(coeffs, numeral(-r), null_literal)));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
theory_var theory_utvpi<Ext>::expand(bool pos, th_var v, rational & k) {
|
||||
context& ctx = get_context();
|
||||
enode* e = get_enode(v);
|
||||
expr* x, *y;
|
||||
rational r;
|
||||
for (;;) {
|
||||
app* n = e->get_owner();
|
||||
if (a.is_add(n, x, y)) {
|
||||
if (a.is_numeral(x, r)) {
|
||||
e = ctx.get_enode(y);
|
||||
}
|
||||
else if (a.is_numeral(y, r)) {
|
||||
e = ctx.get_enode(x);
|
||||
}
|
||||
v = e->get_th_var(get_id());
|
||||
SASSERT(v != null_theory_var);
|
||||
if (v == null_theory_var) {
|
||||
break;
|
||||
}
|
||||
if (pos) {
|
||||
k += r;
|
||||
}
|
||||
else {
|
||||
k -= r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// m_graph(source, target, weight, ex);
|
||||
// target - source <= weight
|
||||
|
||||
template<typename Ext>
|
||||
edge_id theory_utvpi<Ext>::add_ineq(vector<std::pair<th_var, rational> > const& terms, numeral const& weight, literal l) {
|
||||
|
||||
SASSERT(terms.size() <= 2);
|
||||
SASSERT(terms.size() < 1 || terms[0].second.is_one() || terms[0].second.is_minus_one());
|
||||
SASSERT(terms.size() < 2 || terms[1].second.is_one() || terms[1].second.is_minus_one());
|
||||
|
||||
th_var v1 = null_theory_var, v2 = null_theory_var;
|
||||
bool pos1 = true, pos2 = true;
|
||||
if (terms.size() >= 1) {
|
||||
v1 = terms[0].first;
|
||||
pos1 = terms[0].second.is_one();
|
||||
SASSERT(v1 != null_theory_var);
|
||||
SASSERT(pos1 || terms[0].second.is_minus_one());
|
||||
}
|
||||
if (terms.size() >= 2) {
|
||||
v2 = terms[1].first;
|
||||
pos2 = terms[1].second.is_one();
|
||||
SASSERT(v1 != null_theory_var);
|
||||
SASSERT(pos2 || terms[1].second.is_minus_one());
|
||||
}
|
||||
// TRACE("utvpi", tout << (pos1?"$":"-$") << v1 << (pos2?" + $":" - $") << v2 << " + " << weight << " <= 0\n";);
|
||||
edge_id id = m_graph.get_num_edges();
|
||||
th_var w1 = to_var(v1), w2 = to_var(v2);
|
||||
if (terms.size() == 1 && pos1) {
|
||||
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, std::make_pair(l,2));
|
||||
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, std::make_pair(l,2));
|
||||
}
|
||||
else if (terms.size() == 1 && !pos1) {
|
||||
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, std::make_pair(l,2));
|
||||
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, std::make_pair(l,2));
|
||||
}
|
||||
else if (pos1 && pos2) {
|
||||
m_graph.add_edge(neg(w2), pos(w1), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(neg(w1), pos(w2), -weight, std::make_pair(l,1));
|
||||
}
|
||||
else if (pos1 && !pos2) {
|
||||
m_graph.add_edge(pos(w2), pos(w1), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(neg(w1), neg(w2), -weight, std::make_pair(l,1));
|
||||
}
|
||||
else if (!pos1 && pos2) {
|
||||
m_graph.add_edge(neg(w2), neg(w1), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(pos(w1), pos(w2), -weight, std::make_pair(l,1));
|
||||
}
|
||||
else {
|
||||
m_graph.add_edge(pos(w1), neg(w2), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(pos(w2), neg(w1), -weight, std::make_pair(l,1));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::enable_edge(edge_id id) {
|
||||
return (id == null_edge_id) || (m_graph.enable_edge(id) && m_graph.enable_edge(id+1));
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::is_consistent() const {
|
||||
return m_graph.is_feasible();
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::is_parity_ok(unsigned i) const {
|
||||
th_var v1 = to_var(i);
|
||||
th_var v2 = neg(v1);
|
||||
rational r1 = m_graph.get_assignment(v1).get_rational();
|
||||
rational r2 = m_graph.get_assignment(v2).get_rational();
|
||||
return r1.is_even() == r2.is_even();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief adjust values for variables in the difference graph
|
||||
such that for variables of integer sort it is
|
||||
the case that x^+ - x^- is even.
|
||||
The informal justification for the procedure enforce_parity relies
|
||||
on a set of properties:
|
||||
1. the graph does not contain a strongly connected component where
|
||||
x^+ and x+- are connected. They can be independently changed.
|
||||
This is checked prior to enforce_parity.
|
||||
2. When x^+ - x^- is odd, the values are adjusted by first
|
||||
decrementing the value of x^+, provided x^- is not 0-dependent.
|
||||
Otherwise decrement x^-.
|
||||
x^- is "0-dependent" if there is a set of tight
|
||||
inequalities from x^+ to x^-.
|
||||
3. The affinity to x^+ (the same component of x^+) ensures that
|
||||
the parity is broken only a finite number of times when
|
||||
traversing that component. Namely, suppose that the parity of y
|
||||
gets broken when fixing 'x'. Then first note that 'y' cannot
|
||||
be equal to 'x'. If it were, then we have a state where:
|
||||
parity(x^+) != parity(x^-) and
|
||||
parity(y^+) == parity(y^-)
|
||||
but x^+ and y^+ are tightly connected and x^- and y^- are
|
||||
also tightly connected using two copies of the same inequalities.
|
||||
This is a contradiction.
|
||||
Thus, 'y' cannot be equal to 'x' if 'y's parity gets broken when
|
||||
repairing 'x'.
|
||||
|
||||
*/
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::enforce_parity() {
|
||||
unsigned_vector todo;
|
||||
unsigned sz = get_num_vars();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
enode* e = get_enode(i);
|
||||
if (a.is_int(e->get_owner()) && !is_parity_ok(i)) {
|
||||
todo.push_back(i);
|
||||
}
|
||||
}
|
||||
if (todo.empty()) {
|
||||
return;
|
||||
}
|
||||
while (!todo.empty()) {
|
||||
unsigned i = todo.back();
|
||||
todo.pop_back();
|
||||
if (is_parity_ok(i)) {
|
||||
continue;
|
||||
}
|
||||
th_var v1 = to_var(i);
|
||||
th_var v2 = neg(v1);
|
||||
|
||||
int_vector zero_v;
|
||||
m_graph.compute_zero_succ(v1, zero_v);
|
||||
for (unsigned j = 0; j < zero_v.size(); ++j) {
|
||||
if (zero_v[j] == v2) {
|
||||
zero_v.reset();
|
||||
m_graph.compute_zero_succ(v2, zero_v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("utvpi",
|
||||
tout << "Disparity: " << v1 << "\n";
|
||||
for (unsigned j = 0; j < zero_v.size(); ++j) {
|
||||
tout << "decrement: " << zero_v[j] << "\n";
|
||||
});
|
||||
|
||||
for (unsigned j = 0; j < zero_v.size(); ++j) {
|
||||
int v = zero_v[j];
|
||||
m_graph.acc_assignment(v, numeral(-1));
|
||||
th_var k = from_var(v);
|
||||
if (!is_parity_ok(k)) {
|
||||
todo.push_back(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
SASSERT(m_graph.is_feasible());
|
||||
DEBUG_CODE(
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
enode* e = get_enode(i);
|
||||
if (a.is_int(e->get_owner()) && !is_parity_ok(i)) {
|
||||
IF_VERBOSE(0, verbose_stream() << "disparities not fixed\n";);
|
||||
UNREACHABLE();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// models:
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::init_model(model_generator & m) {
|
||||
m_factory = alloc(arith_factory, get_manager());
|
||||
m.register_factory(m_factory);
|
||||
enforce_parity();
|
||||
m_graph.set_to_zero(to_var(m_zero_int), to_var(m_zero_real));
|
||||
m_graph.set_to_zero(neg(to_var(m_zero_int)), neg(to_var(m_zero_real)));
|
||||
m_graph.set_to_zero(to_var(m_zero_int), neg(to_var(m_zero_int)));
|
||||
compute_delta();
|
||||
DEBUG_CODE(validate_model(););
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
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();
|
||||
if (!ctx.is_relevant(b)) {
|
||||
continue;
|
||||
}
|
||||
bool ok = true;
|
||||
expr* e = ctx.bool_var2expr(b);
|
||||
lbool assign = ctx.get_assignment(b);
|
||||
switch(assign) {
|
||||
case l_true:
|
||||
ok = eval(e);
|
||||
break;
|
||||
case l_false:
|
||||
ok = !eval(e);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CTRACE("utvpi", !ok,
|
||||
tout << "validation failed:\n";
|
||||
tout << "Assignment: " << assign << "\n";
|
||||
m_atoms[i].display(*this, tout);
|
||||
tout << "\n";
|
||||
display(tout);
|
||||
m_graph.display_agl(tout);
|
||||
);
|
||||
if (!ok) {
|
||||
std::cout << "validation failed:\n";
|
||||
std::cout << "Assignment: " << assign << "\n";
|
||||
m_atoms[i].display(*this, std::cout);
|
||||
std::cout << "\n";
|
||||
display(std::cout);
|
||||
m_graph.display_agl(std::cout);
|
||||
|
||||
}
|
||||
// CTRACE("utvpi", ok, tout << "validation success: " << mk_pp(e, get_manager()) << "\n";);
|
||||
SASSERT(ok);
|
||||
}
|
||||
}
|
||||
|
||||
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), a.is_int(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, bool is_int) {
|
||||
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);
|
||||
SASSERT(!is_int || num.is_int());
|
||||
TRACE("utvpi",
|
||||
expr* n = get_enode(v)->get_owner();
|
||||
tout << mk_pp(n, get_manager()) << " |-> (" << val1 << " - " << val2 << ")/2 = " << num << "\n";);
|
||||
|
||||
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());
|
||||
bool is_int = a.is_int(n->get_owner());
|
||||
rational num = mk_value(v, is_int);
|
||||
TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";);
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compute numeral values for the infinitesimals to satisfy the inequalities.
|
||||
*/
|
||||
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::compute_delta() {
|
||||
m_delta = rational(1);
|
||||
unsigned sz = m_graph.get_num_edges();
|
||||
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
if (!m_graph.is_enabled(i)) {
|
||||
continue;
|
||||
}
|
||||
numeral w = m_graph.get_weight(i);
|
||||
numeral tgt = m_graph.get_assignment(m_graph.get_target(i));
|
||||
numeral src = m_graph.get_assignment(m_graph.get_source(i));
|
||||
numeral b = tgt - src - w;
|
||||
SASSERT(b.is_nonpos());
|
||||
rational eps_r = b.get_infinitesimal();
|
||||
|
||||
// Given: b <= 0
|
||||
// suppose that 0 < b.eps
|
||||
// then we have 0 > b.num
|
||||
// then delta must ensure:
|
||||
// 0 >= b.num + delta*b.eps
|
||||
// <=>
|
||||
// -b.num/b.eps >= delta
|
||||
if (eps_r.is_pos()) {
|
||||
rational num_r = -b.get_rational();
|
||||
SASSERT(num_r.is_pos());
|
||||
rational new_delta = num_r/eps_r;
|
||||
if (new_delta < m_delta) {
|
||||
m_delta = new_delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue