mirror of
https://github.com/Z3Prover/z3
synced 2025-09-03 16:48:06 +00:00
Merge branch 'pure' of https://git01.codeplex.com/z3 into contrib
This commit is contained in:
commit
6a496a1bfb
560 changed files with 52025 additions and 9358 deletions
|
@ -604,7 +604,9 @@ bool arith_eq_solver::solve_integer_equations_gcd(
|
|||
}
|
||||
SASSERT(g == r0[i]);
|
||||
}
|
||||
SASSERT(abs(r0[i]).is_one());
|
||||
if (!abs(r0[i]).is_one()) {
|
||||
return false;
|
||||
}
|
||||
live.erase(live.begin()+live_pos);
|
||||
for (j = 0; j < live.size(); ++j) {
|
||||
row& r = rows[live[j]];
|
||||
|
|
|
@ -820,6 +820,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// 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.
|
||||
|
@ -829,6 +830,12 @@ public:
|
|||
m_assignment[v] += inc;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void inc_assignment(dl_var v, numeral const& inc) {
|
||||
m_assignment[v] += inc;
|
||||
}
|
||||
|
||||
|
||||
struct every_var_proc {
|
||||
bool operator()(dl_var v) const {
|
||||
|
|
|
@ -23,6 +23,7 @@ void preprocessor_params::updt_local_params(params_ref const & _p) {
|
|||
smt_params_helper p(_p);
|
||||
m_macro_finder = p.macro_finder();
|
||||
m_pull_nested_quantifiers = p.pull_nested_quantifiers();
|
||||
m_refine_inj_axiom = p.refine_inj_axioms();
|
||||
}
|
||||
|
||||
void preprocessor_params::updt_params(params_ref const & p) {
|
||||
|
|
|
@ -27,6 +27,7 @@ void qi_params::updt_params(params_ref const & _p) {
|
|||
m_mbqi_max_iterations = p.mbqi_max_iterations();
|
||||
m_mbqi_trace = p.mbqi_trace();
|
||||
m_mbqi_force_template = p.mbqi_force_template();
|
||||
m_mbqi_id = p.mbqi_id();
|
||||
m_qi_profile = p.qi_profile();
|
||||
m_qi_profile_freq = p.qi_profile_freq();
|
||||
m_qi_max_instances = p.qi_max_instances();
|
||||
|
|
|
@ -51,6 +51,7 @@ struct qi_params {
|
|||
unsigned m_mbqi_max_iterations;
|
||||
bool m_mbqi_trace;
|
||||
unsigned m_mbqi_force_template;
|
||||
const char * m_mbqi_id;
|
||||
|
||||
qi_params(params_ref const & p = params_ref()):
|
||||
/*
|
||||
|
@ -97,7 +98,9 @@ struct qi_params {
|
|||
m_mbqi_max_cexs_incr(1),
|
||||
m_mbqi_max_iterations(1000),
|
||||
m_mbqi_trace(false),
|
||||
m_mbqi_force_template(10) {
|
||||
m_mbqi_force_template(10),
|
||||
m_mbqi_id(0)
|
||||
{
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,11 @@ Revision History:
|
|||
#include"smt_params.h"
|
||||
#include"smt_params_helper.hpp"
|
||||
#include"model_params.hpp"
|
||||
#include"gparams.h"
|
||||
|
||||
void smt_params::updt_local_params(params_ref const & _p) {
|
||||
smt_params_helper p(_p);
|
||||
m_auto_config = p.auto_config();
|
||||
m_auto_config = p.auto_config() && gparams::get_value("auto_config") == "true"; // auto-config is not scoped by smt in gparams.
|
||||
m_random_seed = p.random_seed();
|
||||
m_relevancy_lvl = p.relevancy();
|
||||
m_ematching = p.ematching();
|
||||
|
@ -40,6 +41,7 @@ void smt_params::updt_local_params(params_ref const & _p) {
|
|||
m_arith_pivot_strategy = ARITH_PIVOT_GREATEST_ERROR;
|
||||
else if (_p.get_bool("arith.least_error_pivot", false))
|
||||
m_arith_pivot_strategy = ARITH_PIVOT_LEAST_ERROR;
|
||||
theory_array_params::updt_params(_p);
|
||||
}
|
||||
|
||||
void smt_params::updt_params(params_ref const & p) {
|
||||
|
@ -47,6 +49,7 @@ void smt_params::updt_params(params_ref const & p) {
|
|||
qi_params::updt_params(p);
|
||||
theory_arith_params::updt_params(p);
|
||||
theory_bv_params::updt_params(p);
|
||||
// theory_array_params::updt_params(p);
|
||||
updt_local_params(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ def_module_params(module_name='smt',
|
|||
('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'),
|
||||
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'),
|
||||
('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'),
|
||||
('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'),
|
||||
('soft_timeout', UINT, 0, 'soft timeout (0 means no timeout)'),
|
||||
('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'),
|
||||
('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'),
|
||||
|
@ -21,6 +22,7 @@ def_module_params(module_name='smt',
|
|||
('mbqi.max_iterations', UINT, 1000, 'maximum number of rounds of MBQI'),
|
||||
('mbqi.trace', BOOL, False, 'generate tracing messages for Model Based Quantifier Instantiation (MBQI). It will display a message before every round of MBQI, and the quantifiers that were not satisfied'),
|
||||
('mbqi.force_template', UINT, 10, 'some quantifiers can be used as templates for building interpretations for functions. Z3 uses heuristics to decide whether a quantifier will be used as a template or not. Quantifiers with weight >= mbqi.force_template are forced to be used as a template'),
|
||||
('mbqi.id', STRING, '', 'Only use model-based instantiation for quantifiers with id\'s beginning with string'),
|
||||
('qi.profile', BOOL, False, 'profile quantifier instantiation'),
|
||||
('qi.profile_freq', UINT, UINT_MAX, 'how frequent results are reported by qi.profile'),
|
||||
('qi.max_instances', UINT, UINT_MAX, 'maximum number of quantifier instantiations'),
|
||||
|
@ -41,4 +43,7 @@ def_module_params(module_name='smt',
|
|||
('arith.propagation_mode', UINT, 2, '0 - no propagation, 1 - propagate existing literals, 2 - refine bounds'),
|
||||
('arith.branch_cut_ratio', UINT, 2, 'branch/cut ratio for linear integer arithmetic'),
|
||||
('arith.int_eq_branch', BOOL, False, 'branching using derived integer equations'),
|
||||
('arith.ignore_int', BOOL, False, 'treat integer variables as real')))
|
||||
('arith.ignore_int', BOOL, False, 'treat integer variables as real'),
|
||||
('array.weak', BOOL, False, 'weak array theory'),
|
||||
('array.extensional', BOOL, True, 'extensional array theory')
|
||||
))
|
||||
|
|
|
@ -22,6 +22,7 @@ Revision History:
|
|||
void theory_arith_params::updt_params(params_ref const & _p) {
|
||||
smt_params_helper p(_p);
|
||||
m_arith_random_initial_value = p.arith_random_initial_value();
|
||||
m_arith_random_seed = p.random_seed();
|
||||
m_arith_mode = static_cast<arith_solver_id>(p.arith_solver());
|
||||
m_nl_arith = p.arith_nl();
|
||||
m_nl_arith_gb = p.arith_nl_gb();
|
||||
|
|
|
@ -27,8 +27,7 @@ enum arith_solver_id {
|
|||
AS_DIFF_LOGIC,
|
||||
AS_ARITH,
|
||||
AS_DENSE_DIFF_LOGIC,
|
||||
AS_UTVPI,
|
||||
AS_HORN
|
||||
AS_UTVPI
|
||||
};
|
||||
|
||||
enum bound_prop_mode {
|
||||
|
|
28
src/smt/params/theory_array_params.cpp
Normal file
28
src/smt/params/theory_array_params.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_array_params.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-05-06.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"theory_array_params.h"
|
||||
#include"smt_params_helper.hpp"
|
||||
|
||||
void theory_array_params::updt_params(params_ref const & _p) {
|
||||
smt_params_helper p(_p);
|
||||
m_array_weak = p.array_weak();
|
||||
m_array_extensional = p.array_extensional();
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +51,9 @@ struct theory_array_params : public array_simplifier_params {
|
|||
m_array_lazy_ieq_delay(10) {
|
||||
}
|
||||
|
||||
|
||||
void updt_params(params_ref const & _p);
|
||||
|
||||
#if 0
|
||||
void register_params(ini_params & p) {
|
||||
p.register_int_param("array_solver", 0, 3, reinterpret_cast<int&>(m_array_mode), "0 - no array, 1 - simple, 2 - model based, 3 - full");
|
||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
|||
#include"proto_model.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"expr_functors.h"
|
||||
|
||||
datatype_factory::datatype_factory(ast_manager & m, proto_model & md):
|
||||
struct_factory(m, m.mk_family_id("datatype"), md),
|
||||
|
@ -47,8 +48,10 @@ expr * datatype_factory::get_some_value(sort * s) {
|
|||
*/
|
||||
expr * datatype_factory::get_last_fresh_value(sort * s) {
|
||||
expr * val = 0;
|
||||
if (m_last_fresh_value.find(s, val))
|
||||
if (m_last_fresh_value.find(s, val)) {
|
||||
TRACE("datatype_factory", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";);
|
||||
return val;
|
||||
}
|
||||
value_set * set = get_value_set(s);
|
||||
if (set->empty())
|
||||
val = get_some_value(s);
|
||||
|
@ -59,6 +62,17 @@ expr * datatype_factory::get_last_fresh_value(sort * s) {
|
|||
return val;
|
||||
}
|
||||
|
||||
bool datatype_factory::is_subterm_of_last_value(app* e) {
|
||||
expr* last;
|
||||
if (!m_last_fresh_value.find(m_manager.get_sort(e), last)) {
|
||||
return false;
|
||||
}
|
||||
contains_app contains(m_manager, e);
|
||||
bool result = contains(last);
|
||||
TRACE("datatype_factory", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create an almost fresh value. If s is recursive, then the result is not 0.
|
||||
It also updates m_last_fresh_value
|
||||
|
@ -67,6 +81,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;
|
||||
|
@ -104,11 +119,18 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) {
|
|||
}
|
||||
}
|
||||
if (recursive || found_fresh_arg) {
|
||||
expr * new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
|
||||
app * new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
|
||||
SASSERT(!found_fresh_arg || !set->contains(new_value));
|
||||
register_value(new_value);
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, new_value);
|
||||
if (m_util.is_recursive(s)) {
|
||||
if (is_subterm_of_last_value(new_value)) {
|
||||
new_value = static_cast<app*>(m_last_fresh_value.find(s));
|
||||
}
|
||||
else {
|
||||
m_last_fresh_value.insert(s, new_value);
|
||||
}
|
||||
}
|
||||
TRACE("datatype_factory", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";);
|
||||
return new_value;
|
||||
}
|
||||
}
|
||||
|
@ -169,8 +191,10 @@ expr * datatype_factory::get_fresh_value(sort * s) {
|
|||
// Approach 2)
|
||||
// For recursive datatypes.
|
||||
// search for constructor...
|
||||
unsigned num_iterations = 0;
|
||||
if (m_util.is_recursive(s)) {
|
||||
while(true) {
|
||||
++num_iterations;
|
||||
TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
|
||||
ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s);
|
||||
ptr_vector<func_decl>::const_iterator it = constructors->begin();
|
||||
|
@ -180,21 +204,42 @@ expr * datatype_factory::get_fresh_value(sort * s) {
|
|||
expr_ref_vector args(m_manager);
|
||||
bool found_sibling = false;
|
||||
unsigned num = constructor->get_arity();
|
||||
TRACE("datatype_factory", tout << "checking constructor: " << constructor->get_name() << "\n";);
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
sort * s_arg = constructor->get_domain(i);
|
||||
TRACE("datatype_factory", tout << mk_pp(s, m_manager) << " "
|
||||
<< mk_pp(s_arg, m_manager) << " are_siblings "
|
||||
<< m_util.are_siblings(s, s_arg) << " is_datatype "
|
||||
<< m_util.is_datatype(s_arg) << " found_sibling "
|
||||
<< found_sibling << "\n";);
|
||||
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);
|
||||
expr * maybe_new_arg = 0;
|
||||
if (num_iterations <= 1) {
|
||||
maybe_new_arg = get_almost_fresh_value(s_arg);
|
||||
}
|
||||
else {
|
||||
maybe_new_arg = get_fresh_value(s_arg);
|
||||
}
|
||||
if (!maybe_new_arg) {
|
||||
TRACE("datatype_factory",
|
||||
tout << "no argument found for " << mk_pp(s_arg, m_manager) << "\n";);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (found_sibling) {
|
||||
expr_ref new_value(m_manager);
|
||||
new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
|
||||
TRACE("datatype_factory", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";);
|
||||
m_last_fresh_value.insert(s, new_value);
|
||||
if (!set->contains(new_value)) {
|
||||
register_value(new_value);
|
||||
|
|
|
@ -29,6 +29,8 @@ class datatype_factory : public struct_factory {
|
|||
expr * get_last_fresh_value(sort * s);
|
||||
expr * get_almost_fresh_value(sort * s);
|
||||
|
||||
bool is_subterm_of_last_value(app* e);
|
||||
|
||||
public:
|
||||
datatype_factory(ast_manager & m, proto_model & md);
|
||||
virtual ~datatype_factory() {}
|
||||
|
|
|
@ -247,6 +247,7 @@ bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
|
|||
new_t = mk_some_interp_for(f);
|
||||
}
|
||||
else {
|
||||
TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";);
|
||||
is_ok = false;
|
||||
}
|
||||
}
|
||||
|
@ -294,6 +295,7 @@ bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
|
|||
// f is an uninterpreted function, there is no need to use m_simplifier.mk_app
|
||||
new_t = m_manager.mk_app(f, num_args, args.c_ptr());
|
||||
trail.push_back(new_t);
|
||||
TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";);
|
||||
is_ok = false;
|
||||
}
|
||||
}
|
||||
|
@ -326,6 +328,7 @@ bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
|
|||
todo.pop_back();
|
||||
break;
|
||||
case AST_QUANTIFIER:
|
||||
TRACE("model_eval", tout << "found quantifier\n" << mk_pp(a, m_manager) << "\n";);
|
||||
is_ok = false; // evaluator does not handle quantifiers.
|
||||
SASSERT(a != 0);
|
||||
eval_cache.insert(a, a);
|
||||
|
|
|
@ -180,10 +180,23 @@ 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 start = set->m_next;
|
||||
Number & next = set->m_next;
|
||||
while (!is_new) {
|
||||
result = mk_value(next, s, is_new);
|
||||
next++;
|
||||
if (has_max && next > max_size + start) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SASSERT(result != 0);
|
||||
return result;
|
||||
|
|
|
@ -759,7 +759,8 @@ namespace smt {
|
|||
app * fact = to_app(m_manager.get_fact(pr));
|
||||
app * n1_owner = n1->get_owner();
|
||||
app * n2_owner = n2->get_owner();
|
||||
if (fact->get_num_args() != 2 || (fact->get_arg(0) != n2_owner && fact->get_arg(1) != n2_owner)) {
|
||||
bool is_eq = m_manager.is_eq(fact) || m_manager.is_iff(fact);
|
||||
if (!is_eq || (fact->get_arg(0) != n2_owner && fact->get_arg(1) != n2_owner)) {
|
||||
CTRACE("norm_eq_proof_bug", !m_ctx.is_true(n2) && !m_ctx.is_false(n2),
|
||||
tout << "n1: #" << n1->get_owner_id() << ", n2: #" << n2->get_owner_id() << "\n";
|
||||
if (fact->get_num_args() == 2) {
|
||||
|
|
|
@ -1615,6 +1615,8 @@ namespace smt {
|
|||
unsigned qhead = m_qhead;
|
||||
if (!bcp())
|
||||
return false;
|
||||
if (m_cancel_flag)
|
||||
return true;
|
||||
SASSERT(!inconsistent());
|
||||
propagate_relevancy(qhead);
|
||||
if (inconsistent())
|
||||
|
|
|
@ -54,7 +54,11 @@ Revision History:
|
|||
// the case that each context only references a few expressions.
|
||||
// Using a map instead of a vector for the literals can compress space
|
||||
// consumption.
|
||||
#ifdef SPARSE_MAP
|
||||
#define USE_BOOL_VAR_VECTOR 0
|
||||
#else
|
||||
#define USE_BOOL_VAR_VECTOR 1
|
||||
#endif
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -69,9 +73,10 @@ namespace smt {
|
|||
std::string last_failure_as_string() const;
|
||||
void set_progress_callback(progress_callback *callback);
|
||||
|
||||
|
||||
protected:
|
||||
ast_manager & m_manager;
|
||||
smt_params & m_fparams;
|
||||
smt_params & m_fparams;
|
||||
params_ref m_params;
|
||||
setup m_setup;
|
||||
volatile bool m_cancel_flag;
|
||||
|
@ -106,7 +111,7 @@ namespace smt {
|
|||
// -----------------------------------
|
||||
enode * m_true_enode;
|
||||
enode * m_false_enode;
|
||||
ptr_vector<enode> m_app2enode; // app -> enode
|
||||
app2enode_t m_app2enode; // app -> enode
|
||||
ptr_vector<enode> m_enodes;
|
||||
plugin_manager<theory> m_theories; // mapping from theory_id -> theory
|
||||
ptr_vector<theory> m_theory_set; // set of theories for fast traversal
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace smt {
|
|||
/**
|
||||
\brief Initialize an enode in the given memory position.
|
||||
*/
|
||||
enode * enode::init(ast_manager & m, void * mem, ptr_vector<enode> const & app2enode, app * owner,
|
||||
enode * enode::init(ast_manager & m, void * mem, app2enode_t const & app2enode, app * owner,
|
||||
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
|
||||
bool cgc_enabled, bool update_children_parent) {
|
||||
SASSERT(m.is_bool(owner) || !merge_tf);
|
||||
|
@ -60,7 +60,7 @@ namespace smt {
|
|||
return n;
|
||||
}
|
||||
|
||||
enode * enode::mk(ast_manager & m, region & r, ptr_vector<enode> const & app2enode, app * owner,
|
||||
enode * enode::mk(ast_manager & m, region & r, app2enode_t const & app2enode, app * owner,
|
||||
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
|
||||
bool cgc_enabled, bool update_children_parent) {
|
||||
SASSERT(m.is_bool(owner) || !merge_tf);
|
||||
|
@ -69,7 +69,7 @@ namespace smt {
|
|||
return init(m, mem, app2enode, owner, generation, suppress_args, merge_tf, iscope_lvl, cgc_enabled, update_children_parent);
|
||||
}
|
||||
|
||||
enode * enode::mk_dummy(ast_manager & m, ptr_vector<enode> const & app2enode, app * owner) {
|
||||
enode * enode::mk_dummy(ast_manager & m, app2enode_t const & app2enode, app * owner) {
|
||||
unsigned sz = get_enode_size(owner->get_num_args());
|
||||
void * mem = alloc_svect(char, sz);
|
||||
return init(m, mem, app2enode, owner, 0, false, false, 0, true, false);
|
||||
|
|
|
@ -38,6 +38,29 @@ namespace smt {
|
|||
}
|
||||
};
|
||||
|
||||
/** \ brief Use sparse maps in SMT solver.
|
||||
|
||||
Define this to use hash maps rather than vectors over ast
|
||||
nodes. This is useful in the case there are many solvers, each
|
||||
referencing few nodes from a large ast manager. There is some
|
||||
unknown performance penalty for this. */
|
||||
|
||||
// #define SPARSE_MAP
|
||||
|
||||
#ifndef SPARSE_MAP
|
||||
typedef ptr_vector<enode> app2enode_t; // app -> enode
|
||||
#else
|
||||
class app2enode_t : public u_map<enode *> {
|
||||
public:
|
||||
void setx(unsigned x, enode *val, enode *def){
|
||||
if(val == 0)
|
||||
erase(x);
|
||||
else
|
||||
insert(x,val);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class tmp_enode;
|
||||
|
||||
/**
|
||||
|
@ -115,7 +138,7 @@ namespace smt {
|
|||
|
||||
friend class tmp_enode;
|
||||
|
||||
static enode * init(ast_manager & m, void * mem, ptr_vector<enode> const & app2enode, app * owner,
|
||||
static enode * init(ast_manager & m, void * mem, app2enode_t const & app2enode, app * owner,
|
||||
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
|
||||
bool cgc_enabled, bool update_children_parent);
|
||||
public:
|
||||
|
@ -124,11 +147,11 @@ namespace smt {
|
|||
return sizeof(enode) + num_args * sizeof(enode*);
|
||||
}
|
||||
|
||||
static enode * mk(ast_manager & m, region & r, ptr_vector<enode> const & app2enode, app * owner,
|
||||
static enode * mk(ast_manager & m, region & r, app2enode_t const & app2enode, app * owner,
|
||||
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
|
||||
bool cgc_enabled, bool update_children_parent);
|
||||
|
||||
static enode * mk_dummy(ast_manager & m, ptr_vector<enode> const & app2enode, app * owner);
|
||||
static enode * mk_dummy(ast_manager & m, app2enode_t const & app2enode, app * owner);
|
||||
|
||||
static void del_dummy(enode * n) { dealloc_svect(reinterpret_cast<char*>(n)); }
|
||||
|
||||
|
|
|
@ -136,9 +136,8 @@ namespace smt {
|
|||
if (cex == 0)
|
||||
return false; // no model available.
|
||||
unsigned num_decls = q->get_num_decls();
|
||||
unsigned num_sks = sks.size();
|
||||
// Remark: sks were created for the flat version of q.
|
||||
SASSERT(num_sks >= num_decls);
|
||||
SASSERT(sks.size() >= num_decls);
|
||||
expr_ref_buffer bindings(m_manager);
|
||||
bindings.resize(num_decls);
|
||||
unsigned max_generation = 0;
|
||||
|
@ -322,6 +321,7 @@ namespace smt {
|
|||
|
||||
for (; it != end; ++it) {
|
||||
quantifier * q = *it;
|
||||
if(!m_qm->mbqi_enabled(q)) continue;
|
||||
if (m_context->is_relevant(q) && m_context->get_assignment(q) == l_true) {
|
||||
if (m_params.m_mbqi_trace && q->get_qid() != symbol::null) {
|
||||
verbose_stream() << "(smt.mbqi :checking " << q->get_qid() << ")\n";
|
||||
|
|
|
@ -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();
|
||||
|
@ -388,7 +396,7 @@ namespace smt {
|
|||
|
||||
// Support for evaluating expressions in the current model.
|
||||
proto_model * m_model;
|
||||
obj_map<expr, expr *> m_eval_cache;
|
||||
obj_map<expr, expr *> m_eval_cache[2];
|
||||
expr_ref_vector m_eval_cache_range;
|
||||
|
||||
ptr_vector<node> m_root_nodes;
|
||||
|
@ -401,7 +409,8 @@ namespace smt {
|
|||
}
|
||||
|
||||
void reset_eval_cache() {
|
||||
m_eval_cache.reset();
|
||||
m_eval_cache[0].reset();
|
||||
m_eval_cache[1].reset();
|
||||
m_eval_cache_range.reset();
|
||||
}
|
||||
|
||||
|
@ -460,6 +469,7 @@ namespace smt {
|
|||
|
||||
~auf_solver() {
|
||||
flush_nodes();
|
||||
reset_eval_cache();
|
||||
}
|
||||
|
||||
void set_context(context * ctx) {
|
||||
|
@ -525,6 +535,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 (!n_val || !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);
|
||||
|
@ -537,15 +571,19 @@ namespace smt {
|
|||
|
||||
virtual expr * eval(expr * n, bool model_completion) {
|
||||
expr * r = 0;
|
||||
if (m_eval_cache.find(n, r)) {
|
||||
if (m_eval_cache[model_completion].find(n, r)) {
|
||||
return r;
|
||||
}
|
||||
expr_ref tmp(m_manager);
|
||||
if (!m_model->eval(n, tmp, model_completion))
|
||||
if (!m_model->eval(n, tmp, model_completion)) {
|
||||
r = 0;
|
||||
else
|
||||
TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n-----> null\n";);
|
||||
}
|
||||
else {
|
||||
r = tmp;
|
||||
m_eval_cache.insert(n, r);
|
||||
TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";);
|
||||
}
|
||||
m_eval_cache[model_completion].insert(n, r);
|
||||
m_eval_cache_range.push_back(r);
|
||||
return r;
|
||||
}
|
||||
|
@ -942,9 +980,11 @@ namespace smt {
|
|||
// Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value.
|
||||
// If these module values "leak" inside the logical context, they may affect satisfiability.
|
||||
//
|
||||
// n->insert(m_model->get_some_value(n->get_sort()), 0);
|
||||
// TODO: we can use get_some_value if the sort n->get_sort() does not depend on any uninterpreted sorts.
|
||||
n->insert(m_manager.mk_fresh_const("elem", n->get_sort()), 0);
|
||||
sort * ns = n->get_sort();
|
||||
if (m_manager.is_fully_interp(ns))
|
||||
n->insert(m_model->get_some_value(ns), 0);
|
||||
else
|
||||
n->insert(m_manager.mk_fresh_const("elem", ns), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1047,6 +1087,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);
|
||||
|
|
|
@ -102,6 +102,7 @@ namespace smt {
|
|||
if (th && th->build_models()) {
|
||||
if (r->get_th_var(th->get_id()) != null_theory_var) {
|
||||
proc = th->mk_value(r, *this);
|
||||
SASSERT(proc);
|
||||
}
|
||||
else {
|
||||
TRACE("model_bug", tout << "creating fresh value for #" << r->get_owner_id() << "\n";);
|
||||
|
@ -110,6 +111,7 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
proc = mk_model_value(r);
|
||||
SASSERT(proc);
|
||||
}
|
||||
}
|
||||
SASSERT(proc);
|
||||
|
|
|
@ -335,6 +335,10 @@ namespace smt {
|
|||
return m_imp->m_plugin->model_based();
|
||||
}
|
||||
|
||||
bool quantifier_manager::mbqi_enabled(quantifier *q) const {
|
||||
return m_imp->m_plugin->mbqi_enabled(q);
|
||||
}
|
||||
|
||||
void quantifier_manager::adjust_model(proto_model * m) {
|
||||
m_imp->m_plugin->adjust_model(m);
|
||||
}
|
||||
|
@ -434,8 +438,22 @@ namespace smt {
|
|||
|
||||
virtual bool model_based() const { return m_fparams->m_mbqi; }
|
||||
|
||||
virtual bool mbqi_enabled(quantifier *q) const {
|
||||
if(!m_fparams->m_mbqi_id) return true;
|
||||
const symbol &s = q->get_qid();
|
||||
size_t len = strlen(m_fparams->m_mbqi_id);
|
||||
if(s == symbol::null || s.is_numerical())
|
||||
return len == 0;
|
||||
return strncmp(s.bare_str(),m_fparams->m_mbqi_id,len) == 0;
|
||||
}
|
||||
|
||||
/* Quantifier id's must begin with the prefix specified by
|
||||
parameter mbqi.id to be instantiated with MBQI. The default
|
||||
value is the empty string, so all quantifiers are
|
||||
instantiated.
|
||||
*/
|
||||
virtual void add(quantifier * q) {
|
||||
if (m_fparams->m_mbqi) {
|
||||
if (m_fparams->m_mbqi && mbqi_enabled(q)) {
|
||||
m_model_finder->register_quantifier(q);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ namespace smt {
|
|||
};
|
||||
|
||||
bool model_based() const;
|
||||
bool mbqi_enabled(quantifier *q) const; // can mbqi instantiate this quantifier?
|
||||
void adjust_model(proto_model * m);
|
||||
check_model_result check_model(proto_model * m, obj_map<enode, app *> const & root2value);
|
||||
|
||||
|
@ -144,6 +145,11 @@ namespace smt {
|
|||
*/
|
||||
virtual bool model_based() const = 0;
|
||||
|
||||
/**
|
||||
\brief Is "model based" instantiate allowed to instantiate this quantifier?
|
||||
*/
|
||||
virtual bool mbqi_enabled(quantifier *q) const {return true;}
|
||||
|
||||
/**
|
||||
\brief Give a change to the plugin to adjust the interpretation of unintepreted functions.
|
||||
It can basically change the "else" of each uninterpreted function.
|
||||
|
|
|
@ -22,7 +22,6 @@ 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"
|
||||
|
@ -725,12 +724,6 @@ 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));
|
||||
|
|
|
@ -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;
|
||||
|
@ -104,7 +104,7 @@ protected:
|
|||
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);
|
||||
|
@ -119,7 +119,7 @@ protected:
|
|||
{
|
||||
m_solver.push();
|
||||
expr_ref fml1(m);
|
||||
fml1 = m.mk_and(fmls.size(), fmls.c_ptr());
|
||||
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);
|
||||
|
@ -139,22 +139,32 @@ protected:
|
|||
SASSERT(g.is_well_sorted());
|
||||
}
|
||||
|
||||
struct expr_pos {
|
||||
unsigned m_parent;
|
||||
unsigned m_self;
|
||||
unsigned m_idx;
|
||||
expr* m_expr;
|
||||
expr_pos(unsigned p, unsigned s, unsigned i, expr* e):
|
||||
m_parent(p), m_self(s), m_idx(i), m_expr(e)
|
||||
{}
|
||||
expr_pos():
|
||||
m_parent(0), m_self(0), m_idx(0), m_expr(0)
|
||||
{}
|
||||
};
|
||||
|
||||
void reduce(expr_ref& result){
|
||||
SASSERT(m.is_bool(result));
|
||||
ptr_vector<expr> todo;
|
||||
ptr_vector<expr> names;
|
||||
svector<bool> is_checked;
|
||||
svector<unsigned> parent_ids, self_ids;
|
||||
svector<expr_pos> todo;
|
||||
expr_ref_vector fresh_vars(m), trail(m);
|
||||
expr_ref res(m), tmp(m);
|
||||
obj_map<expr,std::pair<unsigned, expr*> > cache;
|
||||
unsigned id = 1;
|
||||
obj_map<expr, expr_pos> cache;
|
||||
unsigned id = 1, child_id = 0;
|
||||
expr_ref n2(m), fml(m);
|
||||
unsigned path_id = 0, self_pos = 0;
|
||||
unsigned parent_pos = 0, self_pos = 0, self_idx = 0;
|
||||
app * a;
|
||||
unsigned sz;
|
||||
std::pair<unsigned,expr*> path_r;
|
||||
ptr_vector<expr> found;
|
||||
expr_pos path_r;
|
||||
expr_ref_vector args(m);
|
||||
expr_ref n = mk_fresh(id, m.mk_bool_sort());
|
||||
trail.push_back(n);
|
||||
|
@ -163,26 +173,25 @@ protected:
|
|||
tmp = m.mk_not(m.mk_iff(fml, n));
|
||||
m_solver.assert_expr(tmp);
|
||||
|
||||
todo.push_back(fml);
|
||||
todo.push_back(expr_pos(0,0,0,fml));
|
||||
names.push_back(n);
|
||||
is_checked.push_back(false);
|
||||
parent_ids.push_back(0);
|
||||
self_ids.push_back(0);
|
||||
m_solver.push();
|
||||
|
||||
while (!todo.empty() && !m_cancel) {
|
||||
expr_ref res(m);
|
||||
args.reset();
|
||||
expr* e = todo.back();
|
||||
unsigned pos = parent_ids.back();
|
||||
expr* e = todo.back().m_expr;
|
||||
self_pos = todo.back().m_self;
|
||||
parent_pos = todo.back().m_parent;
|
||||
self_idx = todo.back().m_idx;
|
||||
n = names.back();
|
||||
bool checked = is_checked.back();
|
||||
|
||||
if (cache.contains(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";);
|
||||
if (m.is_bool(e) && simplify_bool(n, res)) {
|
||||
TRACE("ctx_solver_simplify_tactic",
|
||||
tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";);
|
||||
goto done;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
|
@ -191,49 +200,31 @@ protected:
|
|||
}
|
||||
|
||||
a = to_app(e);
|
||||
if (!is_checked.back()) {
|
||||
self_ids.back() = ++path_id;
|
||||
is_checked.back() = true;
|
||||
}
|
||||
self_pos = self_ids.back();
|
||||
sz = a->get_num_args();
|
||||
|
||||
sz = a->get_num_args();
|
||||
n2 = 0;
|
||||
|
||||
found.reset(); // arguments already simplified.
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr* arg = a->get_arg(i);
|
||||
if (cache.find(arg, path_r) && !found.contains(arg)) {
|
||||
if (cache.find(arg, path_r)) {
|
||||
//
|
||||
// This is a single traversal version of the context
|
||||
// simplifier. It simplifies only the first occurrence of
|
||||
// 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) << " |-> " << mk_pp(path_r.second, m) << "\n";);
|
||||
args.push_back(path_r.second);
|
||||
}
|
||||
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";);
|
||||
args.push_back(res);
|
||||
if (path_r.m_parent == self_pos && path_r.m_idx == i) {
|
||||
args.push_back(path_r.m_expr);
|
||||
}
|
||||
else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
else if (!n2 && !found.contains(arg)) {
|
||||
else if (!n2) {
|
||||
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);
|
||||
todo.push_back(expr_pos(self_pos, child_id++, i, arg));
|
||||
names.push_back(n2);
|
||||
args.push_back(n2);
|
||||
is_checked.push_back(false);
|
||||
}
|
||||
else {
|
||||
args.push_back(arg);
|
||||
|
@ -251,22 +242,16 @@ protected:
|
|||
|
||||
done:
|
||||
if (res) {
|
||||
cache.insert(e, std::make_pair(pos, res));
|
||||
}
|
||||
|
||||
TRACE("ctx_solver_simplify_tactic",
|
||||
tout << mk_pp(e, m) << " checked: " << checked << " cached: " << mk_pp(res?res.get():e, m) << "\n";);
|
||||
cache.insert(e, expr_pos(parent_pos, self_pos, self_idx, res));
|
||||
}
|
||||
|
||||
todo.pop_back();
|
||||
parent_ids.pop_back();
|
||||
self_ids.pop_back();
|
||||
names.pop_back();
|
||||
is_checked.pop_back();
|
||||
m_solver.pop(1);
|
||||
}
|
||||
if (!m_cancel) {
|
||||
VERIFY(cache.find(fml, path_r));
|
||||
result = path_r.second;
|
||||
result = path_r.m_expr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,32 +291,6 @@ protected:
|
|||
}
|
||||
return expr_ref(m.mk_app(fn, m_arith.mk_numeral(rational(id++), true)), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) {
|
||||
SASSERT(index < a->get_num_args());
|
||||
SASSERT(m.is_bool(a->get_arg(index)));
|
||||
expr_ref n2(m), result(m), tmp(m);
|
||||
n2 = mk_fresh(id, m.get_sort(a->get_arg(index)));
|
||||
ptr_buffer<expr> args;
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
if (i == index) {
|
||||
args.push_back(n2);
|
||||
}
|
||||
else {
|
||||
args.push_back(a->get_arg(i));
|
||||
}
|
||||
}
|
||||
m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result);
|
||||
m_solver.push();
|
||||
tmp = m.mk_eq(result, n);
|
||||
m_solver.assert_expr(tmp);
|
||||
if (!simplify_bool(n2, result)) {
|
||||
result = a;
|
||||
}
|
||||
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
|
|
@ -85,6 +85,7 @@ namespace smt {
|
|||
typedef typename Ext::numeral numeral;
|
||||
typedef typename Ext::inf_numeral inf_numeral;
|
||||
typedef vector<numeral> numeral_vector;
|
||||
typedef map<rational, theory_var, obj_hash<rational>, default_eq<rational> > rational2var;
|
||||
|
||||
static const int dead_row_id = -1;
|
||||
protected:
|
||||
|
@ -409,6 +410,7 @@ namespace smt {
|
|||
atoms m_atoms; // set of theory atoms
|
||||
ptr_vector<bound> m_asserted_bounds; // set of asserted bounds
|
||||
unsigned m_asserted_qhead;
|
||||
ptr_vector<atom> m_new_atoms; // new bound atoms that have yet to be internalized.
|
||||
svector<theory_var> m_nl_monomials; // non linear monomials
|
||||
svector<theory_var> m_nl_propagated; // non linear monomials that became linear
|
||||
v_dependency_manager m_dep_manager; // for tracking bounds during non-linear reasoning
|
||||
|
@ -569,6 +571,22 @@ namespace smt {
|
|||
void mk_clause(literal l1, literal l2, unsigned num_params, parameter * params);
|
||||
void mk_clause(literal l1, literal l2, literal l3, unsigned num_params, parameter * params);
|
||||
void mk_bound_axioms(atom * a);
|
||||
void mk_bound_axiom(atom* a1, atom* a2);
|
||||
void flush_bound_axioms();
|
||||
typename atoms::iterator next_sup(atom* a1, atom_kind kind,
|
||||
typename atoms::iterator it,
|
||||
typename atoms::iterator end,
|
||||
bool& found_compatible);
|
||||
typename atoms::iterator next_inf(atom* a1, atom_kind kind,
|
||||
typename atoms::iterator it,
|
||||
typename atoms::iterator end,
|
||||
bool& found_compatible);
|
||||
typename atoms::iterator first(atom_kind kind,
|
||||
typename atoms::iterator it,
|
||||
typename atoms::iterator end);
|
||||
struct compare_atoms {
|
||||
bool operator()(atom* a1, atom* a2) const { return a1->get_k() < a2->get_k(); }
|
||||
};
|
||||
virtual bool default_internalizer() const { return false; }
|
||||
virtual bool internalize_atom(app * n, bool gate_ctx);
|
||||
virtual bool internalize_term(app * term);
|
||||
|
|
|
@ -475,10 +475,11 @@ namespace smt {
|
|||
bool theory_arith<Ext>::all_coeff_int(row const & r) const {
|
||||
typename vector<row_entry>::const_iterator it = r.begin_entries();
|
||||
typename vector<row_entry>::const_iterator end = r.end_entries();
|
||||
for (; it != end; ++it) {
|
||||
if (!it->is_dead() && !it->m_coeff.is_int())
|
||||
for (; it != end; ++it) {
|
||||
if (!it->is_dead() && !it->m_coeff.is_int())
|
||||
TRACE("gomory_cut", display_row(tout, r, true););
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -348,13 +348,24 @@ namespace smt {
|
|||
context & ctx = get_context();
|
||||
simplifier & s = ctx.get_simplifier();
|
||||
expr_ref s_ante(m), s_conseq(m);
|
||||
expr* s_conseq_n, * s_ante_n;
|
||||
bool negated;
|
||||
proof_ref pr(m);
|
||||
|
||||
s(ante, s_ante, pr);
|
||||
negated = m.is_not(s_ante, s_ante_n);
|
||||
if (negated) s_ante = s_ante_n;
|
||||
ctx.internalize(s_ante, false);
|
||||
literal l_ante = ctx.get_literal(s_ante);
|
||||
if (negated) l_ante.neg();
|
||||
|
||||
s(conseq, s_conseq, pr);
|
||||
negated = m.is_not(s_conseq, s_conseq_n);
|
||||
if (negated) s_conseq = s_conseq_n;
|
||||
ctx.internalize(s_conseq, false);
|
||||
literal l_conseq = ctx.get_literal(s_conseq);
|
||||
if (negated) l_conseq.neg();
|
||||
|
||||
literal lits[2] = {l_ante, l_conseq};
|
||||
ctx.mk_th_axiom(get_id(), 2, lits);
|
||||
if (ctx.relevancy()) {
|
||||
|
@ -800,48 +811,238 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
void theory_arith<Ext>::mk_bound_axioms(atom * a1) {
|
||||
theory_var v = a1->get_var();
|
||||
literal l1(a1->get_bool_var());
|
||||
atoms & occs = m_var_occs[v];
|
||||
if (!get_context().is_searching()) {
|
||||
//
|
||||
// NB. We make an assumption that user push calls propagation
|
||||
// before internal scopes are pushed. This flushes all newly
|
||||
// asserted atoms into the right context.
|
||||
//
|
||||
m_new_atoms.push_back(a1);
|
||||
return;
|
||||
}
|
||||
numeral const & k1(a1->get_k());
|
||||
atom_kind kind1 = a1->get_atom_kind();
|
||||
TRACE("mk_bound_axioms", tout << "making bound axioms for v" << v << " " << kind1 << " " << k1 << "\n";);
|
||||
atoms & occs = m_var_occs[v];
|
||||
typename atoms::iterator it = occs.begin();
|
||||
typename atoms::iterator end = occs.end();
|
||||
|
||||
typename atoms::iterator lo_inf = end, lo_sup = end;
|
||||
typename atoms::iterator hi_inf = end, hi_sup = end;
|
||||
for (; it != end; ++it) {
|
||||
atom * a2 = *it;
|
||||
literal l2(a2->get_bool_var());
|
||||
numeral const & k2 = a2->get_k();
|
||||
atom_kind kind2 = a2->get_atom_kind();
|
||||
atom * a2 = *it;
|
||||
numeral const & k2(a2->get_k());
|
||||
atom_kind kind2 = a2->get_atom_kind();
|
||||
SASSERT(k1 != k2 || kind1 != kind2);
|
||||
SASSERT(a2->get_var() == v);
|
||||
parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) };
|
||||
if (kind1 == A_LOWER) {
|
||||
if (kind2 == A_LOWER) {
|
||||
// x >= k1, x >= k2
|
||||
if (k1 >= k2) mk_clause(~l1, l2, 3, coeffs);
|
||||
else mk_clause(~l2, l1, 3, coeffs);
|
||||
if (kind2 == A_LOWER) {
|
||||
if (k2 < k1) {
|
||||
if (lo_inf == end || k2 > (*lo_inf)->get_k()) {
|
||||
lo_inf = it;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// x >= k1, x <= k2
|
||||
if (k1 > k2) mk_clause(~l1, ~l2, 3, coeffs);
|
||||
else mk_clause(l1, l2, 3, coeffs);
|
||||
else if (lo_sup == end || k2 < (*lo_sup)->get_k()) {
|
||||
lo_sup = it;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (kind2 == A_LOWER) {
|
||||
// x <= k1, x >= k2
|
||||
if (k1 < k2) mk_clause(~l1, ~l2, 3, coeffs);
|
||||
else mk_clause(l1, l2, 3, coeffs);
|
||||
else if (k2 < k1) {
|
||||
if (hi_inf == end || k2 > (*hi_inf)->get_k()) {
|
||||
hi_inf = it;
|
||||
}
|
||||
}
|
||||
else if (hi_sup == end || k2 < (*hi_sup)->get_k()) {
|
||||
hi_sup = it;
|
||||
}
|
||||
}
|
||||
if (lo_inf != end) mk_bound_axiom(a1, *lo_inf);
|
||||
if (lo_sup != end) mk_bound_axiom(a1, *lo_sup);
|
||||
if (hi_inf != end) mk_bound_axiom(a1, *hi_inf);
|
||||
if (hi_sup != end) mk_bound_axiom(a1, *hi_sup);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::mk_bound_axiom(atom* a1, atom* a2) {
|
||||
theory_var v = a1->get_var();
|
||||
literal l1(a1->get_bool_var());
|
||||
literal l2(a2->get_bool_var());
|
||||
numeral const & k1(a1->get_k());
|
||||
numeral const & k2(a2->get_k());
|
||||
atom_kind kind1 = a1->get_atom_kind();
|
||||
atom_kind kind2 = a2->get_atom_kind();
|
||||
bool v_is_int = is_int(v);
|
||||
SASSERT(v == a2->get_var());
|
||||
SASSERT(k1 != k2 || kind1 != kind2);
|
||||
parameter coeffs[3] = { parameter(symbol("farkas")),
|
||||
parameter(rational(1)), parameter(rational(1)) };
|
||||
|
||||
if (kind1 == A_LOWER) {
|
||||
if (kind2 == A_LOWER) {
|
||||
if (k2 <= k1) {
|
||||
mk_clause(~l1, l2, 3, coeffs);
|
||||
}
|
||||
else {
|
||||
// x <= k1, x <= k2
|
||||
if (k1 < k2) mk_clause(~l1, l2, 3, coeffs);
|
||||
else mk_clause(~l2, l1, 3, coeffs);
|
||||
mk_clause(l1, ~l2, 3, coeffs);
|
||||
}
|
||||
}
|
||||
else if (k1 <= k2) {
|
||||
// k1 <= k2, k1 <= x or x <= k2
|
||||
mk_clause(l1, l2, 3, coeffs);
|
||||
}
|
||||
else {
|
||||
// k1 > hi_inf, k1 <= x => ~(x <= hi_inf)
|
||||
mk_clause(~l1, ~l2, 3, coeffs);
|
||||
if (v_is_int && k1 == k2 + numeral(1)) {
|
||||
// k1 <= x or x <= k1-1
|
||||
mk_clause(l1, l2, 3, coeffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (kind2 == A_LOWER) {
|
||||
if (k1 >= k2) {
|
||||
// k1 >= lo_inf, k1 >= x or lo_inf <= x
|
||||
mk_clause(l1, l2, 3, coeffs);
|
||||
}
|
||||
else {
|
||||
// k1 < k2, k2 <= x => ~(x <= k1)
|
||||
mk_clause(~l1, ~l2, 3, coeffs);
|
||||
if (v_is_int && k1 == k2 - numeral(1)) {
|
||||
// x <= k1 or k1+l <= x
|
||||
mk_clause(l1, l2, 3, coeffs);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
// kind1 == A_UPPER, kind2 == A_UPPER
|
||||
if (k1 >= k2) {
|
||||
// k1 >= k2, x <= k2 => x <= k1
|
||||
mk_clause(l1, ~l2, 3, coeffs);
|
||||
}
|
||||
else {
|
||||
// k1 <= hi_sup , x <= k1 => x <= hi_sup
|
||||
mk_clause(~l1, l2, 3, coeffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::flush_bound_axioms() {
|
||||
while (!m_new_atoms.empty()) {
|
||||
ptr_vector<atom> atoms;
|
||||
atoms.push_back(m_new_atoms.back());
|
||||
m_new_atoms.pop_back();
|
||||
theory_var v = atoms.back()->get_var();
|
||||
for (unsigned i = 0; i < m_new_atoms.size(); ++i) {
|
||||
if (m_new_atoms[i]->get_var() == v) {
|
||||
atoms.push_back(m_new_atoms[i]);
|
||||
m_new_atoms[i] = m_new_atoms.back();
|
||||
m_new_atoms.pop_back();
|
||||
--i;
|
||||
}
|
||||
}
|
||||
ptr_vector<atom> occs(m_var_occs[v]);
|
||||
|
||||
std::sort(atoms.begin(), atoms.end(), compare_atoms());
|
||||
std::sort(occs.begin(), occs.end(), compare_atoms());
|
||||
|
||||
typename atoms::iterator begin1 = occs.begin();
|
||||
typename atoms::iterator begin2 = occs.begin();
|
||||
typename atoms::iterator end = occs.end();
|
||||
begin1 = first(A_LOWER, begin1, end);
|
||||
begin2 = first(A_UPPER, begin2, end);
|
||||
|
||||
typename atoms::iterator lo_inf = begin1, lo_sup = begin1;
|
||||
typename atoms::iterator hi_inf = begin2, hi_sup = begin2;
|
||||
typename atoms::iterator lo_inf1 = begin1, lo_sup1 = begin1;
|
||||
typename atoms::iterator hi_inf1 = begin2, hi_sup1 = begin2;
|
||||
bool flo_inf, fhi_inf, flo_sup, fhi_sup;
|
||||
ptr_addr_hashtable<atom> visited;
|
||||
for (unsigned i = 0; i < atoms.size(); ++i) {
|
||||
atom* a1 = atoms[i];
|
||||
lo_inf1 = next_inf(a1, A_LOWER, lo_inf, end, flo_inf);
|
||||
hi_inf1 = next_inf(a1, A_UPPER, hi_inf, end, fhi_inf);
|
||||
lo_sup1 = next_sup(a1, A_LOWER, lo_sup, end, flo_sup);
|
||||
hi_sup1 = next_sup(a1, A_UPPER, hi_sup, end, fhi_sup);
|
||||
if (lo_inf1 != end) lo_inf = lo_inf1;
|
||||
if (lo_sup1 != end) lo_sup = lo_sup1;
|
||||
if (hi_inf1 != end) hi_inf = hi_inf1;
|
||||
if (hi_sup1 != end) hi_sup = hi_sup1;
|
||||
if (!flo_inf) lo_inf = end;
|
||||
if (!fhi_inf) hi_inf = end;
|
||||
if (!flo_sup) lo_sup = end;
|
||||
if (!fhi_sup) hi_sup = end;
|
||||
visited.insert(a1);
|
||||
if (lo_inf1 != end && lo_inf != end && !visited.contains(*lo_inf)) mk_bound_axiom(a1, *lo_inf);
|
||||
if (lo_sup1 != end && lo_sup != end && !visited.contains(*lo_sup)) mk_bound_axiom(a1, *lo_sup);
|
||||
if (hi_inf1 != end && hi_inf != end && !visited.contains(*hi_inf)) mk_bound_axiom(a1, *hi_inf);
|
||||
if (hi_sup1 != end && hi_sup != end && !visited.contains(*hi_sup)) mk_bound_axiom(a1, *hi_sup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
typename theory_arith<Ext>::atoms::iterator
|
||||
theory_arith<Ext>::first(
|
||||
atom_kind kind,
|
||||
typename atoms::iterator it,
|
||||
typename atoms::iterator end) {
|
||||
for (; it != end; ++it) {
|
||||
atom* a = *it;
|
||||
if (a->get_atom_kind() == kind) return it;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
typename theory_arith<Ext>::atoms::iterator
|
||||
theory_arith<Ext>::next_inf(
|
||||
atom* a1,
|
||||
atom_kind kind,
|
||||
typename atoms::iterator it,
|
||||
typename atoms::iterator end,
|
||||
bool& found_compatible) {
|
||||
numeral const & k1(a1->get_k());
|
||||
typename atoms::iterator result = end;
|
||||
found_compatible = false;
|
||||
for (; it != end; ++it) {
|
||||
atom * a2 = *it;
|
||||
if (a1 == a2) continue;
|
||||
if (a2->get_atom_kind() != kind) continue;
|
||||
numeral const & k2(a2->get_k());
|
||||
found_compatible = true;
|
||||
if (k2 <= k1) {
|
||||
result = it;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
typename theory_arith<Ext>::atoms::iterator
|
||||
theory_arith<Ext>::next_sup(
|
||||
atom* a1,
|
||||
atom_kind kind,
|
||||
typename atoms::iterator it,
|
||||
typename atoms::iterator end,
|
||||
bool& found_compatible) {
|
||||
numeral const & k1(a1->get_k());
|
||||
found_compatible = false;
|
||||
for (; it != end; ++it) {
|
||||
atom * a2 = *it;
|
||||
if (a1 == a2) continue;
|
||||
if (a2->get_atom_kind() != kind) continue;
|
||||
numeral const & k2(a2->get_k());
|
||||
found_compatible = true;
|
||||
if (k1 < k2) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::internalize_atom(app * n, bool gate_ctx) {
|
||||
TRACE("arith_internalize", tout << "internalising atom:\n" << mk_pp(n, this->get_manager()) << "\n";);
|
||||
|
@ -879,7 +1080,7 @@ namespace smt {
|
|||
bool_var bv = ctx.mk_bool_var(n);
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
rational _k;
|
||||
m_util.is_numeral(rhs, _k);
|
||||
VERIFY(m_util.is_numeral(rhs, _k));
|
||||
numeral k(_k);
|
||||
atom * a = alloc(atom, bv, v, k, kind);
|
||||
mk_bound_axioms(a);
|
||||
|
@ -927,6 +1128,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||
TRACE("arith", tout << "v" << v << " " << is_true << "\n";);
|
||||
atom * a = get_bv2a(v);
|
||||
if (!a) return;
|
||||
SASSERT(get_context().get_assignment(a->get_bool_var()) != l_undef);
|
||||
|
@ -1072,8 +1274,10 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
while (m_final_check_idx != old_idx);
|
||||
if (result == FC_DONE && m_found_unsupported_op)
|
||||
if (result == FC_DONE && m_found_unsupported_op) {
|
||||
TRACE("arith", tout << "Found unsupported operation\n";);
|
||||
result = FC_GIVEUP;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1142,6 +1346,7 @@ namespace smt {
|
|||
CASSERT("arith", wf_columns());
|
||||
CASSERT("arith", valid_row_assignment());
|
||||
|
||||
flush_bound_axioms();
|
||||
propagate_linear_monomials();
|
||||
while (m_asserted_qhead < m_asserted_bounds.size()) {
|
||||
bound * b = m_asserted_bounds[m_asserted_qhead];
|
||||
|
@ -2421,6 +2626,8 @@ namespace smt {
|
|||
if (val == l_undef)
|
||||
continue;
|
||||
// TODO: check if the following line is a bottleneck
|
||||
TRACE("arith", tout << "v" << a->get_bool_var() << " " << (val == l_true) << "\n";);
|
||||
|
||||
a->assign_eh(val == l_true, get_epsilon(a->get_var()));
|
||||
if (val != l_undef && a->get_bound_kind() == b->get_bound_kind()) {
|
||||
SASSERT((ctx.get_assignment(bv) == l_true) == a->is_true());
|
||||
|
@ -2780,7 +2987,6 @@ namespace smt {
|
|||
*/
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::refine_epsilon() {
|
||||
typedef map<rational, theory_var, obj_hash<rational>, default_eq<rational> > rational2var;
|
||||
while (true) {
|
||||
rational2var mapping;
|
||||
theory_var num = get_num_vars();
|
||||
|
@ -2788,6 +2994,8 @@ namespace smt {
|
|||
for (theory_var v = 0; v < num; v++) {
|
||||
if (is_int(v))
|
||||
continue;
|
||||
if (!get_context().is_shared(get_enode(v)))
|
||||
continue;
|
||||
inf_numeral const & val = get_value(v);
|
||||
rational value = val.get_rational().to_rational() + m_epsilon.to_rational() * val.get_infinitesimal().to_rational();
|
||||
theory_var v2;
|
||||
|
@ -2915,6 +3123,7 @@ namespace smt {
|
|||
SASSERT(m_to_patch.empty());
|
||||
m_to_check.reset();
|
||||
m_in_to_check.reset();
|
||||
m_new_atoms.reset();
|
||||
CASSERT("arith", wf_rows());
|
||||
CASSERT("arith", wf_columns());
|
||||
CASSERT("arith", valid_row_assignment());
|
||||
|
|
|
@ -193,7 +193,7 @@ namespace smt {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!r.get_base_var() == x && x > y) {
|
||||
if (r.get_base_var() != x && x > y) {
|
||||
std::swap(x, y);
|
||||
k.neg();
|
||||
}
|
||||
|
|
|
@ -1294,8 +1294,10 @@ namespace smt {
|
|||
}
|
||||
tout << "max: " << max << ", min: " << min << "\n";);
|
||||
|
||||
if (m_params.m_arith_ignore_int)
|
||||
if (m_params.m_arith_ignore_int) {
|
||||
TRACE("arith", tout << "Ignore int: give up\n";);
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
|
||||
if (!gcd_test())
|
||||
return FC_CONTINUE;
|
||||
|
|
|
@ -654,6 +654,7 @@ namespace smt {
|
|||
}
|
||||
return get_value(v, computed_epsilon) == val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Return true if for every monomial x_1 * ... * x_n,
|
||||
|
@ -2309,16 +2310,19 @@ namespace smt {
|
|||
if (m_nl_monomials.empty())
|
||||
return FC_DONE;
|
||||
|
||||
if (check_monomial_assignments())
|
||||
if (check_monomial_assignments()) {
|
||||
return FC_DONE;
|
||||
}
|
||||
|
||||
if (!m_params.m_nl_arith)
|
||||
if (!m_params.m_nl_arith) {
|
||||
TRACE("non_linear", tout << "Non-linear is not enabled\n";);
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
|
||||
TRACE("process_non_linear", display(tout););
|
||||
|
||||
if (m_nl_rounds > m_params.m_nl_arith_rounds) {
|
||||
TRACE("non_linear", tout << "GIVE UP non linear problem...\n";);
|
||||
TRACE("non_linear", tout << "GIVEUP non linear problem...\n";);
|
||||
IF_VERBOSE(3, verbose_stream() << "Max. non linear arithmetic rounds. Increase threshold using NL_ARITH_ROUNDS=<limit>\n";);
|
||||
return FC_GIVEUP;
|
||||
}
|
||||
|
@ -2338,9 +2342,10 @@ namespace smt {
|
|||
if (!max_min_nl_vars())
|
||||
return FC_CONTINUE;
|
||||
|
||||
if (check_monomial_assignments())
|
||||
if (check_monomial_assignments()) {
|
||||
return m_liberal_final_check || !m_changed_assignment ? FC_DONE : FC_CONTINUE;
|
||||
|
||||
}
|
||||
|
||||
svector<theory_var> vars;
|
||||
get_non_linear_cluster(vars);
|
||||
|
||||
|
@ -2391,8 +2396,9 @@ namespace smt {
|
|||
}
|
||||
while (m_nl_strategy_idx != old_idx);
|
||||
|
||||
if (check_monomial_assignments())
|
||||
if (check_monomial_assignments()) {
|
||||
return m_liberal_final_check || !m_changed_assignment ? FC_DONE : FC_CONTINUE;
|
||||
}
|
||||
|
||||
TRACE("non_linear", display(tout););
|
||||
|
||||
|
|
|
@ -376,8 +376,10 @@ namespace smt {
|
|||
enode_vector::const_iterator end = r->end_parents();
|
||||
for (; it != end; ++it) {
|
||||
enode * parent = *it;
|
||||
#if 0
|
||||
if (!ctx.is_relevant(parent))
|
||||
continue;
|
||||
#endif
|
||||
unsigned num_args = parent->get_num_args();
|
||||
if (is_store(parent)) {
|
||||
SET_ARRAY(parent->get_arg(0));
|
||||
|
@ -399,6 +401,7 @@ namespace smt {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void theory_array_base::collect_shared_vars(sbuffer<theory_var> & result) {
|
||||
TRACE("array_shared", tout << "collecting shared vars...\n";);
|
||||
context & ctx = get_context();
|
||||
|
@ -420,6 +423,31 @@ namespace smt {
|
|||
}
|
||||
unmark_enodes(to_unmark.size(), to_unmark.c_ptr());
|
||||
}
|
||||
#else
|
||||
void theory_array_base::collect_shared_vars(sbuffer<theory_var> & result) {
|
||||
TRACE("array_shared", tout << "collecting shared vars...\n";);
|
||||
context & ctx = get_context();
|
||||
ptr_buffer<enode> to_unmark;
|
||||
unsigned num_vars = get_num_vars();
|
||||
for (unsigned i = 0; i < num_vars; i++) {
|
||||
enode * n = get_enode(i);
|
||||
if (ctx.is_relevant(n)) {
|
||||
enode * r = n->get_root();
|
||||
if (!r->is_marked()){
|
||||
if(is_array_sort(r) && ctx.is_shared(r)) {
|
||||
TRACE("array_shared", tout << "new shared var: #" << r->get_owner_id() << "\n";);
|
||||
theory_var r_th_var = r->get_th_var(get_id());
|
||||
SASSERT(r_th_var != null_theory_var);
|
||||
result.push_back(r_th_var);
|
||||
}
|
||||
r->set_mark();
|
||||
to_unmark.push_back(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
unmark_enodes(to_unmark.size(), to_unmark.c_ptr());
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Create interface variables for shared array variables.
|
||||
|
@ -688,7 +716,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 +908,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)));
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace smt {
|
|||
unsigned bv_size = get_bv_size(n);
|
||||
context & ctx = get_context();
|
||||
literal_vector & bits = m_bits[v];
|
||||
bits.reset();
|
||||
for (unsigned i = 0; i < bv_size; i++) {
|
||||
app * bit = mk_bit2bool(owner, i);
|
||||
ctx.internalize(bit, true);
|
||||
|
@ -75,12 +76,14 @@ namespace smt {
|
|||
void theory_bv::mk_bit2bool(app * n) {
|
||||
context & ctx = get_context();
|
||||
SASSERT(!ctx.b_internalized(n));
|
||||
if (!ctx.e_internalized(n->get_arg(0))) {
|
||||
|
||||
expr* first_arg = n->get_arg(0);
|
||||
|
||||
if (!ctx.e_internalized(first_arg)) {
|
||||
// This may happen if bit2bool(x) is in a conflict
|
||||
// clause that is being reinitialized, and x was not reinitialized
|
||||
// yet.
|
||||
// So, we internalize x (i.e., n->get_arg(0))
|
||||
expr * first_arg = n->get_arg(0);
|
||||
// So, we internalize x (i.e., arg)
|
||||
ctx.internalize(first_arg, false);
|
||||
SASSERT(ctx.e_internalized(first_arg));
|
||||
// In most cases, when x is internalized, its bits are created.
|
||||
|
@ -91,10 +94,27 @@ namespace smt {
|
|||
// This will also force the creation of all bits for x.
|
||||
enode * first_arg_enode = ctx.get_enode(first_arg);
|
||||
get_var(first_arg_enode);
|
||||
SASSERT(ctx.b_internalized(n));
|
||||
// numerals are not blasted into bit2bool, so we do this directly.
|
||||
if (!ctx.b_internalized(n)) {
|
||||
rational val;
|
||||
unsigned sz;
|
||||
VERIFY(m_util.is_numeral(first_arg, val, sz));
|
||||
theory_var v = first_arg_enode->get_th_var(get_id());
|
||||
app* owner = first_arg_enode->get_owner();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
ctx.internalize(mk_bit2bool(owner, i), true);
|
||||
}
|
||||
m_bits[v].reset();
|
||||
rational bit;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
div(val, rational::power_of_two(i), bit);
|
||||
mod(bit, rational(2), bit);
|
||||
m_bits[v].push_back(bit.is_zero()?false_literal:true_literal);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
enode * arg = ctx.get_enode(n->get_arg(0));
|
||||
enode * arg = ctx.get_enode(first_arg);
|
||||
// The argument was already internalized, but it may not have a theory variable associated with it.
|
||||
// For example, for ite-terms the method apply_sort_cnstr is not invoked.
|
||||
// See comment in the then-branch.
|
||||
|
@ -581,10 +601,13 @@ namespace smt {
|
|||
void theory_bv::assert_int2bv_axiom(app* n) {
|
||||
//
|
||||
// create the axiom:
|
||||
// bv2int(n) = e mod 2^bit_width
|
||||
//
|
||||
// bv2int(n) = e mod 2^bit_width
|
||||
// where n = int2bv(e)
|
||||
//
|
||||
// Create the axioms:
|
||||
// bit2bool(i,n) == ((e div 2^i) mod 2 != 0)
|
||||
// for i = 0,.., sz-1
|
||||
//
|
||||
SASSERT(get_context().e_internalized(n));
|
||||
SASSERT(m_util.is_int2bv(n));
|
||||
ast_manager & m = get_manager();
|
||||
|
@ -592,10 +615,12 @@ namespace smt {
|
|||
|
||||
parameter param(m_autil.mk_int());
|
||||
expr* n_expr = n;
|
||||
expr* lhs = m.mk_app(get_id(), OP_BV2INT, 1, ¶m, 1, &n_expr);
|
||||
expr* e = n->get_arg(0);
|
||||
expr_ref lhs(m), rhs(m);
|
||||
lhs = m.mk_app(get_id(), OP_BV2INT, 1, ¶m, 1, &n_expr);
|
||||
unsigned sz = m_util.get_bv_size(n);
|
||||
numeral mod = power(numeral(2), sz);
|
||||
expr* rhs = m_autil.mk_mod(n->get_arg(0), m_autil.mk_numeral(mod, true));
|
||||
rhs = m_autil.mk_mod(e, m_autil.mk_numeral(mod, true));
|
||||
|
||||
literal l(mk_eq(lhs, rhs, false));
|
||||
ctx.mark_as_relevant(l);
|
||||
|
@ -605,6 +630,24 @@ namespace smt {
|
|||
tout << mk_pp(lhs, m) << " == \n";
|
||||
tout << mk_pp(rhs, m) << "\n";
|
||||
);
|
||||
|
||||
expr_ref_vector n_bits(m);
|
||||
enode * n_enode = mk_enode(n);
|
||||
get_bits(n_enode, n_bits);
|
||||
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
numeral div = power(numeral(2), i);
|
||||
mod = numeral(2);
|
||||
rhs = m_autil.mk_idiv(e, m_autil.mk_numeral(div,true));
|
||||
rhs = m_autil.mk_mod(rhs, m_autil.mk_numeral(mod, true));
|
||||
rhs = m.mk_eq(rhs, m_autil.mk_numeral(rational(1), true));
|
||||
lhs = n_bits.get(i);
|
||||
TRACE("bv", tout << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << "\n";);
|
||||
l = literal(mk_eq(lhs, rhs, false));
|
||||
ctx.mark_as_relevant(l);
|
||||
ctx.mk_th_axiom(get_id(), 1, &l);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1018,6 +1061,7 @@ namespace smt {
|
|||
|
||||
void theory_bv::new_diseq_eh(theory_var v1, theory_var v2) {
|
||||
if (is_bv(v1)) {
|
||||
SASSERT(m_bits[v1].size() == m_bits[v2].size());
|
||||
expand_diseq(v1, v2);
|
||||
}
|
||||
}
|
||||
|
@ -1175,6 +1219,7 @@ namespace smt {
|
|||
void theory_bv::relevant_eh(app * n) {
|
||||
ast_manager & m = get_manager();
|
||||
context & ctx = get_context();
|
||||
TRACE("bv", tout << "relevant: " << mk_pp(n, m) << "\n";);
|
||||
if (m.is_bool(n)) {
|
||||
bool_var v = ctx.get_bool_var(n);
|
||||
atom * a = get_bv2a(v);
|
||||
|
@ -1357,6 +1402,7 @@ namespace smt {
|
|||
if (v1 != null_theory_var) {
|
||||
// conflict was detected ... v1 and v2 have complementary bits
|
||||
SASSERT(m_bits[v1][it->m_idx] == ~(m_bits[v2][it->m_idx]));
|
||||
SASSERT(m_bits[v1].size() == m_bits[v2].size());
|
||||
mk_new_diseq_axiom(v1, v2, it->m_idx);
|
||||
RESET_MERGET_AUX();
|
||||
return false;
|
||||
|
|
|
@ -983,11 +983,8 @@ template<typename Ext>
|
|||
void theory_diff_logic<Ext>::get_eq_antecedents(
|
||||
theory_var v1, theory_var v2, unsigned timestamp, conflict_resolution & cr) {
|
||||
imp_functor functor(cr);
|
||||
bool r;
|
||||
r = m_graph.find_shortest_zero_edge_path(v1, v2, timestamp, functor);
|
||||
SASSERT(r);
|
||||
r = m_graph.find_shortest_zero_edge_path(v2, v1, timestamp, functor);
|
||||
SASSERT(r);
|
||||
VERIFY(m_graph.find_shortest_zero_edge_path(v1, v2, timestamp, functor));
|
||||
VERIFY(m_graph.find_shortest_zero_edge_path(v2, v1, timestamp, functor));
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
|
|
|
@ -91,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);
|
||||
|
@ -162,7 +162,7 @@ namespace smt {
|
|||
m.register_factory(alloc(dl_factory, m_util, m.get_model()));
|
||||
}
|
||||
|
||||
virtual smt::model_value_proc * mk_value(smt::enode * n) {
|
||||
virtual smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator&) {
|
||||
return alloc(dl_value_proc, *this, n);
|
||||
}
|
||||
|
||||
|
@ -201,9 +201,8 @@ namespace smt {
|
|||
if(!m_reps.find(s, r) || !m_vals.find(s,v)) {
|
||||
SASSERT(!m_reps.contains(s));
|
||||
sort* bv = b().mk_sort(64);
|
||||
// TBD: filter these from model.
|
||||
r = m().mk_fresh_func_decl("rep",1, &s,bv);
|
||||
v = m().mk_fresh_func_decl("val",1, &bv,s);
|
||||
r = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_REP, 0, 0, 1, &s, bv);
|
||||
v = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_ABS, 0, 0, 1, &bv, s);
|
||||
m_reps.insert(s, r);
|
||||
m_vals.insert(s, v);
|
||||
add_trail(r);
|
||||
|
|
46
src/smt/theory_fpa.cpp
Normal file
46
src/smt/theory_fpa.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_fpa.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Floating-Point Theory Plugin
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2014-04-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"theory_fpa.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) {
|
||||
TRACE("bv", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";);
|
||||
SASSERT(atom->get_family_id() == get_family_id());
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return true;
|
||||
}
|
||||
|
||||
void theory_fpa::new_eq_eh(theory_var, theory_var) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
|
||||
void theory_fpa::new_diseq_eh(theory_var, theory_var) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
|
||||
void theory_fpa::push_scope_eh() {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
|
||||
void theory_fpa::pop_scope_eh(unsigned num_scopes) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
};
|
45
src/smt/theory_fpa.h
Normal file
45
src/smt/theory_fpa.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_fpa.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Floating-Point Theory Plugin
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2014-04-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _THEORY_FPA_H_
|
||||
#define _THEORY_FPA_H_
|
||||
|
||||
#include"smt_theory.h"
|
||||
#include"fpa2bv_converter.h"
|
||||
|
||||
namespace smt {
|
||||
class theory_fpa : public theory {
|
||||
fpa2bv_converter m_converter;
|
||||
|
||||
virtual final_check_status final_check_eh() { return FC_DONE; }
|
||||
virtual bool internalize_atom(app*, bool);
|
||||
virtual bool internalize_term(app*) { return internalize_atom(0, false); }
|
||||
virtual void new_eq_eh(theory_var, theory_var);
|
||||
virtual void new_diseq_eh(theory_var, theory_var);
|
||||
virtual void push_scope_eh();
|
||||
virtual void pop_scope_eh(unsigned num_scopes);
|
||||
virtual theory* mk_fresh(context*) { return alloc(theory_fpa, get_manager()); }
|
||||
virtual char const * get_name() const { return "fpa"; }
|
||||
public:
|
||||
theory_fpa(ast_manager& m) : theory(m.mk_family_id("fpa")), m_converter(m) {}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _THEORY_FPA_H_ */
|
||||
|
|
@ -1,236 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_horn_ineq.h
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-04-18
|
||||
|
||||
Revision History:
|
||||
|
||||
The implementaton is derived from theory_diff_logic.
|
||||
|
||||
--*/
|
||||
#include "theory_horn_ineq.h"
|
||||
#include "theory_horn_ineq_def.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
template class theory_horn_ineq<ihi_ext>;
|
||||
template class theory_horn_ineq<rhi_ext>;
|
||||
|
||||
// similar to test_diff_logic:
|
||||
|
||||
horn_ineq_tester::horn_ineq_tester(ast_manager& m): m(m), a(m) {}
|
||||
|
||||
bool horn_ineq_tester::operator()(expr* e) {
|
||||
m_todo.reset();
|
||||
m_pols.reset();
|
||||
pos_mark.reset();
|
||||
neg_mark.reset();
|
||||
m_todo.push_back(e);
|
||||
m_pols.push_back(l_true);
|
||||
while (!m_todo.empty()) {
|
||||
expr* e = m_todo.back();
|
||||
lbool p = m_pols.back();
|
||||
m_todo.pop_back();
|
||||
m_pols.pop_back();
|
||||
switch (p) {
|
||||
case l_true:
|
||||
if (pos_mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
pos_mark.mark(e, true);
|
||||
break;
|
||||
case l_false:
|
||||
if (neg_mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
neg_mark.mark(e, true);
|
||||
break;
|
||||
case l_undef:
|
||||
if (pos_mark.is_marked(e) && neg_mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
pos_mark.mark(e, true);
|
||||
neg_mark.mark(e, true);
|
||||
break;
|
||||
}
|
||||
if (!test_expr(p, e)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<std::pair<expr*,rational> > const& horn_ineq_tester::get_linearization() const {
|
||||
return m_terms;
|
||||
}
|
||||
|
||||
bool horn_ineq_tester::test_expr(lbool p, expr* e) {
|
||||
expr* e1, *e2, *e3;
|
||||
if (is_var(e)) {
|
||||
return true;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
return false;
|
||||
}
|
||||
app* ap = to_app(e);
|
||||
if (m.is_and(ap) || m.is_or(ap)) {
|
||||
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
|
||||
m_todo.push_back(ap->get_arg(i));
|
||||
m_pols.push_back(p);
|
||||
}
|
||||
}
|
||||
else if (m.is_not(e, e1)) {
|
||||
m_todo.push_back(e);
|
||||
m_pols.push_back(~p);
|
||||
}
|
||||
else if (m.is_ite(e, e1, e2, e3)) {
|
||||
m_todo.push_back(e1);
|
||||
m_pols.push_back(l_undef);
|
||||
m_todo.push_back(e2);
|
||||
m_pols.push_back(p);
|
||||
m_todo.push_back(e3);
|
||||
m_pols.push_back(p);
|
||||
}
|
||||
else if (m.is_iff(e, e1, e2)) {
|
||||
m_todo.push_back(e1);
|
||||
m_pols.push_back(l_undef);
|
||||
m_todo.push_back(e2);
|
||||
m_pols.push_back(l_undef);
|
||||
m_todo.push_back(e2);
|
||||
}
|
||||
else if (m.is_implies(e, e1, e2)) {
|
||||
m_todo.push_back(e1);
|
||||
m_pols.push_back(~p);
|
||||
m_todo.push_back(e2);
|
||||
m_pols.push_back(p);
|
||||
}
|
||||
else if (m.is_eq(e, e1, e2)) {
|
||||
return linearize(e1, e2) == diff;
|
||||
}
|
||||
else if (m.is_true(e) || m.is_false(e)) {
|
||||
// no-op
|
||||
}
|
||||
else if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1) ||
|
||||
a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) {
|
||||
if (p == l_false) {
|
||||
std::swap(e2, e1);
|
||||
}
|
||||
classify_t cl = linearize(e1, e2);
|
||||
switch(p) {
|
||||
case l_undef:
|
||||
return cl == diff;
|
||||
case l_true:
|
||||
case l_false:
|
||||
return cl == horn || cl == diff;
|
||||
}
|
||||
}
|
||||
else if (!is_uninterp_const(e)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool horn_ineq_tester::operator()(unsigned num_fmls, expr* const* fmls) {
|
||||
for (unsigned i = 0; i < num_fmls; ++i) {
|
||||
if (!(*this)(fmls[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e) {
|
||||
m_terms.reset();
|
||||
m_terms.push_back(std::make_pair(e, rational(1)));
|
||||
return linearize();
|
||||
}
|
||||
|
||||
horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e1, expr* e2) {
|
||||
m_terms.reset();
|
||||
m_terms.push_back(std::make_pair(e1, rational(1)));
|
||||
m_terms.push_back(std::make_pair(e2, rational(-1)));
|
||||
return linearize();
|
||||
}
|
||||
|
||||
horn_ineq_tester::classify_t horn_ineq_tester::linearize() {
|
||||
|
||||
m_weight.reset();
|
||||
m_coeff_map.reset();
|
||||
|
||||
while (!m_terms.empty()) {
|
||||
expr* e1, *e2;
|
||||
rational num;
|
||||
rational mul = m_terms.back().second;
|
||||
expr* e = m_terms.back().first;
|
||||
m_terms.pop_back();
|
||||
if (a.is_add(e)) {
|
||||
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||
m_terms.push_back(std::make_pair(to_app(e)->get_arg(i), mul));
|
||||
}
|
||||
}
|
||||
else if (a.is_mul(e, e1, e2) && a.is_numeral(e1, num)) {
|
||||
m_terms.push_back(std::make_pair(e2, mul*num));
|
||||
}
|
||||
else if (a.is_mul(e, e2, e1) && a.is_numeral(e1, num)) {
|
||||
m_terms.push_back(std::make_pair(e2, mul*num));
|
||||
}
|
||||
else if (a.is_sub(e, e1, e2)) {
|
||||
m_terms.push_back(std::make_pair(e1, mul));
|
||||
m_terms.push_back(std::make_pair(e2, -mul));
|
||||
}
|
||||
else if (a.is_uminus(e, e1)) {
|
||||
m_terms.push_back(std::make_pair(e1, -mul));
|
||||
}
|
||||
else if (a.is_numeral(e, num)) {
|
||||
m_weight += num*mul;
|
||||
}
|
||||
else if (a.is_to_real(e, e1)) {
|
||||
m_terms.push_back(std::make_pair(e1, mul));
|
||||
}
|
||||
else if (!is_uninterp_const(e)) {
|
||||
return non_horn;
|
||||
}
|
||||
else {
|
||||
m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul;
|
||||
}
|
||||
}
|
||||
unsigned num_negative = 0;
|
||||
unsigned num_positive = 0;
|
||||
bool is_unit_pos = true, is_unit_neg = true;
|
||||
obj_map<expr, rational>::iterator it = m_coeff_map.begin();
|
||||
obj_map<expr, rational>::iterator end = m_coeff_map.end();
|
||||
for (; it != end; ++it) {
|
||||
rational r = it->m_value;
|
||||
if (r.is_zero()) {
|
||||
continue;
|
||||
}
|
||||
m_terms.push_back(std::make_pair(it->m_key, r));
|
||||
if (r.is_pos()) {
|
||||
is_unit_pos = is_unit_pos && r.is_one();
|
||||
num_positive++;
|
||||
}
|
||||
else {
|
||||
is_unit_neg = is_unit_neg && r.is_minus_one();
|
||||
num_negative++;
|
||||
}
|
||||
}
|
||||
if (num_negative <= 1 && is_unit_pos && is_unit_neg && num_positive <= 1) {
|
||||
return diff;
|
||||
}
|
||||
if (num_positive <= 1 && is_unit_pos) {
|
||||
return horn;
|
||||
}
|
||||
if (num_negative <= 1 && is_unit_neg) {
|
||||
return co_horn;
|
||||
}
|
||||
return non_horn;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,328 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
theory_horn_ineq.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A*x <= weight + D*x, coefficients to A and D are non-negative,
|
||||
D is a diagonal matrix.
|
||||
Coefficients to weight may have both signs.
|
||||
|
||||
Label variables by weight.
|
||||
Select inequality that is not satisfied.
|
||||
Set delta(LHS) := 0
|
||||
Set delta(RHS(x)) := weight(x) - b
|
||||
Propagate weight increment through inequalities.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-04-18
|
||||
|
||||
Revision History:
|
||||
|
||||
The implementaton is derived from theory_diff_logic.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _THEORY_HORN_INEQ_H_
|
||||
#define _THEORY_HORN_INEQ_H_
|
||||
|
||||
#include"rational.h"
|
||||
#include"inf_rational.h"
|
||||
#include"inf_int_rational.h"
|
||||
#include"inf_eps_rational.h"
|
||||
#include"smt_theory.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"smt_justification.h"
|
||||
#include"map.h"
|
||||
#include"smt_params.h"
|
||||
#include"arith_eq_adapter.h"
|
||||
#include"smt_model_generator.h"
|
||||
#include"numeral_factory.h"
|
||||
#include"smt_clause.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
class horn_ineq_tester {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
ptr_vector<expr> m_todo;
|
||||
svector<lbool> m_pols;
|
||||
ast_mark pos_mark, neg_mark;
|
||||
obj_map<expr, rational> m_coeff_map;
|
||||
rational m_weight;
|
||||
vector<std::pair<expr*, rational> > m_terms;
|
||||
|
||||
public:
|
||||
enum classify_t {
|
||||
co_horn,
|
||||
horn,
|
||||
diff,
|
||||
non_horn
|
||||
};
|
||||
horn_ineq_tester(ast_manager& m);
|
||||
|
||||
// test if formula is in the Horn inequality fragment:
|
||||
bool operator()(expr* fml);
|
||||
bool operator()(unsigned num_fmls, expr* const* fmls);
|
||||
|
||||
// linearize inequality/equality
|
||||
classify_t linearize(expr* e);
|
||||
classify_t linearize(expr* e1, expr* e2);
|
||||
|
||||
// retrieve linearization
|
||||
vector<std::pair<expr*,rational> > const& get_linearization() const;
|
||||
rational const& get_weight() const { return m_weight; }
|
||||
private:
|
||||
bool test_expr(lbool p, expr* e);
|
||||
classify_t linearize();
|
||||
};
|
||||
|
||||
template<typename Ext>
|
||||
class theory_horn_ineq : public theory, private Ext {
|
||||
|
||||
typedef typename Ext::numeral numeral;
|
||||
typedef typename Ext::inf_numeral inf_numeral;
|
||||
typedef literal explanation;
|
||||
typedef theory_var th_var;
|
||||
typedef svector<th_var> th_var_vector;
|
||||
typedef unsigned clause_id;
|
||||
typedef vector<std::pair<th_var, rational> > coeffs;
|
||||
|
||||
class clause;
|
||||
class graph;
|
||||
class assignment_trail;
|
||||
class parent_trail;
|
||||
|
||||
class atom {
|
||||
protected:
|
||||
bool_var m_bvar;
|
||||
bool m_true;
|
||||
int m_pos;
|
||||
int m_neg;
|
||||
public:
|
||||
atom(bool_var bv, int pos, int neg) :
|
||||
m_bvar(bv), m_true(false),
|
||||
m_pos(pos), m_neg(neg) {}
|
||||
~atom() {}
|
||||
bool_var get_bool_var() const { return m_bvar; }
|
||||
bool is_true() const { return m_true; }
|
||||
void assign_eh(bool is_true) { m_true = is_true; }
|
||||
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
|
||||
int get_pos() const { return m_pos; }
|
||||
int get_neg() const { return m_neg; }
|
||||
std::ostream& display(theory_horn_ineq const& th, std::ostream& out) const;
|
||||
};
|
||||
typedef svector<atom> atoms;
|
||||
|
||||
struct scope {
|
||||
unsigned m_atoms_lim;
|
||||
unsigned m_asserted_atoms_lim;
|
||||
unsigned m_asserted_qhead_old;
|
||||
};
|
||||
|
||||
struct stats {
|
||||
unsigned m_num_conflicts;
|
||||
unsigned m_num_assertions;
|
||||
unsigned m_num_core2th_eqs;
|
||||
unsigned m_num_core2th_diseqs;
|
||||
|
||||
void reset() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
stats() {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
stats m_stats;
|
||||
smt_params m_params;
|
||||
arith_util a;
|
||||
arith_eq_adapter m_arith_eq_adapter;
|
||||
th_var m_zero_int; // cache the variable representing the zero variable.
|
||||
th_var m_zero_real; // cache the variable representing the zero variable.
|
||||
|
||||
graph* m_graph;
|
||||
atoms m_atoms;
|
||||
unsigned_vector m_asserted_atoms; // set of asserted atoms
|
||||
unsigned m_asserted_qhead;
|
||||
u_map<unsigned> m_bool_var2atom;
|
||||
svector<scope> m_scopes;
|
||||
|
||||
double m_agility;
|
||||
bool m_lia;
|
||||
bool m_lra;
|
||||
bool m_non_horn_ineq_exprs;
|
||||
|
||||
horn_ineq_tester m_test;
|
||||
|
||||
|
||||
arith_factory * m_factory;
|
||||
rational m_delta;
|
||||
rational m_lambda;
|
||||
|
||||
|
||||
// Set a conflict due to a negative cycle.
|
||||
void set_neg_cycle_conflict();
|
||||
|
||||
// Create a new theory variable.
|
||||
virtual th_var mk_var(enode* n);
|
||||
|
||||
virtual th_var mk_var(expr* n);
|
||||
|
||||
void compute_delta();
|
||||
|
||||
void found_non_horn_ineq_expr(expr * n);
|
||||
|
||||
bool is_interpreted(app* n) const {
|
||||
return n->get_family_id() == get_family_id();
|
||||
}
|
||||
|
||||
public:
|
||||
theory_horn_ineq(ast_manager& m);
|
||||
|
||||
virtual ~theory_horn_ineq();
|
||||
|
||||
virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_horn_ineq, get_manager()); }
|
||||
|
||||
virtual char const * get_name() const { return "horn-inequality-logic"; }
|
||||
|
||||
/**
|
||||
\brief See comment in theory::mk_eq_atom
|
||||
*/
|
||||
virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); }
|
||||
|
||||
virtual void init(context * ctx);
|
||||
|
||||
virtual bool internalize_atom(app * atom, bool gate_ctx);
|
||||
|
||||
virtual bool internalize_term(app * term);
|
||||
|
||||
virtual void internalize_eq_eh(app * atom, bool_var v);
|
||||
|
||||
virtual void assign_eh(bool_var v, bool is_true);
|
||||
|
||||
virtual void new_eq_eh(th_var v1, th_var v2) {
|
||||
m_arith_eq_adapter.new_eq_eh(v1, v2);
|
||||
}
|
||||
|
||||
virtual bool use_diseqs() const { return true; }
|
||||
|
||||
virtual void new_diseq_eh(th_var v1, th_var v2) {
|
||||
m_arith_eq_adapter.new_diseq_eh(v1, v2);
|
||||
}
|
||||
|
||||
virtual void push_scope_eh();
|
||||
|
||||
virtual void pop_scope_eh(unsigned num_scopes);
|
||||
|
||||
virtual void restart_eh() {
|
||||
m_arith_eq_adapter.restart_eh();
|
||||
}
|
||||
|
||||
virtual void relevant_eh(app* e) {}
|
||||
|
||||
virtual void init_search_eh() {
|
||||
m_arith_eq_adapter.init_search_eh();
|
||||
}
|
||||
|
||||
virtual final_check_status final_check_eh();
|
||||
|
||||
virtual bool is_shared(th_var v) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool can_propagate() {
|
||||
SASSERT(m_asserted_qhead <= m_asserted_atoms.size());
|
||||
return m_asserted_qhead != m_asserted_atoms.size();
|
||||
}
|
||||
|
||||
virtual void propagate();
|
||||
|
||||
virtual justification * why_is_diseq(th_var v1, th_var v2) {
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void reset_eh();
|
||||
|
||||
virtual void init_model(model_generator & m);
|
||||
|
||||
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
||||
|
||||
virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void display(std::ostream & out) const;
|
||||
|
||||
virtual void collect_statistics(::statistics & st) const;
|
||||
|
||||
private:
|
||||
|
||||
virtual void new_eq_eh(th_var v1, th_var v2, justification& j) {
|
||||
m_stats.m_num_core2th_eqs++;
|
||||
new_eq_or_diseq(true, v1, v2, j);
|
||||
}
|
||||
|
||||
virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) {
|
||||
m_stats.m_num_core2th_diseqs++;
|
||||
new_eq_or_diseq(false, v1, v2, j);
|
||||
}
|
||||
|
||||
void negate(coeffs& coeffs, rational& weight);
|
||||
numeral mk_weight(bool is_real, bool is_strict, rational const& w) const;
|
||||
void mk_coeffs(vector<std::pair<expr*,rational> >const& terms, coeffs& coeffs, rational& w);
|
||||
|
||||
void del_atoms(unsigned old_size);
|
||||
|
||||
void propagate_core();
|
||||
|
||||
bool propagate_atom(atom const& a);
|
||||
|
||||
th_var mk_term(app* n);
|
||||
|
||||
th_var mk_num(app* n, rational const& r);
|
||||
|
||||
bool is_consistent() const;
|
||||
|
||||
th_var expand(bool pos, th_var v, rational & k);
|
||||
|
||||
void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just);
|
||||
|
||||
th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; }
|
||||
|
||||
th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); }
|
||||
|
||||
void inc_conflicts();
|
||||
|
||||
};
|
||||
|
||||
struct rhi_ext {
|
||||
typedef inf_rational inf_numeral;
|
||||
typedef inf_eps_rational<inf_rational> numeral;
|
||||
numeral m_epsilon;
|
||||
numeral m_minus_infty;
|
||||
rhi_ext() : m_epsilon(inf_rational(rational(), true)), m_minus_infty(rational(-1),inf_rational()) {}
|
||||
};
|
||||
|
||||
struct ihi_ext {
|
||||
typedef rational inf_numeral;
|
||||
typedef inf_eps_rational<rational> numeral;
|
||||
numeral m_epsilon;
|
||||
numeral m_minus_infty;
|
||||
ihi_ext() : m_epsilon(rational(1)), m_minus_infty(rational(-1),rational(0)) {}
|
||||
};
|
||||
|
||||
typedef theory_horn_ineq<rhi_ext> theory_rhi;
|
||||
typedef theory_horn_ineq<ihi_ext> theory_ihi;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _THEORY_HORN_INEQ_H_ */
|
File diff suppressed because it is too large
Load diff
|
@ -752,7 +752,8 @@ namespace smt {
|
|||
|
||||
for (unsigned j = 0; j < zero_v.size(); ++j) {
|
||||
int v = zero_v[j];
|
||||
m_graph.acc_assignment(v, numeral(-1));
|
||||
|
||||
m_graph.inc_assignment(v, numeral(-1));
|
||||
th_var k = from_var(v);
|
||||
if (!is_parity_ok(k)) {
|
||||
todo.push_back(k);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue