mirror of
https://github.com/Z3Prover/z3
synced 2025-10-06 07:53:59 +00:00
merge with master
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
3533bf486f
223 changed files with 7175 additions and 2167 deletions
|
@ -292,7 +292,7 @@ v_dependency * interval::join_opt(v_dependency * d1, v_dependency * d2, v_depend
|
|||
}
|
||||
|
||||
interval & interval::operator*=(interval const & other) {
|
||||
#if Z3DEBUG || _TRACE
|
||||
#if defined(Z3DEBUG) || defined(_TRACE)
|
||||
bool contains_zero1 = contains_zero();
|
||||
bool contains_zero2 = other.contains_zero();
|
||||
#endif
|
||||
|
|
|
@ -47,14 +47,14 @@ def_module_params(module_name='smt',
|
|||
('induction', BOOL, False, 'enable generation of induction lemmas'),
|
||||
('bv.reflect', BOOL, True, 'create enode for every bit-vector term'),
|
||||
('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'),
|
||||
('bv.eq_axioms', BOOL, True, 'add dynamic equality axioms'),
|
||||
('bv.watch_diseq', BOOL, False, 'use watch lists instead of eager axioms for bit-vectors'),
|
||||
('bv.delay', BOOL, True, 'delay internalize expensive bit-vector operations'),
|
||||
('bv.polysat', BOOL, False, 'use polysat bit-vector solver'),
|
||||
('bv.eq_axioms', BOOL, True, 'enable redundant equality axioms for bit-vectors'),
|
||||
('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'),
|
||||
('arith.solver', UINT, 6, '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 4 - utvpi, 5 - infinitary lra, 6 - lra solver'),
|
||||
('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2'),
|
||||
('arith.nl.nra', BOOL, True, 'call nra_solver when incremental lianirization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6'),
|
||||
('arith.nl.nra', BOOL, True, 'call nra_solver when incremental linearization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6'),
|
||||
('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters, relevant only if smt.arith.solver=2'),
|
||||
('arith.nl.rounds', UINT, 1024, 'threshold for number of (nested) final checks for non linear arithmetic, relevant only if smt.arith.solver=2'),
|
||||
('arith.nl.order', BOOL, True, 'run order lemmas'),
|
||||
|
|
|
@ -26,9 +26,9 @@ void theory_bv_params::updt_params(params_ref const & _p) {
|
|||
m_hi_div0 = rp.hi_div0();
|
||||
m_bv_reflect = p.bv_reflect();
|
||||
m_bv_enable_int2bv2int = p.bv_enable_int2bv();
|
||||
m_bv_eq_axioms = p.bv_eq_axioms();
|
||||
m_bv_delay = p.bv_delay();
|
||||
m_bv_polysat = p.bv_polysat();
|
||||
m_bv_eq_axioms = p.bv_eq_axioms();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
@ -38,8 +38,8 @@ void theory_bv_params::display(std::ostream & out) const {
|
|||
DISPLAY_PARAM(m_hi_div0);
|
||||
DISPLAY_PARAM(m_bv_reflect);
|
||||
DISPLAY_PARAM(m_bv_lazy_le);
|
||||
DISPLAY_PARAM(m_bv_cc);
|
||||
DISPLAY_PARAM(m_bv_eq_axioms);
|
||||
DISPLAY_PARAM(m_bv_cc);
|
||||
DISPLAY_PARAM(m_bv_blast_max_size);
|
||||
DISPLAY_PARAM(m_bv_enable_int2bv2int);
|
||||
DISPLAY_PARAM(m_bv_delay);
|
||||
|
|
|
@ -612,7 +612,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
vector<unsigned_vector> _mutexes;
|
||||
mc.cliques(ps, _mutexes);
|
||||
mc.cliques2(ps, _mutexes);
|
||||
for (auto const& mux : _mutexes) {
|
||||
expr_ref_vector lits(m);
|
||||
for (unsigned idx : mux) {
|
||||
|
|
|
@ -29,6 +29,7 @@ Revision History:
|
|||
#include "ast/proofs/proof_checker.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/well_sorted.h"
|
||||
#include "model/model_params.hpp"
|
||||
#include "model/model.h"
|
||||
#include "model/model_pp.h"
|
||||
#include "smt/smt_context.h"
|
||||
|
@ -171,7 +172,7 @@ namespace smt {
|
|||
dst_ctx.setup_context(dst_ctx.m_fparams.m_auto_config);
|
||||
dst_ctx.internalize_assertions();
|
||||
|
||||
dst_ctx.copy_user_propagator(src_ctx);
|
||||
dst_ctx.copy_user_propagator(src_ctx, true);
|
||||
|
||||
TRACE("smt_context",
|
||||
src_ctx.display(tout);
|
||||
|
@ -193,16 +194,19 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
void context::copy_user_propagator(context& src_ctx) {
|
||||
void context::copy_user_propagator(context& src_ctx, bool copy_registered) {
|
||||
if (!src_ctx.m_user_propagator)
|
||||
return;
|
||||
ast_translation tr(src_ctx.m, m, false);
|
||||
auto* p = get_theory(m.mk_family_id("user_propagator"));
|
||||
m_user_propagator = reinterpret_cast<theory_user_propagator*>(p);
|
||||
SASSERT(m_user_propagator);
|
||||
if (!copy_registered) {
|
||||
return;
|
||||
}
|
||||
ast_translation tr(src_ctx.m, m, false);
|
||||
for (unsigned i = 0; i < src_ctx.m_user_propagator->get_num_vars(); ++i) {
|
||||
app* e = src_ctx.m_user_propagator->get_expr(i);
|
||||
m_user_propagator->add_expr(tr(e));
|
||||
m_user_propagator->add_expr(tr(e), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +215,7 @@ namespace smt {
|
|||
new_ctx->m_is_auxiliary = true;
|
||||
new_ctx->set_logic(l == nullptr ? m_setup.get_logic() : *l);
|
||||
copy_plugins(*this, *new_ctx);
|
||||
new_ctx->copy_user_propagator(*this, false);
|
||||
return new_ctx;
|
||||
}
|
||||
|
||||
|
@ -1761,6 +1766,70 @@ namespace smt {
|
|||
m_bvar_inc *= INV_ACTIVITY_LIMIT;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Returns a truth value for the given variable
|
||||
*/
|
||||
bool context::guess(bool_var var, lbool phase) {
|
||||
if (is_quantifier(m_bool_var2expr[var])) {
|
||||
// Overriding any decision on how to assign the quantifier.
|
||||
// assigning a quantifier to false is equivalent to make it irrelevant.
|
||||
phase = l_false;
|
||||
}
|
||||
literal l(var, false);
|
||||
|
||||
if (phase != l_undef)
|
||||
return phase == l_true;
|
||||
|
||||
bool_var_data & d = m_bdata[var];
|
||||
if (d.try_true_first())
|
||||
return true;
|
||||
switch (m_fparams.m_phase_selection) {
|
||||
case PS_THEORY:
|
||||
if (m_phase_cache_on && d.m_phase_available) {
|
||||
return m_bdata[var].m_phase;
|
||||
}
|
||||
if (!m_phase_cache_on && d.is_theory_atom()) {
|
||||
theory * th = m_theories.get_plugin(d.get_theory());
|
||||
lbool th_phase = th->get_phase(var);
|
||||
if (th_phase != l_undef) {
|
||||
return th_phase == l_true;
|
||||
}
|
||||
}
|
||||
if (track_occs()) {
|
||||
if (m_lit_occs[l.index()] == 0) {
|
||||
return false;
|
||||
}
|
||||
if (m_lit_occs[(~l).index()] == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return m_phase_default;
|
||||
case PS_CACHING:
|
||||
case PS_CACHING_CONSERVATIVE:
|
||||
case PS_CACHING_CONSERVATIVE2:
|
||||
if (m_phase_cache_on && d.m_phase_available) {
|
||||
TRACE("phase_selection", tout << "using cached value, is_pos: " << m_bdata[var].m_phase << ", var: p" << var << "\n";);
|
||||
return m_bdata[var].m_phase;
|
||||
}
|
||||
else {
|
||||
TRACE("phase_selection", tout << "setting to false\n";);
|
||||
return m_phase_default;
|
||||
}
|
||||
case PS_ALWAYS_FALSE:
|
||||
return false;
|
||||
case PS_ALWAYS_TRUE:
|
||||
return true;
|
||||
case PS_RANDOM:
|
||||
return m_random() % 2 == 0;
|
||||
case PS_OCCURRENCE: {
|
||||
return m_lit_occs[l.index()] > m_lit_occs[(~l).index()];
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Execute next case split, return false if there are no
|
||||
more case splits to be performed.
|
||||
|
@ -1802,81 +1871,15 @@ namespace smt {
|
|||
TRACE("decide", tout << "splitting, lvl: " << m_scope_lvl << "\n";);
|
||||
|
||||
TRACE("decide_detail", tout << mk_pp(bool_var2expr(var), m) << "\n";);
|
||||
|
||||
bool is_pos;
|
||||
|
||||
if (is_quantifier(m_bool_var2expr[var])) {
|
||||
// Overriding any decision on how to assign the quantifier.
|
||||
// assigning a quantifier to false is equivalent to make it irrelevant.
|
||||
phase = l_false;
|
||||
}
|
||||
|
||||
bool is_pos = guess(var, phase);
|
||||
literal l(var, false);
|
||||
|
||||
if (phase != l_undef) {
|
||||
is_pos = phase == l_true;
|
||||
}
|
||||
else {
|
||||
bool_var_data & d = m_bdata[var];
|
||||
if (d.try_true_first()) {
|
||||
is_pos = true;
|
||||
}
|
||||
else {
|
||||
switch (m_fparams.m_phase_selection) {
|
||||
case PS_THEORY:
|
||||
if (m_phase_cache_on && d.m_phase_available) {
|
||||
is_pos = m_bdata[var].m_phase;
|
||||
break;
|
||||
}
|
||||
if (!m_phase_cache_on && d.is_theory_atom()) {
|
||||
theory * th = m_theories.get_plugin(d.get_theory());
|
||||
lbool th_phase = th->get_phase(var);
|
||||
if (th_phase != l_undef) {
|
||||
is_pos = th_phase == l_true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (track_occs()) {
|
||||
if (m_lit_occs[l.index()] == 0) {
|
||||
is_pos = false;
|
||||
break;
|
||||
}
|
||||
if (m_lit_occs[(~l).index()] == 0) {
|
||||
is_pos = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
is_pos = m_phase_default;
|
||||
break;
|
||||
case PS_CACHING:
|
||||
case PS_CACHING_CONSERVATIVE:
|
||||
case PS_CACHING_CONSERVATIVE2:
|
||||
if (m_phase_cache_on && d.m_phase_available) {
|
||||
TRACE("phase_selection", tout << "using cached value, is_pos: " << m_bdata[var].m_phase << ", var: p" << var << "\n";);
|
||||
is_pos = m_bdata[var].m_phase;
|
||||
}
|
||||
else {
|
||||
TRACE("phase_selection", tout << "setting to false\n";);
|
||||
is_pos = m_phase_default;
|
||||
}
|
||||
break;
|
||||
case PS_ALWAYS_FALSE:
|
||||
is_pos = false;
|
||||
break;
|
||||
case PS_ALWAYS_TRUE:
|
||||
is_pos = true;
|
||||
break;
|
||||
case PS_RANDOM:
|
||||
is_pos = (m_random() % 2 == 0);
|
||||
break;
|
||||
case PS_OCCURRENCE: {
|
||||
is_pos = m_lit_occs[l.index()] > m_lit_occs[(~l).index()];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
is_pos = false;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
bool_var original_choice = var;
|
||||
|
||||
if (decide_user_interference(var, is_pos)) {
|
||||
m_case_split_queue->unassign_var_eh(original_choice);
|
||||
l = literal(var, false);
|
||||
}
|
||||
|
||||
if (!is_pos) l.neg();
|
||||
|
@ -1884,7 +1887,7 @@ namespace smt {
|
|||
assign(l, b_justification::mk_axiom(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Update counter that is used to enable/disable phase caching.
|
||||
*/
|
||||
|
@ -2901,6 +2904,14 @@ namespace smt {
|
|||
return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_family_id()) != null_theory_var;
|
||||
}
|
||||
|
||||
bool context::decide_user_interference(bool_var& var, bool& is_pos) {
|
||||
if (!m_user_propagator || !m_user_propagator->has_decide())
|
||||
return false;
|
||||
bool_var old = var;
|
||||
m_user_propagator->decide(var, is_pos);
|
||||
return old != var;
|
||||
}
|
||||
|
||||
void context::assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain) {
|
||||
theory_var v = n->get_th_var(m_user_propagator->get_family_id());
|
||||
m_user_propagator->new_fixed_eh(v, val, sz, explain);
|
||||
|
@ -3037,7 +3048,8 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
literal_vector new_case_split;
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
literal l = lits[i];
|
||||
|
@ -3731,7 +3743,7 @@ namespace smt {
|
|||
if (status == l_false) {
|
||||
return false;
|
||||
}
|
||||
if (status == l_true && !m_qmanager->has_quantifiers()) {
|
||||
if (status == l_true && !m_qmanager->has_quantifiers() && !m_has_lambda) {
|
||||
return false;
|
||||
}
|
||||
if (status == l_true && m_qmanager->has_quantifiers()) {
|
||||
|
@ -3754,6 +3766,11 @@ namespace smt {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (status == l_true && m_has_lambda) {
|
||||
m_last_search_failure = LAMBDAS;
|
||||
status = l_undef;
|
||||
return false;
|
||||
}
|
||||
inc_limits();
|
||||
if (status == l_true || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) {
|
||||
SASSERT(!inconsistent());
|
||||
|
@ -3765,13 +3782,13 @@ namespace smt {
|
|||
pop_scope(m_scope_lvl - curr_lvl);
|
||||
SASSERT(at_search_level());
|
||||
}
|
||||
for (theory* th : m_theory_set) {
|
||||
if (!inconsistent()) th->restart_eh();
|
||||
}
|
||||
for (theory* th : m_theory_set)
|
||||
if (!inconsistent())
|
||||
th->restart_eh();
|
||||
|
||||
TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";);
|
||||
if (!inconsistent()) {
|
||||
if (!inconsistent())
|
||||
m_qmanager->restart_eh();
|
||||
}
|
||||
if (inconsistent()) {
|
||||
VERIFY(!resolve_conflict());
|
||||
status = l_false;
|
||||
|
@ -3993,6 +4010,10 @@ namespace smt {
|
|||
TRACE("final_check_step", tout << "RESULT final_check: " << result << "\n";);
|
||||
if (result == FC_GIVEUP && f != OK)
|
||||
m_last_search_failure = f;
|
||||
if (result == FC_DONE && m_has_lambda) {
|
||||
m_last_search_failure = LAMBDAS;
|
||||
result = FC_GIVEUP;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4598,18 +4619,36 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
expr_ref_vector context::get_trail() {
|
||||
expr_ref_vector context::get_trail(unsigned max_level) {
|
||||
expr_ref_vector result(get_manager());
|
||||
get_assignments(result);
|
||||
for (literal lit : m_assigned_literals) {
|
||||
if (get_assign_level(lit) > max_level + m_base_lvl)
|
||||
continue;
|
||||
expr_ref e(m);
|
||||
literal2expr(lit, e);
|
||||
result.push_back(std::move(e));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void context::get_units(expr_ref_vector& result) {
|
||||
expr_mark visited;
|
||||
for (expr* fml : result)
|
||||
visited.mark(fml);
|
||||
expr_ref_vector trail = get_trail(0);
|
||||
for (expr* t : trail)
|
||||
if (!visited.is_marked(t))
|
||||
result.push_back(t);
|
||||
}
|
||||
|
||||
|
||||
failure context::get_last_search_failure() const {
|
||||
return m_last_search_failure;
|
||||
}
|
||||
|
||||
void context::add_rec_funs_to_model() {
|
||||
if (m_model)
|
||||
model_params p;
|
||||
if (m_model && p.user_functions())
|
||||
m_model->add_rec_funs();
|
||||
}
|
||||
|
||||
|
|
|
@ -773,6 +773,7 @@ namespace smt {
|
|||
|
||||
void internalize_quantifier(quantifier * q, bool gate_ctx);
|
||||
|
||||
bool m_has_lambda = false;
|
||||
void internalize_lambda(quantifier * q);
|
||||
|
||||
void internalize_formula_core(app * n, bool gate_ctx);
|
||||
|
@ -1133,6 +1134,8 @@ namespace smt {
|
|||
|
||||
enode * get_enode_eq_to(func_decl * f, unsigned num_args, enode * const * args);
|
||||
|
||||
bool guess(bool_var var, lbool phase);
|
||||
|
||||
protected:
|
||||
bool decide();
|
||||
|
||||
|
@ -1575,7 +1578,7 @@ namespace smt {
|
|||
|
||||
void log_stats();
|
||||
|
||||
void copy_user_propagator(context& src);
|
||||
void copy_user_propagator(context& src, bool copy_registered);
|
||||
|
||||
public:
|
||||
context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref());
|
||||
|
@ -1666,7 +1669,7 @@ namespace smt {
|
|||
|
||||
void get_levels(ptr_vector<expr> const& vars, unsigned_vector& depth);
|
||||
|
||||
expr_ref_vector get_trail();
|
||||
expr_ref_vector get_trail(unsigned max_level);
|
||||
|
||||
void get_model(model_ref & m);
|
||||
|
||||
|
@ -1690,6 +1693,8 @@ namespace smt {
|
|||
|
||||
void get_assertions(ptr_vector<expr> & result) { m_asserted_formulas.get_assertions(result); }
|
||||
|
||||
void get_units(expr_ref_vector& result);
|
||||
|
||||
/*
|
||||
* user-propagator
|
||||
*/
|
||||
|
@ -1723,10 +1728,10 @@ namespace smt {
|
|||
m_user_propagator->register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e) {
|
||||
void user_propagate_register_expr(expr* e) {
|
||||
if (!m_user_propagator)
|
||||
throw default_exception("user propagator must be initialized");
|
||||
return m_user_propagator->add_expr(e);
|
||||
m_user_propagator->add_expr(e, true);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r) {
|
||||
|
@ -1735,8 +1740,16 @@ namespace smt {
|
|||
m_user_propagator->register_created(r);
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& r) {
|
||||
if (!m_user_propagator)
|
||||
throw default_exception("user propagator must be initialized");
|
||||
m_user_propagator->register_decide(r);
|
||||
}
|
||||
|
||||
bool watches_fixed(enode* n) const;
|
||||
|
||||
bool decide_user_interference(bool_var& var, bool& is_pos);
|
||||
|
||||
void assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain);
|
||||
|
||||
void assign_fixed(enode* n, expr* val, literal_vector const& explain) {
|
||||
|
|
|
@ -56,6 +56,8 @@ namespace smt {
|
|||
return out;
|
||||
case QUANTIFIERS:
|
||||
return out << "QUANTIFIERS";
|
||||
case LAMBDAS:
|
||||
return out << "LAMBDAS";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return out << "?";
|
||||
|
@ -79,6 +81,7 @@ namespace smt {
|
|||
}
|
||||
case RESOURCE_LIMIT: r = "(resource limits reached)"; break;
|
||||
case QUANTIFIERS: r = "(incomplete quantifiers)"; break;
|
||||
case LAMBDAS: r = "(incomplete lambdas)"; break;
|
||||
case UNKNOWN: r = m_unknown; break;
|
||||
}
|
||||
return r;
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace smt {
|
|||
NUM_CONFLICTS, //!< Maximum number of conflicts was reached
|
||||
THEORY, //!< Theory is incomplete
|
||||
RESOURCE_LIMIT,
|
||||
LAMBDAS, //!< Logical context contains lambdas.
|
||||
QUANTIFIERS //!< Logical context contains universal quantifiers.
|
||||
};
|
||||
|
||||
|
|
|
@ -375,7 +375,6 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
SASSERT(is_app(n));
|
||||
SASSERT(!gate_ctx);
|
||||
internalize_term(to_app(n));
|
||||
}
|
||||
}
|
||||
|
@ -605,6 +604,8 @@ namespace smt {
|
|||
bool_var bv = get_bool_var(fa);
|
||||
assign(literal(bv, false), nullptr);
|
||||
mark_as_relevant(bv);
|
||||
push_trail(value_trail<bool>(m_has_lambda));
|
||||
m_has_lambda = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -177,6 +177,10 @@ namespace smt {
|
|||
void kernel::get_assignments(expr_ref_vector & result) {
|
||||
m_imp->m_kernel.get_assignments(result);
|
||||
}
|
||||
|
||||
void kernel::get_units(expr_ref_vector & result) {
|
||||
m_imp->m_kernel.get_units(result);
|
||||
}
|
||||
|
||||
void kernel::get_relevant_labels(expr * cnstr, buffer<symbol> & result) {
|
||||
m_imp->m_kernel.get_relevant_labels(cnstr, result);
|
||||
|
@ -244,8 +248,8 @@ namespace smt {
|
|||
m_imp->m_kernel.get_levels(vars, depth);
|
||||
}
|
||||
|
||||
expr_ref_vector kernel::get_trail() {
|
||||
return m_imp->m_kernel.get_trail();
|
||||
expr_ref_vector kernel::get_trail(unsigned max_level) {
|
||||
return m_imp->m_kernel.get_trail(max_level);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_init(
|
||||
|
@ -272,12 +276,16 @@ namespace smt {
|
|||
m_imp->m_kernel.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned kernel::user_propagate_register_expr(expr* e) {
|
||||
return m_imp->m_kernel.user_propagate_register_expr(e);
|
||||
void kernel::user_propagate_register_expr(expr* e) {
|
||||
m_imp->m_kernel.user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_register_created(user_propagator::created_eh_t& r) {
|
||||
m_imp->m_kernel.user_propagate_register_created(r);
|
||||
}
|
||||
|
||||
};
|
||||
void kernel::user_propagate_register_decide(user_propagator::decide_eh_t& r) {
|
||||
m_imp->m_kernel.user_propagate_register_decide(r);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -202,6 +202,12 @@ namespace smt {
|
|||
\brief Return the set of formulas assigned by the kernel.
|
||||
*/
|
||||
void get_assignments(expr_ref_vector & result);
|
||||
|
||||
|
||||
/**
|
||||
\brief Return units assigned by the kernel.
|
||||
*/
|
||||
void get_units(expr_ref_vector& result);
|
||||
|
||||
/**
|
||||
\brief Return the set of relevant labels in the last check command.
|
||||
|
@ -242,7 +248,7 @@ namespace smt {
|
|||
/**
|
||||
\brief retrieve trail of assignment stack.
|
||||
*/
|
||||
expr_ref_vector get_trail();
|
||||
expr_ref_vector get_trail(unsigned max_level);
|
||||
|
||||
/**
|
||||
\brief (For debubbing purposes) Prints the state of the kernel
|
||||
|
@ -301,10 +307,12 @@ namespace smt {
|
|||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh);
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e);
|
||||
void user_propagate_register_expr(expr* e);
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r);
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& r);
|
||||
|
||||
/**
|
||||
\brief Return a reference to smt::context.
|
||||
This breaks abstractions.
|
||||
|
|
|
@ -208,8 +208,8 @@ namespace {
|
|||
m_context.get_levels(vars, depth);
|
||||
}
|
||||
|
||||
expr_ref_vector get_trail() override {
|
||||
return m_context.get_trail();
|
||||
expr_ref_vector get_trail(unsigned max_level) override {
|
||||
return m_context.get_trail(max_level);
|
||||
}
|
||||
|
||||
void user_propagate_init(
|
||||
|
@ -236,14 +236,18 @@ namespace {
|
|||
m_context.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e) override {
|
||||
return m_context.user_propagate_register_expr(e);
|
||||
void user_propagate_register_expr(expr* e) override {
|
||||
m_context.user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& c) override {
|
||||
m_context.user_propagate_register_created(c);
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& c) override {
|
||||
m_context.user_propagate_register_decide(c);
|
||||
}
|
||||
|
||||
struct scoped_minimize_core {
|
||||
smt_solver& s;
|
||||
expr_ref_vector m_assumptions;
|
||||
|
@ -318,6 +322,10 @@ namespace {
|
|||
return m_context.get_formula(idx);
|
||||
}
|
||||
|
||||
void get_units_core(expr_ref_vector& units) override {
|
||||
m_context.get_units(units);
|
||||
}
|
||||
|
||||
expr_ref_vector cube(expr_ref_vector& vars, unsigned cutoff) override {
|
||||
ast_manager& m = get_manager();
|
||||
if (!m_cuber) {
|
||||
|
|
|
@ -40,6 +40,7 @@ class smt_tactic : public tactic {
|
|||
ast_manager& m;
|
||||
smt_params m_params;
|
||||
params_ref m_params_ref;
|
||||
expr_ref_vector m_vars;
|
||||
statistics m_stats;
|
||||
smt::kernel* m_ctx = nullptr;
|
||||
symbol m_logic;
|
||||
|
@ -321,141 +322,22 @@ public:
|
|||
user_propagator::eq_eh_t m_eq_eh;
|
||||
user_propagator::eq_eh_t m_diseq_eh;
|
||||
user_propagator::created_eh_t m_created_eh;
|
||||
|
||||
expr_ref_vector m_vars;
|
||||
unsigned_vector m_var2internal;
|
||||
unsigned_vector m_internal2var;
|
||||
unsigned_vector m_limit;
|
||||
user_propagator::decide_eh_t m_decide_eh;
|
||||
|
||||
|
||||
user_propagator::push_eh_t i_push_eh;
|
||||
user_propagator::pop_eh_t i_pop_eh;
|
||||
user_propagator::fixed_eh_t i_fixed_eh;
|
||||
user_propagator::final_eh_t i_final_eh;
|
||||
user_propagator::eq_eh_t i_eq_eh;
|
||||
user_propagator::eq_eh_t i_diseq_eh;
|
||||
user_propagator::created_eh_t i_created_eh;
|
||||
|
||||
|
||||
struct callback : public user_propagator::callback {
|
||||
smt_tactic* t = nullptr;
|
||||
user_propagator::callback* cb = nullptr;
|
||||
unsigned_vector fixed, lhs, rhs;
|
||||
void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr* conseq) override {
|
||||
fixed.reset();
|
||||
lhs.reset();
|
||||
rhs.reset();
|
||||
for (unsigned i = 0; i < num_fixed; ++i)
|
||||
fixed.push_back(t->m_var2internal[fixed_ids[i]]);
|
||||
for (unsigned i = 0; i < num_eqs; ++i) {
|
||||
lhs.push_back(t->m_var2internal[eq_lhs[i]]);
|
||||
rhs.push_back(t->m_var2internal[eq_rhs[i]]);
|
||||
}
|
||||
cb->propagate_cb(num_fixed, fixed.data(), num_eqs, lhs.data(), rhs.data(), conseq);
|
||||
}
|
||||
|
||||
unsigned register_cb(expr* e) override {
|
||||
unsigned j = t->m_vars.size();
|
||||
t->m_vars.push_back(e);
|
||||
unsigned i = cb->register_cb(e);
|
||||
t->m_var2internal.setx(j, i, 0);
|
||||
t->m_internal2var.setx(i, j, 0);
|
||||
return j;
|
||||
}
|
||||
};
|
||||
|
||||
callback i_cb;
|
||||
|
||||
void init_i_fixed_eh() {
|
||||
if (!m_fixed_eh)
|
||||
return;
|
||||
i_fixed_eh = [this](void* ctx, user_propagator::callback* cb, unsigned id, expr* value) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_fixed_eh(ctx, &i_cb, m_internal2var[id], value);
|
||||
};
|
||||
m_ctx->user_propagate_register_fixed(i_fixed_eh);
|
||||
}
|
||||
|
||||
void init_i_final_eh() {
|
||||
if (!m_final_eh)
|
||||
return;
|
||||
i_final_eh = [this](void* ctx, user_propagator::callback* cb) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_final_eh(ctx, &i_cb);
|
||||
};
|
||||
m_ctx->user_propagate_register_final(i_final_eh);
|
||||
}
|
||||
|
||||
void init_i_eq_eh() {
|
||||
if (!m_eq_eh)
|
||||
return;
|
||||
i_eq_eh = [this](void* ctx, user_propagator::callback* cb, unsigned u, unsigned v) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_eq_eh(ctx, &i_cb, m_internal2var[u], m_internal2var[v]);
|
||||
};
|
||||
m_ctx->user_propagate_register_eq(i_eq_eh);
|
||||
}
|
||||
|
||||
void init_i_diseq_eh() {
|
||||
if (!m_diseq_eh)
|
||||
return;
|
||||
i_diseq_eh = [this](void* ctx, user_propagator::callback* cb, unsigned u, unsigned v) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_diseq_eh(ctx, &i_cb, m_internal2var[u], m_internal2var[v]);
|
||||
};
|
||||
m_ctx->user_propagate_register_diseq(i_diseq_eh);
|
||||
}
|
||||
|
||||
void init_i_created_eh() {
|
||||
if (!m_created_eh)
|
||||
return;
|
||||
i_created_eh = [this](void* ctx, user_propagator::callback* cb, expr* e, unsigned i) {
|
||||
unsigned j = m_vars.size();
|
||||
m_vars.push_back(e);
|
||||
m_internal2var.setx(i, j, 0);
|
||||
m_var2internal.setx(j, i, 0);
|
||||
m_created_eh(ctx, cb, e, j);
|
||||
};
|
||||
m_ctx->user_propagate_register_created(i_created_eh);
|
||||
}
|
||||
|
||||
void init_i_push_pop() {
|
||||
i_push_eh = [this](void* ctx) {
|
||||
m_limit.push_back(m_vars.size());
|
||||
m_push_eh(ctx);
|
||||
};
|
||||
i_pop_eh = [this](void* ctx, unsigned n) {
|
||||
unsigned old_sz = m_limit.size() - n;
|
||||
unsigned num_vars = m_limit[old_sz];
|
||||
m_vars.shrink(num_vars);
|
||||
m_limit.shrink(old_sz);
|
||||
m_pop_eh(ctx, n);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void user_propagate_delay_init() {
|
||||
if (!m_user_ctx)
|
||||
return;
|
||||
init_i_push_pop();
|
||||
m_ctx->user_propagate_init(m_user_ctx, i_push_eh, i_pop_eh, m_fresh_eh);
|
||||
init_i_fixed_eh();
|
||||
init_i_final_eh();
|
||||
init_i_eq_eh();
|
||||
init_i_diseq_eh();
|
||||
init_i_created_eh();
|
||||
m_ctx->user_propagate_init(m_user_ctx, m_push_eh, m_pop_eh, m_fresh_eh);
|
||||
if (m_fixed_eh) m_ctx->user_propagate_register_fixed(m_fixed_eh);
|
||||
if (m_final_eh) m_ctx->user_propagate_register_final(m_final_eh);
|
||||
if (m_eq_eh) m_ctx->user_propagate_register_eq(m_eq_eh);
|
||||
if (m_diseq_eh) m_ctx->user_propagate_register_diseq(m_diseq_eh);
|
||||
if (m_created_eh) m_ctx->user_propagate_register_created(m_created_eh);
|
||||
if (m_decide_eh) m_ctx->user_propagate_register_decide(m_decide_eh);
|
||||
|
||||
unsigned i = 0;
|
||||
for (expr* v : m_vars) {
|
||||
unsigned j = m_ctx->user_propagate_register_expr(v);
|
||||
m_var2internal.setx(i, j, 0);
|
||||
m_internal2var.setx(j, i, 0);
|
||||
++i;
|
||||
}
|
||||
for (expr* v : m_vars)
|
||||
m_ctx->user_propagate_register_expr(v);
|
||||
}
|
||||
|
||||
void user_propagate_clear() override {
|
||||
|
@ -496,9 +378,8 @@ public:
|
|||
m_diseq_eh = diseq_eh;
|
||||
}
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e) override {
|
||||
void user_propagate_register_expr(expr* e) override {
|
||||
m_vars.push_back(e);
|
||||
return m_vars.size() - 1;
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override {
|
||||
|
|
|
@ -602,9 +602,11 @@ namespace smt {
|
|||
void add_row_entry(unsigned r_id, numeral const & coeff, theory_var v);
|
||||
uint_set& row_vars();
|
||||
class scoped_row_vars;
|
||||
|
||||
|
||||
void check_app(expr* e, expr* n);
|
||||
void internalize_internal_monomial(app * m, unsigned r_id);
|
||||
theory_var internalize_add(app * n);
|
||||
theory_var internalize_sub(app * n);
|
||||
theory_var internalize_mul_core(app * m);
|
||||
theory_var internalize_mul(app * m);
|
||||
theory_var internalize_div(app * n);
|
||||
|
|
|
@ -302,6 +302,44 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::check_app(expr* e, expr* n) {
|
||||
if (is_app(e))
|
||||
return;
|
||||
std::ostringstream strm;
|
||||
strm << mk_pp(n, m) << " contains a " << (is_var(e) ? "free variable":"quantifier");
|
||||
throw default_exception(strm.str());
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
theory_var theory_arith<Ext>::internalize_sub(app * n) {
|
||||
VERIFY(m_util.is_sub(n));
|
||||
bool first = true;
|
||||
unsigned r_id = mk_row();
|
||||
scoped_row_vars _sc(m_row_vars, m_row_vars_top);
|
||||
theory_var v;
|
||||
for (expr* arg : *n) {
|
||||
check_app(arg, n);
|
||||
v = internalize_term_core(to_app(arg));
|
||||
if (first)
|
||||
add_row_entry<true>(r_id, numeral::one(), v);
|
||||
else
|
||||
add_row_entry<false>(r_id, numeral::one(), v);
|
||||
first = false;
|
||||
}
|
||||
enode * e = mk_enode(n);
|
||||
v = e->get_th_var(get_id());
|
||||
if (v == null_theory_var) {
|
||||
v = mk_var(e);
|
||||
add_row_entry<false>(r_id, numeral::one(), v);
|
||||
init_row(r_id);
|
||||
}
|
||||
else
|
||||
del_row(r_id);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Internalize a polynomial (+ h t). Return an alias for the monomial, that is,
|
||||
a variable v such that v = (+ h t) is a new row in the tableau.
|
||||
|
@ -314,11 +352,7 @@ namespace smt {
|
|||
unsigned r_id = mk_row();
|
||||
scoped_row_vars _sc(m_row_vars, m_row_vars_top);
|
||||
for (expr* arg : *n) {
|
||||
if (is_var(arg)) {
|
||||
std::ostringstream strm;
|
||||
strm << mk_pp(n, m) << " contains a free variable";
|
||||
throw default_exception(strm.str());
|
||||
}
|
||||
check_app(arg, n);
|
||||
internalize_internal_monomial(to_app(arg), r_id);
|
||||
}
|
||||
enode * e = mk_enode(n);
|
||||
|
@ -383,11 +417,7 @@ namespace smt {
|
|||
}
|
||||
unsigned r_id = mk_row();
|
||||
scoped_row_vars _sc(m_row_vars, m_row_vars_top);
|
||||
if (is_var(arg1)) {
|
||||
std::ostringstream strm;
|
||||
strm << mk_pp(m, get_manager()) << " contains a free variable";
|
||||
throw default_exception(strm.str());
|
||||
}
|
||||
check_app(arg1, m);
|
||||
if (reflection_enabled())
|
||||
internalize_term_core(to_app(arg0));
|
||||
theory_var v = internalize_mul_core(to_app(arg1));
|
||||
|
@ -749,7 +779,6 @@ namespace smt {
|
|||
return e->get_th_var(get_id());
|
||||
}
|
||||
|
||||
SASSERT(!m_util.is_sub(n));
|
||||
SASSERT(!m_util.is_uminus(n));
|
||||
|
||||
if (m_util.is_add(n))
|
||||
|
@ -770,6 +799,8 @@ namespace smt {
|
|||
return internalize_to_int(n);
|
||||
else if (m_util.is_numeral(n))
|
||||
return internalize_numeral(n);
|
||||
else if (m_util.is_sub(n))
|
||||
return internalize_sub(n);
|
||||
if (m_util.is_power(n)) {
|
||||
// unsupported
|
||||
found_unsupported_op(n);
|
||||
|
|
|
@ -240,12 +240,16 @@ namespace smt {
|
|||
bool theory_array::internalize_term_core(app * n) {
|
||||
TRACE("array_bug", tout << mk_bounded_pp(n, m) << "\n";);
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
ctx.internalize(n->get_arg(i), false);
|
||||
if (ctx.e_internalized(n)) {
|
||||
for (expr* arg : *n)
|
||||
ctx.internalize(arg, false);
|
||||
// force merge-tf by re-internalizing expression.
|
||||
for (expr* arg : *n)
|
||||
if (m.is_bool(arg))
|
||||
ctx.internalize(arg, false);
|
||||
if (ctx.e_internalized(n))
|
||||
return false;
|
||||
}
|
||||
enode * e = ctx.mk_enode(n, false, false, true);
|
||||
|
||||
enode * e = ctx.mk_enode(n, false, false, true);
|
||||
if (!is_attached_to_var(e))
|
||||
mk_var(e);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace smt {
|
|||
unsigned m_num_axiom1, m_num_axiom2a, m_num_axiom2b, m_num_extensionality, m_num_eq_splits;
|
||||
unsigned m_num_map_axiom, m_num_default_map_axiom;
|
||||
unsigned m_num_select_const_axiom, m_num_default_store_axiom, m_num_default_const_axiom, m_num_default_as_array_axiom;
|
||||
unsigned m_num_select_as_array_axiom;
|
||||
unsigned m_num_select_as_array_axiom, m_num_default_lambda_axiom;
|
||||
void reset() { memset(this, 0, sizeof(theory_array_stats)); }
|
||||
theory_array_stats() { reset(); }
|
||||
};
|
||||
|
|
|
@ -958,8 +958,8 @@ namespace smt {
|
|||
fi->insert_entry(args.data(), result);
|
||||
}
|
||||
|
||||
parameter p[1] = { parameter(f) };
|
||||
return m.mk_app(m_fid, OP_AS_ARRAY, 1, p);
|
||||
parameter p(f);
|
||||
return m.mk_app(m_fid, OP_AS_ARRAY, 1, &p);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -181,6 +181,17 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
void theory_array_full::add_lambda(theory_var v, enode* lam) {
|
||||
var_data * d = m_var_data[v];
|
||||
unsigned lambda_equiv_class_size = get_lambda_equiv_size(v, d);
|
||||
if (m_params.m_array_always_prop_upward || lambda_equiv_class_size >= 1)
|
||||
set_prop_upward(v, d);
|
||||
ptr_vector<enode> & lambdas = m_var_data_full[v]->m_lambdas;
|
||||
m_trail_stack.push(push_back_trail<enode *, false>(lambdas));
|
||||
lambdas.push_back(lam);
|
||||
instantiate_default_lambda_def_axiom(lam);
|
||||
}
|
||||
|
||||
void theory_array_full::add_as_array(theory_var v, enode* arr) {
|
||||
var_data * d = m_var_data[v];
|
||||
unsigned lambda_equiv_class_size = get_lambda_equiv_size(v, d);
|
||||
|
@ -238,6 +249,10 @@ namespace smt {
|
|||
instantiate_default_as_array_axiom(n);
|
||||
d->m_as_arrays.push_back(n);
|
||||
}
|
||||
else if (m.is_lambda_def(n->get_decl())) {
|
||||
instantiate_default_lambda_def_axiom(n);
|
||||
d->m_lambdas.push_back(n);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -331,18 +346,16 @@ namespace smt {
|
|||
// v1 is the new root
|
||||
SASSERT(v1 == find(v1));
|
||||
var_data_full * d2 = m_var_data_full[v2];
|
||||
for (enode * n : d2->m_maps) {
|
||||
for (enode * n : d2->m_maps)
|
||||
add_map(v1, n);
|
||||
}
|
||||
for (enode * n : d2->m_parent_maps) {
|
||||
for (enode * n : d2->m_parent_maps)
|
||||
add_parent_map(v1, n);
|
||||
}
|
||||
for (enode * n : d2->m_consts) {
|
||||
for (enode * n : d2->m_consts)
|
||||
add_const(v1, n);
|
||||
}
|
||||
for (enode * n : d2->m_as_arrays) {
|
||||
for (enode * n : d2->m_as_arrays)
|
||||
add_as_array(v1, n);
|
||||
}
|
||||
for (enode* n : d2->m_lambdas)
|
||||
add_lambda(v1, n);
|
||||
TRACE("array",
|
||||
tout << pp(get_enode(v1), m) << "\n";
|
||||
tout << pp(get_enode(v2), m) << "\n";
|
||||
|
@ -577,6 +590,23 @@ namespace smt {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool theory_array_full::instantiate_default_lambda_def_axiom(enode* arr) {
|
||||
if (!ctx.add_fingerprint(this, m_default_lambda_fingerprint, 1, &arr))
|
||||
return false;
|
||||
m_stats.m_num_default_lambda_axiom++;
|
||||
expr* def = mk_default(arr->get_expr());
|
||||
quantifier* lam = m.is_lambda_def(arr->get_decl());
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(lam);
|
||||
for (unsigned i = 0; i < lam->get_num_decls(); ++i)
|
||||
args.push_back(mk_epsilon(lam->get_decl_sort(i)).first);
|
||||
expr_ref val(mk_select(args), m);
|
||||
ctx.internalize(def, false);
|
||||
ctx.internalize(val.get(), false);
|
||||
return try_assign_eq(val.get(), def);
|
||||
}
|
||||
|
||||
|
||||
bool theory_array_full::has_unitary_domain(app* array_term) {
|
||||
SASSERT(is_array_sort(array_term));
|
||||
sort* s = array_term->get_sort();
|
||||
|
@ -715,8 +745,8 @@ namespace smt {
|
|||
//
|
||||
//
|
||||
expr_ref_vector args1(m), args2(m);
|
||||
args1.push_back(store_app->get_arg(0));
|
||||
args2.push_back(store_app);
|
||||
args1.push_back(store_app);
|
||||
args2.push_back(store_app->get_arg(0));
|
||||
|
||||
for (unsigned i = 1; i + 1 < num_args; ++i) {
|
||||
expr* arg = store_app->get_arg(i);
|
||||
|
@ -732,40 +762,6 @@ namespace smt {
|
|||
ctx.internalize(def2, false);
|
||||
is_new = try_assign_eq(def1, sel1) || try_assign_eq(def2, sel2);
|
||||
return is_new;
|
||||
|
||||
|
||||
#if 0
|
||||
//
|
||||
// This is incorrect, issue #5593.
|
||||
//
|
||||
|
||||
// let A = store(B, i, v)
|
||||
//
|
||||
// Add:
|
||||
// default(A) = ite(epsilon1 = i, v, default(B))
|
||||
// A[diag(i)] = B[diag(i)]
|
||||
//
|
||||
expr_ref_vector eqs(m);
|
||||
expr_ref_vector args1(m), args2(m);
|
||||
args1.push_back(store_app->get_arg(0));
|
||||
args2.push_back(store_app);
|
||||
|
||||
for (unsigned i = 1; i + 1 < num_args; ++i) {
|
||||
expr* arg = store_app->get_arg(i);
|
||||
sort* srt = arg->get_sort();
|
||||
auto ep = mk_epsilon(srt);
|
||||
eqs.push_back(m.mk_eq(ep.first, arg));
|
||||
args1.push_back(m.mk_app(ep.second, arg));
|
||||
args2.push_back(m.mk_app(ep.second, arg));
|
||||
}
|
||||
expr_ref eq(mk_and(eqs), m);
|
||||
def2 = m.mk_ite(eq, store_app->get_arg(num_args-1), def2);
|
||||
app_ref sel1(m), sel2(m);
|
||||
sel1 = mk_select(args1);
|
||||
sel2 = mk_select(args2);
|
||||
std::cout << "small domain " << sel1 << " " << sel2 << "\n";
|
||||
is_new = try_assign_eq(sel1, sel2);
|
||||
#endif
|
||||
}
|
||||
|
||||
ctx.internalize(def1, false);
|
||||
|
@ -863,5 +859,6 @@ namespace smt {
|
|||
st.update("array def store", m_stats.m_num_default_store_axiom);
|
||||
st.update("array def as-array", m_stats.m_num_default_as_array_axiom);
|
||||
st.update("array sel as-array", m_stats.m_num_select_as_array_axiom);
|
||||
st.update("array def lambda", m_stats.m_num_default_lambda_axiom);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace smt {
|
|||
ptr_vector<enode> m_maps;
|
||||
ptr_vector<enode> m_consts;
|
||||
ptr_vector<enode> m_as_arrays;
|
||||
ptr_vector<enode> m_lambdas;
|
||||
ptr_vector<enode> m_parent_maps;
|
||||
};
|
||||
|
||||
|
@ -41,6 +42,7 @@ namespace smt {
|
|||
static unsigned const m_default_store_fingerprint = UINT_MAX - 113;
|
||||
static unsigned const m_default_const_fingerprint = UINT_MAX - 115;
|
||||
static unsigned const m_default_as_array_fingerprint = UINT_MAX - 116;
|
||||
static unsigned const m_default_lambda_fingerprint = UINT_MAX - 117;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -66,6 +68,7 @@ namespace smt {
|
|||
void add_map(theory_var v, enode* s);
|
||||
void add_parent_map(theory_var v, enode* s);
|
||||
void add_as_array(theory_var v, enode* arr);
|
||||
void add_lambda(theory_var v, enode* lam);
|
||||
|
||||
void add_parent_select(theory_var v, enode * s) override;
|
||||
void add_parent_default(theory_var v);
|
||||
|
@ -76,6 +79,7 @@ namespace smt {
|
|||
bool instantiate_default_store_axiom(enode* store);
|
||||
bool instantiate_default_map_axiom(enode* map);
|
||||
bool instantiate_default_as_array_axiom(enode* arr);
|
||||
bool instantiate_default_lambda_def_axiom(enode* arr);
|
||||
bool instantiate_parent_stores_default(theory_var v);
|
||||
|
||||
bool has_large_domain(app* array_term);
|
||||
|
|
|
@ -224,8 +224,6 @@ namespace smt {
|
|||
};
|
||||
|
||||
void theory_bv::add_new_diseq_axiom(theory_var v1, theory_var v2, unsigned idx) {
|
||||
if (!params().m_bv_eq_axioms)
|
||||
return;
|
||||
m_prop_diseqs.push_back(bv_diseq(v1, v2, idx));
|
||||
ctx.push_trail(push_back_vector<svector<bv_diseq>>(m_prop_diseqs));
|
||||
}
|
||||
|
@ -533,7 +531,6 @@ namespace smt {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool theory_bv::get_fixed_value(theory_var v, numeral & result) const {
|
||||
result.reset();
|
||||
unsigned i = 0;
|
||||
|
@ -997,7 +994,9 @@ namespace smt {
|
|||
process_args(n);
|
||||
expr_ref_vector arg1_bits(m), arg2_bits(m);
|
||||
get_arg_bits(n, 0, arg1_bits);
|
||||
get_arg_bits(n, 1, arg2_bits);
|
||||
get_arg_bits(n, 1, arg2_bits);
|
||||
if (ctx.b_internalized(n))
|
||||
return;
|
||||
expr_ref le(m);
|
||||
if (Signed)
|
||||
m_bb.mk_sle(arg1_bits.size(), arg1_bits.data(), arg2_bits.data(), le);
|
||||
|
@ -1321,6 +1320,7 @@ namespace smt {
|
|||
else {
|
||||
ctx.assign(consequent, mk_bit_eq_justification(v1, v2, consequent, antecedent));
|
||||
if (params().m_bv_eq_axioms) {
|
||||
|
||||
literal_vector lits;
|
||||
lits.push_back(~consequent);
|
||||
lits.push_back(antecedent);
|
||||
|
@ -1343,7 +1343,7 @@ namespace smt {
|
|||
ctx.mk_th_axiom(get_id(), lits.size(), lits.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_wpos[v2] == idx)
|
||||
find_wpos(v2);
|
||||
// REMARK: bit_eq_justification is marked as a theory_bv justification.
|
||||
|
@ -1820,6 +1820,39 @@ namespace smt {
|
|||
st.update("bv dynamic eqs", m_stats.m_num_eq_dynamic);
|
||||
}
|
||||
|
||||
theory_bv::var_enode_pos theory_bv::get_bv_with_theory(bool_var v, theory_id id) const {
|
||||
atom* a = get_bv2a(v);
|
||||
svector<var_enode_pos> vec;
|
||||
if (!a->is_bit())
|
||||
return var_enode_pos(nullptr, UINT32_MAX);
|
||||
bit_atom * b = static_cast<bit_atom*>(a);
|
||||
var_pos_occ * curr = b->m_occs;
|
||||
while (curr) {
|
||||
enode* n = get_enode(curr->m_var);
|
||||
if (n->get_th_var(id) != null_theory_var)
|
||||
return var_enode_pos(n, curr->m_idx);
|
||||
curr = curr->m_next;
|
||||
}
|
||||
return var_enode_pos(nullptr, UINT32_MAX);
|
||||
}
|
||||
|
||||
bool_var theory_bv::get_first_unassigned(unsigned start_bit, enode* n) const {
|
||||
theory_var v = n->get_th_var(get_family_id());
|
||||
auto& bits = m_bits[v];
|
||||
unsigned sz = bits.size();
|
||||
|
||||
for (unsigned i = start_bit; i < sz; ++i) {
|
||||
if (ctx.get_assignment(bits[i].var()) != l_undef)
|
||||
return bits[i].var();
|
||||
}
|
||||
for (unsigned i = 0; i < start_bit; ++i) {
|
||||
if (ctx.get_assignment(bits[i].var()) != l_undef)
|
||||
return bits[i].var();
|
||||
}
|
||||
|
||||
return null_bool_var;
|
||||
}
|
||||
|
||||
bool theory_bv::check_assignment(theory_var v) {
|
||||
if (!is_root(v))
|
||||
return true;
|
||||
|
|
|
@ -260,6 +260,9 @@ namespace smt {
|
|||
|
||||
smt_params const& params() const;
|
||||
public:
|
||||
|
||||
typedef std::pair<enode*, unsigned> var_enode_pos;
|
||||
|
||||
theory_bv(context& ctx);
|
||||
~theory_bv() override;
|
||||
|
||||
|
@ -284,6 +287,9 @@ namespace smt {
|
|||
bool get_fixed_value(app* x, numeral & result) const;
|
||||
bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector& explain) override;
|
||||
|
||||
var_enode_pos get_bv_with_theory(bool_var v, theory_id id) const;
|
||||
bool_var get_first_unassigned(unsigned start_bit, enode* n) const;
|
||||
|
||||
bool check_assignment(theory_var v);
|
||||
bool check_invariant();
|
||||
bool check_zero_one_bits(theory_var v);
|
||||
|
|
|
@ -254,6 +254,8 @@ namespace smt {
|
|||
app_ref n_is_con(m.mk_app(rec, own), m);
|
||||
ctx.internalize(n_is_con, false);
|
||||
literal lits[2] = { ~is_con, literal(ctx.get_bool_var(n_is_con)) };
|
||||
ctx.mark_as_relevant(lits[0]);
|
||||
ctx.mark_as_relevant(lits[1]);
|
||||
std::function<literal_vector(void)> fn = [&]() { return literal_vector(2, lits); };
|
||||
scoped_trace_stream _st(*this, fn);
|
||||
ctx.mk_th_axiom(get_id(), 2, lits);
|
||||
|
@ -297,7 +299,7 @@ namespace smt {
|
|||
TRACE("datatype", tout << "internalizing term:\n" << mk_pp(term, m) << "\n";);
|
||||
unsigned num_args = term->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
ctx.internalize(term->get_arg(i), has_quantifiers(term));
|
||||
ctx.internalize(term->get_arg(i), m.is_bool(term) && has_quantifiers(term));
|
||||
// the internalization of the arguments may trigger the internalization of term.
|
||||
if (ctx.e_internalized(term))
|
||||
return true;
|
||||
|
|
|
@ -65,8 +65,6 @@ class theory_lra::imp {
|
|||
unsigned m_idiv_lim;
|
||||
unsigned m_asserted_qhead;
|
||||
unsigned m_asserted_atoms_lim;
|
||||
unsigned m_underspecified_lim;
|
||||
expr* m_not_handled;
|
||||
};
|
||||
|
||||
struct delayed_atom {
|
||||
|
@ -161,7 +159,7 @@ class theory_lra::imp {
|
|||
svector<theory_var> m_definitions; // asserted rows corresponding to definitions
|
||||
|
||||
svector<delayed_atom> m_asserted_atoms;
|
||||
expr* m_not_handled;
|
||||
ptr_vector<expr> m_not_handled;
|
||||
ptr_vector<app> m_underspecified;
|
||||
ptr_vector<expr> m_idiv_terms;
|
||||
vector<ptr_vector<api_bound> > m_use_list; // bounds where variables are used.
|
||||
|
@ -294,19 +292,20 @@ class theory_lra::imp {
|
|||
m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report();
|
||||
m_nla->settings().grobner_quota() = prms.arith_nl_gr_q();
|
||||
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency();
|
||||
m_nla->settings().expensive_patching() = prms.arith_nl_expp();
|
||||
m_nla->settings().expensive_patching() = false;
|
||||
}
|
||||
}
|
||||
|
||||
void found_unsupported(expr* n) {
|
||||
ctx().push_trail(value_trail<expr*>(m_not_handled));
|
||||
TRACE("arith", tout << "unsupported " << mk_pp(n, m) << "\n";);
|
||||
m_not_handled = n;
|
||||
}
|
||||
ctx().push_trail(push_back_vector<ptr_vector<expr>>(m_not_handled));
|
||||
TRACE("arith", tout << "unsupported " << mk_pp(n, m) << "\n");
|
||||
m_not_handled.push_back(n);
|
||||
}
|
||||
|
||||
void found_underspecified(expr* n) {
|
||||
if (a.is_underspecified(n)) {
|
||||
TRACE("arith", tout << "Unhandled: " << mk_pp(n, m) << "\n";);
|
||||
ctx().push_trail(push_back_vector<ptr_vector<app>>(m_underspecified));
|
||||
m_underspecified.push_back(to_app(n));
|
||||
}
|
||||
expr* e = nullptr, *x = nullptr, *y = nullptr;
|
||||
|
@ -857,7 +856,6 @@ public:
|
|||
m_zero_var(UINT_MAX),
|
||||
m_rone_var(UINT_MAX),
|
||||
m_rzero_var(UINT_MAX),
|
||||
m_not_handled(nullptr),
|
||||
m_asserted_qhead(0),
|
||||
m_assume_eq_head(0),
|
||||
m_num_conflicts(0),
|
||||
|
@ -1052,8 +1050,6 @@ public:
|
|||
sc.m_asserted_qhead = m_asserted_qhead;
|
||||
sc.m_idiv_lim = m_idiv_terms.size();
|
||||
sc.m_asserted_atoms_lim = m_asserted_atoms.size();
|
||||
sc.m_not_handled = m_not_handled;
|
||||
sc.m_underspecified_lim = m_underspecified.size();
|
||||
lp().push();
|
||||
if (m_nla)
|
||||
m_nla->push();
|
||||
|
@ -1070,8 +1066,6 @@ public:
|
|||
m_idiv_terms.shrink(m_scopes[old_size].m_idiv_lim);
|
||||
m_asserted_atoms.shrink(m_scopes[old_size].m_asserted_atoms_lim);
|
||||
m_asserted_qhead = m_scopes[old_size].m_asserted_qhead;
|
||||
m_underspecified.shrink(m_scopes[old_size].m_underspecified_lim);
|
||||
m_not_handled = m_scopes[old_size].m_not_handled;
|
||||
m_scopes.resize(old_size);
|
||||
lp().pop(num_scopes);
|
||||
// VERIFY(l_false != make_feasible());
|
||||
|
@ -1567,9 +1561,10 @@ public:
|
|||
if (assume_eqs()) {
|
||||
++m_stats.m_assume_eqs;
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (m_not_handled != nullptr) {
|
||||
TRACE("arith", tout << "unhandled operator " << mk_pp(m_not_handled, m) << "\n";);
|
||||
}
|
||||
for (expr* e : m_not_handled) {
|
||||
(void) e; // just in case TRACE() is a no-op
|
||||
TRACE("arith", tout << "unhandled operator " << mk_pp(e, m) << "\n";);
|
||||
st = FC_GIVEUP;
|
||||
}
|
||||
return st;
|
||||
|
@ -1689,8 +1684,11 @@ public:
|
|||
if (m_idiv_terms.empty()) {
|
||||
return true;
|
||||
}
|
||||
bool all_divs_valid = true;
|
||||
for (unsigned i = 0; i < m_idiv_terms.size(); ++i) {
|
||||
bool all_divs_valid = true;
|
||||
unsigned count = 0;
|
||||
unsigned offset = ctx().get_random_value();
|
||||
for (unsigned j = 0; j < m_idiv_terms.size(); ++j) {
|
||||
unsigned i = (offset + j) % m_idiv_terms.size();
|
||||
expr* n = m_idiv_terms[i];
|
||||
expr* p = nullptr, *q = nullptr;
|
||||
VERIFY(a.is_idiv(n, p, q));
|
||||
|
@ -1712,6 +1710,7 @@ public:
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (a.is_numeral(q, r2) && r2.is_pos()) {
|
||||
if (!a.is_bounded(n)) {
|
||||
TRACE("arith", tout << "unbounded " << expr_ref(n, m) << "\n";);
|
||||
|
@ -1720,7 +1719,8 @@ public:
|
|||
if (!is_registered_var(v))
|
||||
continue;
|
||||
lp::impq val_v = get_ivalue(v);
|
||||
if (val_v.y.is_zero() && val_v.x == div(r1.x, r2)) continue;
|
||||
if (val_v.y.is_zero() && val_v.x == div(r1.x, r2))
|
||||
continue;
|
||||
|
||||
TRACE("arith", tout << get_value(v) << " != " << r1 << " div " << r2 << "\n";);
|
||||
rational div_r = div(r1.x, r2);
|
||||
|
@ -1738,6 +1738,7 @@ public:
|
|||
hi = floor(hi/mul);
|
||||
lo = ceil(lo/mul);
|
||||
}
|
||||
std::cout << mk_pp(p, m) << " " << mk_pp(n, m) << " " << hi << " " << lo << " " << div_r << "\n";
|
||||
literal p_le_r1 = mk_literal(a.mk_le(p, a.mk_numeral(hi, true)));
|
||||
literal p_ge_r1 = mk_literal(a.mk_ge(p, a.mk_numeral(lo, true)));
|
||||
literal n_le_div = mk_literal(a.mk_le(n, a.mk_numeral(div_r, true)));
|
||||
|
@ -1752,6 +1753,8 @@ public:
|
|||
}
|
||||
|
||||
all_divs_valid = false;
|
||||
++count;
|
||||
|
||||
|
||||
TRACE("arith",
|
||||
tout << r1 << " div " << r2 << "\n";
|
||||
|
@ -1863,9 +1866,6 @@ public:
|
|||
return l_undef;
|
||||
}
|
||||
lbool lia_check = l_undef;
|
||||
if (!check_idiv_bounds()) {
|
||||
return l_false;
|
||||
}
|
||||
switch (m_lia->check(&m_explanation)) {
|
||||
case lp::lia_move::sat:
|
||||
lia_check = l_true;
|
||||
|
@ -1935,6 +1935,9 @@ public:
|
|||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (lia_check != l_false && !check_idiv_bounds())
|
||||
return l_false;
|
||||
|
||||
return lia_check;
|
||||
}
|
||||
|
||||
|
@ -2020,9 +2023,8 @@ public:
|
|||
Use the set to determine if a variable is shared.
|
||||
*/
|
||||
bool is_shared(theory_var v) const {
|
||||
if (m_underspecified.empty()) {
|
||||
if (m_underspecified.empty())
|
||||
return false;
|
||||
}
|
||||
enode * n = get_enode(v);
|
||||
enode * r = n->get_root();
|
||||
unsigned usz = m_underspecified.size();
|
||||
|
@ -2031,19 +2033,15 @@ public:
|
|||
for (unsigned i = 0; i < usz; ++i) {
|
||||
app* u = m_underspecified[i];
|
||||
unsigned sz = u->get_num_args();
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
if (ctx().get_enode(u->get_arg(j))->get_root() == r) {
|
||||
for (unsigned j = 0; j < sz; ++j)
|
||||
if (ctx().get_enode(u->get_arg(j))->get_root() == r)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (enode * parent : r->get_const_parents()) {
|
||||
if (a.is_underspecified(parent->get_expr())) {
|
||||
for (enode * parent : r->get_const_parents())
|
||||
if (a.is_underspecified(parent->get_expr()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3199,7 +3197,7 @@ public:
|
|||
m_arith_eq_adapter.reset_eh();
|
||||
m_solver = nullptr;
|
||||
m_internalize_head = 0;
|
||||
m_not_handled = nullptr;
|
||||
m_not_handled.reset();
|
||||
del_bounds(0);
|
||||
m_unassigned_bounds.reset();
|
||||
m_asserted_qhead = 0;
|
||||
|
|
|
@ -1881,12 +1881,13 @@ namespace smt {
|
|||
inc_coeff(conseq, offset);
|
||||
clause& cls = *js.get_clause();
|
||||
justification* cjs = cls.get_justification();
|
||||
if (cjs && !is_proof_justification(*cjs)) {
|
||||
TRACE("pb", tout << "skipping justification for clause over: " << conseq << " "
|
||||
<< typeid(*cjs).name() << "\n";);
|
||||
unsigned num_lits = cls.get_num_literals();
|
||||
if (cjs && typeid(smt::unit_resolution_justification) == typeid(*cjs))
|
||||
;
|
||||
else if (cjs && !is_proof_justification(*cjs)) {
|
||||
TRACE("pb", tout << "not processing justification over: " << conseq << " " << typeid(*cjs).name() << "\n";);
|
||||
break;
|
||||
}
|
||||
unsigned num_lits = cls.get_num_literals();
|
||||
if (cls.get_literal(0) == conseq) {
|
||||
process_antecedent(cls.get_literal(1), offset);
|
||||
}
|
||||
|
|
|
@ -1498,8 +1498,8 @@ void theory_seq::add_length(expr* l) {
|
|||
TRACE("seq", tout << mk_bounded_pp(e, m, 2) << "\n";);
|
||||
m_length.push_back(l);
|
||||
m_has_length.insert(e);
|
||||
m_trail_stack.push(insert_obj_trail<expr>(m_has_length, e));
|
||||
m_trail_stack.push(push_back_vector<expr_ref_vector>(m_length));
|
||||
m_trail_stack.push(insert_obj_trail<expr>(m_has_length, e));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1542,8 +1542,8 @@ bool theory_seq::add_length_to_eqc(expr* e) {
|
|||
expr* o = n->get_expr();
|
||||
if (!has_length(o)) {
|
||||
expr_ref len(m_util.str.mk_length(o), m);
|
||||
ensure_enode(len);
|
||||
add_length(len);
|
||||
ensure_enode(len);
|
||||
change = true;
|
||||
}
|
||||
n = n->get_next();
|
||||
|
|
|
@ -17,13 +17,17 @@ Author:
|
|||
|
||||
|
||||
#include "ast/ast_pp.h"
|
||||
#include "smt/theory_bv.h"
|
||||
#include "smt/theory_user_propagator.h"
|
||||
#include "smt/smt_context.h"
|
||||
|
||||
using namespace smt;
|
||||
|
||||
theory_user_propagator::theory_user_propagator(context& ctx):
|
||||
theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name()))
|
||||
theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())),
|
||||
m_var2expr(ctx.get_manager()),
|
||||
m_push_popping(false),
|
||||
m_to_add(ctx.get_manager())
|
||||
{}
|
||||
|
||||
theory_user_propagator::~theory_user_propagator() {
|
||||
|
@ -32,15 +36,18 @@ theory_user_propagator::~theory_user_propagator() {
|
|||
|
||||
void theory_user_propagator::force_push() {
|
||||
for (; m_num_scopes > 0; --m_num_scopes) {
|
||||
flet<bool> _pushing(m_push_popping, true);
|
||||
theory::push_scope_eh();
|
||||
m_push_eh(m_user_context);
|
||||
m_prop_lim.push_back(m_prop.size());
|
||||
m_to_add_lim.push_back(m_to_add.size());
|
||||
m_push_eh(m_user_context, this);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned theory_user_propagator::add_expr(expr* e) {
|
||||
void theory_user_propagator::add_expr(expr* term, bool ensure_enode) {
|
||||
force_push();
|
||||
expr_ref r(m);
|
||||
expr* e = term;
|
||||
ctx.get_rewriter()(e, r);
|
||||
if (r != e) {
|
||||
r = m.mk_fresh_const("aux-expr", e->get_sort());
|
||||
|
@ -50,10 +57,16 @@ unsigned theory_user_propagator::add_expr(expr* e) {
|
|||
e = r;
|
||||
ctx.mark_as_relevant(eq.get());
|
||||
}
|
||||
enode* n = ensure_enode(e);
|
||||
enode* n = ensure_enode ? this->ensure_enode(e) : ctx.get_enode(e);
|
||||
if (is_attached_to_var(n))
|
||||
return n->get_th_var(get_id());
|
||||
return;
|
||||
|
||||
|
||||
theory_var v = mk_var(n);
|
||||
m_var2expr.reserve(v + 1);
|
||||
m_var2expr[v] = term;
|
||||
m_expr2var.setx(term->get_id(), v, null_theory_var);
|
||||
|
||||
if (m.is_bool(e) && !ctx.b_internalized(e)) {
|
||||
bool_var bv = ctx.mk_bool_var(e);
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
|
@ -65,32 +78,46 @@ unsigned theory_user_propagator::add_expr(expr* e) {
|
|||
literal_vector explain;
|
||||
if (ctx.is_fixed(n, r, explain))
|
||||
m_prop.push_back(prop_info(explain, v, r));
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
void theory_user_propagator::propagate_cb(
|
||||
unsigned num_fixed, unsigned const* fixed_ids,
|
||||
unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs,
|
||||
unsigned num_fixed, expr* const* fixed_ids,
|
||||
unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs,
|
||||
expr* conseq) {
|
||||
CTRACE("user_propagate", ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true,
|
||||
ctx.display(tout << "redundant consequence: " << mk_pp(conseq, m) << "\n"));
|
||||
if (ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true)
|
||||
|
||||
expr_ref _conseq(conseq, m);
|
||||
ctx.get_rewriter()(conseq, _conseq);
|
||||
if (ctx.lit_internalized(_conseq) && ctx.get_assignment(ctx.get_literal(_conseq)) == l_true)
|
||||
return;
|
||||
m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, expr_ref(conseq, m)));
|
||||
m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, _conseq));
|
||||
}
|
||||
|
||||
unsigned theory_user_propagator::register_cb(expr* e) {
|
||||
return add_expr(e);
|
||||
void theory_user_propagator::register_cb(expr* e) {
|
||||
if (m_push_popping)
|
||||
m_to_add.push_back(e);
|
||||
else
|
||||
add_expr(e, true);
|
||||
}
|
||||
|
||||
theory * theory_user_propagator::mk_fresh(context * new_ctx) {
|
||||
auto* th = alloc(theory_user_propagator, *new_ctx);
|
||||
void* ctx = m_fresh_eh(m_user_context, new_ctx->get_manager(), th->m_api_context);
|
||||
auto* th = alloc(theory_user_propagator, *new_ctx);
|
||||
void* ctx;
|
||||
try {
|
||||
ctx = m_fresh_eh(m_user_context, new_ctx->get_manager(), th->m_api_context);
|
||||
}
|
||||
catch (...) {
|
||||
throw default_exception("Exception thrown in \"fresh\"-callback");
|
||||
}
|
||||
th->add(ctx, m_push_eh, m_pop_eh, m_fresh_eh);
|
||||
if ((bool)m_fixed_eh) th->register_fixed(m_fixed_eh);
|
||||
if ((bool)m_final_eh) th->register_final(m_final_eh);
|
||||
if ((bool)m_eq_eh) th->register_eq(m_eq_eh);
|
||||
if ((bool)m_diseq_eh) th->register_diseq(m_diseq_eh);
|
||||
if ((bool)m_created_eh) th->register_created(m_created_eh);
|
||||
if ((bool)m_decide_eh) th->register_decide(m_decide_eh);
|
||||
return th;
|
||||
}
|
||||
|
||||
|
@ -98,10 +125,17 @@ final_check_status theory_user_propagator::final_check_eh() {
|
|||
if (!(bool)m_final_eh)
|
||||
return FC_DONE;
|
||||
force_push();
|
||||
unsigned sz = m_prop.size();
|
||||
m_final_eh(m_user_context, this);
|
||||
unsigned sz1 = m_prop.size();
|
||||
unsigned sz2 = m_expr2var.size();
|
||||
try {
|
||||
m_final_eh(m_user_context, this);
|
||||
}
|
||||
catch (...) {
|
||||
throw default_exception("Exception thrown in \"final\"-callback");
|
||||
}
|
||||
propagate();
|
||||
bool done = (sz == m_prop.size()) && !ctx.inconsistent();
|
||||
// check if it became inconsistent or something new was propagated/registered
|
||||
bool done = (sz1 == m_prop.size()) && (sz2 == m_expr2var.size()) && !ctx.inconsistent();
|
||||
return done ? FC_DONE : FC_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -114,40 +148,116 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu
|
|||
m_fixed.insert(v);
|
||||
ctx.push_trail(insert_map<uint_set, unsigned>(m_fixed, v));
|
||||
m_id2justification.setx(v, literal_vector(num_lits, jlits), literal_vector());
|
||||
m_fixed_eh(m_user_context, this, v, value);
|
||||
try {
|
||||
m_fixed_eh(m_user_context, this, var2expr(v), value);
|
||||
}
|
||||
catch (...) {
|
||||
throw default_exception("Exception thrown in \"fixed\"-callback");
|
||||
}
|
||||
}
|
||||
|
||||
void theory_user_propagator::push_scope_eh() {
|
||||
void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
|
||||
|
||||
const bool_var_data& d = ctx.get_bdata(var);
|
||||
|
||||
if (!d.is_theory_atom())
|
||||
return;
|
||||
|
||||
theory* th = ctx.get_theory(d.get_theory());
|
||||
|
||||
bv_util bv(m);
|
||||
enode* original_enode = nullptr;
|
||||
unsigned original_bit = 0;
|
||||
|
||||
if (d.is_enode() && th->get_family_id() == get_family_id()) {
|
||||
// variable is just a registered expression
|
||||
original_enode = ctx.bool_var2enode(var);
|
||||
}
|
||||
else if (th->get_family_id() == bv.get_fid()) {
|
||||
// it might be a registered bit-vector
|
||||
auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id());
|
||||
if (!registered_bv.first)
|
||||
// there is no registered bv associated with the bit
|
||||
return;
|
||||
original_enode = registered_bv.first;
|
||||
original_bit = registered_bv.second;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// call the registered callback
|
||||
unsigned new_bit = original_bit;
|
||||
lbool phase = is_pos ? l_true : l_false;
|
||||
|
||||
expr* e = var2expr(original_enode->get_th_var(get_family_id()));
|
||||
m_decide_eh(m_user_context, this, &e, &new_bit, &phase);
|
||||
enode* new_enode = ctx.get_enode(e);
|
||||
|
||||
// check if the callback changed something
|
||||
if (original_enode == new_enode && (new_enode->is_bool() || original_bit == new_bit)) {
|
||||
if (phase != l_undef)
|
||||
// it only affected the truth value
|
||||
is_pos = phase == l_true;
|
||||
return;
|
||||
}
|
||||
|
||||
bool_var old_var = var;
|
||||
if (new_enode->is_bool()) {
|
||||
// expression was set to a boolean
|
||||
bool_var new_var = ctx.enode2bool_var(new_enode);
|
||||
if (ctx.get_assignment(new_var) == l_undef) {
|
||||
var = new_var;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// expression was set to a bit-vector
|
||||
auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid());
|
||||
bool_var new_var = th_bv->get_first_unassigned(new_bit, new_enode);
|
||||
|
||||
if (new_var != null_bool_var) {
|
||||
var = new_var;
|
||||
}
|
||||
}
|
||||
|
||||
// in case the callback did not decide on a truth value -> let Z3 decide
|
||||
is_pos = ctx.guess(var, phase);
|
||||
}
|
||||
|
||||
void theory_user_propagator::push_scope_eh() {
|
||||
++m_num_scopes;
|
||||
}
|
||||
|
||||
void theory_user_propagator::pop_scope_eh(unsigned num_scopes) {
|
||||
flet<bool> _popping(m_push_popping, true);
|
||||
unsigned n = std::min(num_scopes, m_num_scopes);
|
||||
m_num_scopes -= n;
|
||||
num_scopes -= n;
|
||||
if (num_scopes == 0)
|
||||
return;
|
||||
m_pop_eh(m_user_context, num_scopes);
|
||||
theory::pop_scope_eh(num_scopes);
|
||||
unsigned old_sz = m_prop_lim.size() - num_scopes;
|
||||
m_prop.shrink(m_prop_lim[old_sz]);
|
||||
m_prop_lim.shrink(old_sz);
|
||||
old_sz = m_to_add_lim.size() - num_scopes;
|
||||
m_to_add.shrink(m_to_add_lim[old_sz]);
|
||||
m_to_add_lim.shrink(old_sz);
|
||||
m_pop_eh(m_user_context, this, num_scopes);
|
||||
}
|
||||
|
||||
bool theory_user_propagator::can_propagate() {
|
||||
return m_qhead < m_prop.size();
|
||||
return m_qhead < m_prop.size() || m_to_add_qhead < m_to_add.size();
|
||||
}
|
||||
|
||||
void theory_user_propagator::propagate_consequence(prop_info const& prop) {
|
||||
justification* js;
|
||||
m_lits.reset();
|
||||
m_eqs.reset();
|
||||
for (unsigned id : prop.m_ids)
|
||||
m_lits.append(m_id2justification[id]);
|
||||
for (expr* id : prop.m_ids)
|
||||
m_lits.append(m_id2justification[expr2var(id)]);
|
||||
for (auto const& p : prop.m_eqs)
|
||||
m_eqs.push_back(enode_pair(get_enode(p.first), get_enode(p.second)));
|
||||
m_eqs.push_back(enode_pair(get_enode(expr2var(p.first)), get_enode(expr2var(p.second))));
|
||||
DEBUG_CODE(for (auto const& p : m_eqs) VERIFY(p.first->get_root() == p.second->get_root()););
|
||||
DEBUG_CODE(for (unsigned id : prop.m_ids) VERIFY(m_fixed.contains(id)););
|
||||
DEBUG_CODE(for (expr* e : prop.m_ids) VERIFY(m_fixed.contains(expr2var(e))););
|
||||
DEBUG_CODE(for (literal lit : m_lits) VERIFY(ctx.get_assignment(lit) == l_true););
|
||||
|
||||
TRACE("user_propagate", tout << "propagating #" << prop.m_conseq->get_id() << ": " << prop.m_conseq << "\n");
|
||||
|
@ -188,10 +298,19 @@ void theory_user_propagator::propagate_new_fixed(prop_info const& prop) {
|
|||
|
||||
void theory_user_propagator::propagate() {
|
||||
TRACE("user_propagate", tout << "propagating queue head: " << m_qhead << " prop queue: " << m_prop.size() << "\n");
|
||||
if (m_qhead == m_prop.size())
|
||||
if (m_qhead == m_prop.size() && m_to_add_qhead == m_to_add.size())
|
||||
return;
|
||||
force_push();
|
||||
unsigned qhead = m_qhead;
|
||||
|
||||
unsigned qhead = m_to_add_qhead;
|
||||
if (qhead < m_to_add.size()) {
|
||||
for (; qhead < m_to_add.size(); ++qhead)
|
||||
add_expr(m_to_add.get(qhead), true);
|
||||
ctx.push_trail(value_trail<unsigned>(m_to_add_qhead));
|
||||
m_to_add_qhead = qhead;
|
||||
}
|
||||
|
||||
qhead = m_qhead;
|
||||
while (qhead < m_prop.size() && !ctx.inconsistent()) {
|
||||
auto const& prop = m_prop[qhead];
|
||||
if (prop.m_var == null_theory_var)
|
||||
|
@ -216,12 +335,18 @@ bool theory_user_propagator::internalize_term(app* term) {
|
|||
if (term->get_family_id() == get_id() && !ctx.e_internalized(term))
|
||||
ctx.mk_enode(term, true, false, true);
|
||||
|
||||
unsigned v = add_expr(term);
|
||||
|
||||
if (!m_created_eh && (m_fixed_eh || m_eq_eh || m_diseq_eh))
|
||||
add_expr(term, false);
|
||||
|
||||
if (!m_created_eh)
|
||||
throw default_exception("You have to register a created event handler for new terms if you track them");
|
||||
if (m_created_eh)
|
||||
m_created_eh(m_user_context, this, term, v);
|
||||
|
||||
try {
|
||||
m_created_eh(m_user_context, this, term);
|
||||
}
|
||||
catch (...) {
|
||||
throw default_exception("Exception thrown in \"created\"-callback");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ namespace smt {
|
|||
class theory_user_propagator : public theory, public user_propagator::callback {
|
||||
|
||||
struct prop_info {
|
||||
unsigned_vector m_ids;
|
||||
ptr_vector<expr> m_ids;
|
||||
expr_ref m_conseq;
|
||||
svector<std::pair<unsigned, unsigned>> m_eqs;
|
||||
svector<std::pair<expr*, expr*>> m_eqs;
|
||||
literal_vector m_lits;
|
||||
theory_var m_var = null_theory_var;
|
||||
prop_info(unsigned num_fixed, unsigned const* fixed_ids,
|
||||
unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr_ref const& c):
|
||||
theory_var m_var = null_theory_var;
|
||||
prop_info(unsigned num_fixed, expr* const* fixed_ids,
|
||||
unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr_ref const& c):
|
||||
m_ids(num_fixed, fixed_ids),
|
||||
m_conseq(c) {
|
||||
for (unsigned i = 0; i < num_eqs; ++i)
|
||||
|
@ -56,7 +56,7 @@ namespace smt {
|
|||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
void* m_user_context = nullptr;
|
||||
void* m_user_context = nullptr;
|
||||
user_propagator::push_eh_t m_push_eh;
|
||||
user_propagator::pop_eh_t m_pop_eh;
|
||||
user_propagator::fresh_eh_t m_fresh_eh;
|
||||
|
@ -64,7 +64,8 @@ namespace smt {
|
|||
user_propagator::fixed_eh_t m_fixed_eh;
|
||||
user_propagator::eq_eh_t m_eq_eh;
|
||||
user_propagator::eq_eh_t m_diseq_eh;
|
||||
user_propagator::created_eh_t m_created_eh;
|
||||
user_propagator::created_eh_t m_created_eh;
|
||||
user_propagator::decide_eh_t m_decide_eh;
|
||||
|
||||
user_propagator::context_obj* m_api_context = nullptr;
|
||||
unsigned m_qhead = 0;
|
||||
|
@ -76,6 +77,19 @@ namespace smt {
|
|||
literal_vector m_lits;
|
||||
enode_pair_vector m_eqs;
|
||||
stats m_stats;
|
||||
expr_ref_vector m_var2expr;
|
||||
unsigned_vector m_expr2var;
|
||||
bool m_push_popping;
|
||||
expr_ref_vector m_to_add;
|
||||
unsigned_vector m_to_add_lim;
|
||||
unsigned m_to_add_qhead = 0;
|
||||
|
||||
expr* var2expr(theory_var v) { return m_var2expr.get(v); }
|
||||
theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; }
|
||||
void check_defined(expr* e) {
|
||||
if (e->get_id() >= m_expr2var.size() || get_num_vars() <= m_expr2var[e->get_id()])
|
||||
throw default_exception("expression is not registered");
|
||||
}
|
||||
|
||||
void force_push();
|
||||
|
||||
|
@ -101,26 +115,29 @@ namespace smt {
|
|||
m_fresh_eh = fresh_eh;
|
||||
}
|
||||
|
||||
unsigned add_expr(expr* e);
|
||||
void add_expr(expr* e, bool ensure_enode);
|
||||
|
||||
void register_final(user_propagator::final_eh_t& final_eh) { m_final_eh = final_eh; }
|
||||
void register_fixed(user_propagator::fixed_eh_t& fixed_eh) { m_fixed_eh = fixed_eh; }
|
||||
void register_eq(user_propagator::eq_eh_t& eq_eh) { m_eq_eh = eq_eh; }
|
||||
void register_diseq(user_propagator::eq_eh_t& diseq_eh) { m_diseq_eh = diseq_eh; }
|
||||
void register_created(user_propagator::created_eh_t& created_eh) { m_created_eh = created_eh; }
|
||||
void register_decide(user_propagator::decide_eh_t& decide_eh) { m_decide_eh = decide_eh; }
|
||||
|
||||
bool has_fixed() const { return (bool)m_fixed_eh; }
|
||||
|
||||
void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* lhs, unsigned const* rhs, expr* conseq) override;
|
||||
unsigned register_cb(expr* e) override;
|
||||
bool has_decide() const { return (bool)m_decide_eh; }
|
||||
|
||||
void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override;
|
||||
void register_cb(expr* e) override;
|
||||
|
||||
void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits);
|
||||
void decide(bool_var& var, bool& is_pos);
|
||||
|
||||
theory * mk_fresh(context * new_ctx) override;
|
||||
bool internalize_atom(app* atom, bool gate_ctx) override;
|
||||
bool internalize_term(app* term) override;
|
||||
void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, v1, v2); }
|
||||
void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, v1, v2); }
|
||||
void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); }
|
||||
void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); }
|
||||
bool use_diseqs() const override { return ((bool)m_diseq_eh); }
|
||||
bool build_models() const override { return false; }
|
||||
final_check_status final_check_eh() override;
|
||||
|
@ -133,7 +150,7 @@ namespace smt {
|
|||
void collect_statistics(::statistics & st) const override;
|
||||
model_value_proc * mk_value(enode * n, model_generator & mg) override { return nullptr; }
|
||||
void init_model(model_generator & m) override {}
|
||||
bool include_func_interp(func_decl* f) override { return true; }
|
||||
bool include_func_interp(func_decl* f) override { return false; }
|
||||
bool can_propagate() override;
|
||||
void propagate() override;
|
||||
void display(std::ostream& out) const override {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue