mirror of
https://github.com/Z3Prover/z3
synced 2025-08-19 01:32:17 +00:00
Merge branch 'master' into regex-develop
This commit is contained in:
commit
49b810e00f
108 changed files with 899 additions and 1457 deletions
|
@ -27,8 +27,9 @@ Revision History:
|
|||
#include "ast/macros/quasi_macros.h"
|
||||
#include "smt/asserted_formulas.h"
|
||||
|
||||
asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p):
|
||||
asserted_formulas::asserted_formulas(ast_manager & m, smt_params & sp, params_ref const& p):
|
||||
m(m),
|
||||
m_smt_params(sp),
|
||||
m_params(p),
|
||||
m_rewriter(m),
|
||||
m_substitution(m),
|
||||
|
@ -46,7 +47,6 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p):
|
|||
m_refine_inj_axiom(*this),
|
||||
m_max_bv_sharing_fn(*this),
|
||||
m_elim_term_ite(*this),
|
||||
m_pull_cheap_ite_trees(*this),
|
||||
m_pull_nested_quantifiers(*this),
|
||||
m_elim_bvs_from_quantifiers(*this),
|
||||
m_cheap_quant_fourier_motzkin(*this),
|
||||
|
@ -66,20 +66,20 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p):
|
|||
}
|
||||
|
||||
void asserted_formulas::setup() {
|
||||
switch (m_params.m_lift_ite) {
|
||||
switch (m_smt_params.m_lift_ite) {
|
||||
case LI_FULL:
|
||||
m_params.m_ng_lift_ite = LI_NONE;
|
||||
m_smt_params.m_ng_lift_ite = LI_NONE;
|
||||
break;
|
||||
case LI_CONSERVATIVE:
|
||||
if (m_params.m_ng_lift_ite == LI_CONSERVATIVE)
|
||||
m_params.m_ng_lift_ite = LI_NONE;
|
||||
if (m_smt_params.m_ng_lift_ite == LI_CONSERVATIVE)
|
||||
m_smt_params.m_ng_lift_ite = LI_NONE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_params.m_relevancy_lvl == 0)
|
||||
m_params.m_relevancy_lemma = false;
|
||||
if (m_smt_params.m_relevancy_lvl == 0)
|
||||
m_smt_params.m_relevancy_lemma = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,21 +118,24 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_ex
|
|||
}
|
||||
}
|
||||
|
||||
void asserted_formulas::updt_params(params_ref const& p) {
|
||||
m_params.append(p);
|
||||
}
|
||||
|
||||
void asserted_formulas::set_eliminate_and(bool flag) {
|
||||
if (flag == m_elim_and) return;
|
||||
m_elim_and = flag;
|
||||
params_ref p;
|
||||
p.set_bool("pull_cheap_ite", false);
|
||||
p.set_bool("elim_and", flag);
|
||||
p.set_bool("arith_ineq_lhs", true);
|
||||
p.set_bool("sort_sums", true);
|
||||
p.set_bool("rewrite_patterns", true);
|
||||
p.set_bool("eq2ineq", m_params.m_arith_eq2ineq);
|
||||
p.set_bool("gcd_rounding", true);
|
||||
p.set_bool("expand_select_store", true);
|
||||
p.set_bool("bv_sort_ac", true);
|
||||
p.set_bool("som", true);
|
||||
m_rewriter.updt_params(p);
|
||||
if (m_smt_params.m_pull_cheap_ite) m_params.set_bool("pull_cheap_ite", true);
|
||||
m_params.set_bool("elim_and", flag);
|
||||
m_params.set_bool("arith_ineq_lhs", true);
|
||||
m_params.set_bool("sort_sums", true);
|
||||
m_params.set_bool("rewrite_patterns", true);
|
||||
m_params.set_bool("eq2ineq", m_smt_params.m_arith_eq2ineq);
|
||||
m_params.set_bool("gcd_rounding", true);
|
||||
m_params.set_bool("expand_select_store", true);
|
||||
m_params.set_bool("bv_sort_ac", true);
|
||||
m_params.set_bool("som", true);
|
||||
m_rewriter.updt_params(m_params);
|
||||
flush_cache();
|
||||
}
|
||||
|
||||
|
@ -144,7 +147,7 @@ void asserted_formulas::assert_expr(expr * e, proof * _in_pr) {
|
|||
if (inconsistent())
|
||||
return;
|
||||
|
||||
if (m_params.m_preprocess) {
|
||||
if (m_smt_params.m_preprocess) {
|
||||
TRACE("assert_expr_bug", tout << r << "\n";);
|
||||
set_eliminate_and(false); // do not eliminate and before nnf.
|
||||
m_rewriter(e, r, pr);
|
||||
|
@ -227,7 +230,7 @@ void asserted_formulas::reduce() {
|
|||
return;
|
||||
if (m_qhead == m_formulas.size())
|
||||
return;
|
||||
if (!m_params.m_preprocess)
|
||||
if (!m_smt_params.m_preprocess)
|
||||
return;
|
||||
if (m_macro_manager.has_macros())
|
||||
invoke(m_find_macros);
|
||||
|
@ -241,7 +244,6 @@ void asserted_formulas::reduce() {
|
|||
if (!invoke(m_nnf_cnf)) return;
|
||||
set_eliminate_and(true);
|
||||
if (!invoke(m_reduce_asserted_formulas)) return;
|
||||
if (!invoke(m_pull_cheap_ite_trees)) return;
|
||||
if (!invoke(m_pull_nested_quantifiers)) return;
|
||||
if (!invoke(m_lift_ite)) return;
|
||||
if (!invoke(m_ng_lift_ite)) return;
|
||||
|
|
|
@ -26,7 +26,6 @@ Revision History:
|
|||
#include "ast/rewriter/bit2int.h"
|
||||
#include "ast/rewriter/maximize_ac_sharing.h"
|
||||
#include "ast/rewriter/distribute_forall.h"
|
||||
#include "ast/rewriter/pull_ite_tree.h"
|
||||
#include "ast/rewriter/push_app_ite.h"
|
||||
#include "ast/rewriter/inj_axiom.h"
|
||||
#include "ast/rewriter/bv_elim.h"
|
||||
|
@ -44,7 +43,8 @@ Revision History:
|
|||
class asserted_formulas {
|
||||
|
||||
ast_manager & m;
|
||||
smt_params & m_params;
|
||||
smt_params & m_smt_params;
|
||||
params_ref m_params;
|
||||
th_rewriter m_rewriter;
|
||||
expr_substitution m_substitution;
|
||||
scoped_expr_substitution m_scoped_substitution;
|
||||
|
@ -89,7 +89,7 @@ class asserted_formulas {
|
|||
public:
|
||||
find_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-macros") {}
|
||||
void operator()() override { af.find_macros_core(); }
|
||||
bool should_apply() const override { return af.m_params.m_macro_finder && af.has_quantifiers(); }
|
||||
bool should_apply() const override { return af.m_smt_params.m_macro_finder && af.has_quantifiers(); }
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); }
|
||||
};
|
||||
|
||||
|
@ -97,7 +97,7 @@ class asserted_formulas {
|
|||
public:
|
||||
apply_quasi_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-quasi-macros") {}
|
||||
void operator()() override { af.apply_quasi_macros(); }
|
||||
bool should_apply() const override { return af.m_params.m_quasi_macros && af.has_quantifiers(); }
|
||||
bool should_apply() const override { return af.m_smt_params.m_quasi_macros && af.has_quantifiers(); }
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); }
|
||||
};
|
||||
|
||||
|
@ -105,7 +105,7 @@ class asserted_formulas {
|
|||
public:
|
||||
nnf_cnf_fn(asserted_formulas& af): simplify_fmls(af, "nnf-cnf") {}
|
||||
void operator()() override { af.nnf_cnf(); }
|
||||
bool should_apply() const override { return af.m_params.m_nnf_cnf || (af.m_params.m_mbqi && af.has_quantifiers()); }
|
||||
bool should_apply() const override { return af.m_smt_params.m_nnf_cnf || (af.m_smt_params.m_mbqi && af.has_quantifiers()); }
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); }
|
||||
};
|
||||
|
||||
|
@ -113,7 +113,7 @@ class asserted_formulas {
|
|||
public:
|
||||
propagate_values_fn(asserted_formulas& af): simplify_fmls(af, "propagate-values") {}
|
||||
void operator()() override { af.propagate_values(); }
|
||||
bool should_apply() const override { return af.m_params.m_propagate_values; }
|
||||
bool should_apply() const override { return af.m_smt_params.m_propagate_values; }
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); }
|
||||
};
|
||||
|
||||
|
@ -122,30 +122,30 @@ class asserted_formulas {
|
|||
public:
|
||||
distribute_forall_fn(asserted_formulas& af): simplify_fmls(af, "distribute-forall"), m_functor(af.m) {}
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { m_functor(j.get_fml(), n); }
|
||||
bool should_apply() const override { return af.m_params.m_distribute_forall && af.has_quantifiers(); }
|
||||
bool should_apply() const override { return af.m_smt_params.m_distribute_forall && af.has_quantifiers(); }
|
||||
void post_op() override { af.reduce_and_solve(); TRACE("asserted_formulas", af.display(tout);); }
|
||||
};
|
||||
|
||||
class pattern_inference_fn : public simplify_fmls {
|
||||
pattern_inference_rw m_infer;
|
||||
public:
|
||||
pattern_inference_fn(asserted_formulas& af): simplify_fmls(af, "pattern-inference"), m_infer(af.m, af.m_params) {}
|
||||
pattern_inference_fn(asserted_formulas& af): simplify_fmls(af, "pattern-inference"), m_infer(af.m, af.m_smt_params) {}
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { m_infer(j.get_fml(), n, p); }
|
||||
bool should_apply() const override { return af.m_params.m_ematching && af.has_quantifiers(); }
|
||||
bool should_apply() const override { return af.m_smt_params.m_ematching && af.has_quantifiers(); }
|
||||
};
|
||||
|
||||
class refine_inj_axiom_fn : public simplify_fmls {
|
||||
public:
|
||||
refine_inj_axiom_fn(asserted_formulas& af): simplify_fmls(af, "refine-injectivity") {}
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override;
|
||||
bool should_apply() const override { return af.m_params.m_refine_inj_axiom && af.has_quantifiers(); }
|
||||
bool should_apply() const override { return af.m_smt_params.m_refine_inj_axiom && af.has_quantifiers(); }
|
||||
};
|
||||
|
||||
class max_bv_sharing_fn : public simplify_fmls {
|
||||
public:
|
||||
max_bv_sharing_fn(asserted_formulas& af): simplify_fmls(af, "maximizing-bv-sharing") {}
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { af.m_bv_sharing(j.get_fml(), n, p); }
|
||||
bool should_apply() const override { return af.m_params.m_max_bv_sharing; }
|
||||
bool should_apply() const override { return af.m_smt_params.m_max_bv_sharing; }
|
||||
void post_op() override { af.m_reduce_asserted_formulas(); }
|
||||
};
|
||||
|
||||
|
@ -154,7 +154,7 @@ class asserted_formulas {
|
|||
public:
|
||||
elim_term_ite_fn(asserted_formulas& af): simplify_fmls(af, "elim-term-ite"), m_elim(af.m, af.m_defined_names) {}
|
||||
void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { m_elim(j.get_fml(), n, p); }
|
||||
bool should_apply() const override { return af.m_params.m_eliminate_term_ite && af.m_params.m_lift_ite != LI_FULL; }
|
||||
bool should_apply() const override { return af.m_smt_params.m_eliminate_term_ite && af.m_smt_params.m_lift_ite != LI_FULL; }
|
||||
void post_op() override { af.m_formulas.append(m_elim.new_defs()); af.reduce_and_solve(); m_elim.reset(); }
|
||||
};
|
||||
|
||||
|
@ -172,13 +172,12 @@ class asserted_formulas {
|
|||
|
||||
#define MK_SIMPLIFIERF(NAME, FUNCTOR, MSG, APP, REDUCE) MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, (af.m), REDUCE)
|
||||
|
||||
MK_SIMPLIFIERF(pull_cheap_ite_trees, pull_cheap_ite_tree_rw, "pull-cheap-ite-trees", af.m_params.m_pull_cheap_ite_trees, false);
|
||||
MK_SIMPLIFIERF(pull_nested_quantifiers, pull_nested_quant, "pull-nested-quantifiers", af.m_params.m_pull_nested_quantifiers && af.has_quantifiers(), false);
|
||||
MK_SIMPLIFIERF(cheap_quant_fourier_motzkin, elim_bounds_rw, "cheap-fourier-motzkin", af.m_params.m_eliminate_bounds && af.has_quantifiers(), true);
|
||||
MK_SIMPLIFIERF(elim_bvs_from_quantifiers, bv_elim_rw, "eliminate-bit-vectors-from-quantifiers", af.m_params.m_bb_quantifiers, true);
|
||||
MK_SIMPLIFIERF(apply_bit2int, bit2int, "propagate-bit-vector-over-integers", af.m_params.m_simplify_bit2int, true);
|
||||
MK_SIMPLIFIERA(lift_ite, push_app_ite_rw, "lift-ite", af.m_params.m_lift_ite != LI_NONE, (af.m, af.m_params.m_lift_ite == LI_CONSERVATIVE), true);
|
||||
MK_SIMPLIFIERA(ng_lift_ite, ng_push_app_ite_rw, "lift-ite", af.m_params.m_ng_lift_ite != LI_NONE, (af.m, af.m_params.m_ng_lift_ite == LI_CONSERVATIVE), true);
|
||||
MK_SIMPLIFIERF(pull_nested_quantifiers, pull_nested_quant, "pull-nested-quantifiers", af.m_smt_params.m_pull_nested_quantifiers && af.has_quantifiers(), false);
|
||||
MK_SIMPLIFIERF(cheap_quant_fourier_motzkin, elim_bounds_rw, "cheap-fourier-motzkin", af.m_smt_params.m_eliminate_bounds && af.has_quantifiers(), true);
|
||||
MK_SIMPLIFIERF(elim_bvs_from_quantifiers, bv_elim_rw, "eliminate-bit-vectors-from-quantifiers", af.m_smt_params.m_bb_quantifiers, true);
|
||||
MK_SIMPLIFIERF(apply_bit2int, bit2int, "propagate-bit-vector-over-integers", af.m_smt_params.m_simplify_bit2int, true);
|
||||
MK_SIMPLIFIERA(lift_ite, push_app_ite_rw, "lift-ite", af.m_smt_params.m_lift_ite != LI_NONE, (af.m, af.m_smt_params.m_lift_ite == LI_CONSERVATIVE), true);
|
||||
MK_SIMPLIFIERA(ng_lift_ite, ng_push_app_ite_rw, "lift-ite", af.m_smt_params.m_ng_lift_ite != LI_NONE, (af.m, af.m_smt_params.m_ng_lift_ite == LI_CONSERVATIVE), true);
|
||||
|
||||
|
||||
reduce_asserted_formulas_fn m_reduce_asserted_formulas;
|
||||
|
@ -187,7 +186,6 @@ class asserted_formulas {
|
|||
refine_inj_axiom_fn m_refine_inj_axiom;
|
||||
max_bv_sharing_fn m_max_bv_sharing_fn;
|
||||
elim_term_ite_fn m_elim_term_ite;
|
||||
pull_cheap_ite_trees m_pull_cheap_ite_trees;
|
||||
pull_nested_quantifiers m_pull_nested_quantifiers;
|
||||
elim_bvs_from_quantifiers m_elim_bvs_from_quantifiers;
|
||||
cheap_quant_fourier_motzkin m_cheap_quant_fourier_motzkin;
|
||||
|
@ -219,14 +217,14 @@ class asserted_formulas {
|
|||
bool is_gt(expr* lhs, expr* rhs);
|
||||
void compute_depth(expr* e);
|
||||
unsigned depth(expr* e) { return m_expr2depth[e]; }
|
||||
bool pull_cheap_ite_trees();
|
||||
|
||||
void init(unsigned num_formulas, expr * const * formulas, proof * const * prs);
|
||||
|
||||
public:
|
||||
asserted_formulas(ast_manager & m, smt_params & p);
|
||||
asserted_formulas(ast_manager & m, smt_params & smtp, params_ref const& p);
|
||||
~asserted_formulas();
|
||||
|
||||
void updt_params(params_ref const& p);
|
||||
bool has_quantifiers() const { return m_has_quantifiers; }
|
||||
void setup();
|
||||
void assert_expr(expr * e, proof * in_pr);
|
||||
|
|
|
@ -3924,7 +3924,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
virtual bool check_missing_instances() {
|
||||
bool check_missing_instances() override {
|
||||
TRACE("missing_instance", tout << "checking for missing instances...\n";);
|
||||
flet<bool> l(m_check_missing_instances, true);
|
||||
rematch(false);
|
||||
|
|
|
@ -41,7 +41,7 @@ void preprocessor_params::display(std::ostream & out) const {
|
|||
|
||||
DISPLAY_PARAM(m_lift_ite);
|
||||
DISPLAY_PARAM(m_ng_lift_ite);
|
||||
DISPLAY_PARAM(m_pull_cheap_ite_trees);
|
||||
DISPLAY_PARAM(m_pull_cheap_ite);
|
||||
DISPLAY_PARAM(m_pull_nested_quantifiers);
|
||||
DISPLAY_PARAM(m_eliminate_term_ite);
|
||||
DISPLAY_PARAM(m_macro_finder);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct preprocessor_params : public pattern_inference_params,
|
|||
public bit_blaster_params {
|
||||
lift_ite_kind m_lift_ite;
|
||||
lift_ite_kind m_ng_lift_ite; // lift ite for non ground terms
|
||||
bool m_pull_cheap_ite_trees;
|
||||
bool m_pull_cheap_ite;
|
||||
bool m_pull_nested_quantifiers;
|
||||
bool m_eliminate_term_ite;
|
||||
bool m_macro_finder;
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
preprocessor_params(params_ref const & p = params_ref()):
|
||||
m_lift_ite(LI_NONE),
|
||||
m_ng_lift_ite(LI_NONE),
|
||||
m_pull_cheap_ite_trees(false),
|
||||
m_pull_cheap_ite(false),
|
||||
m_pull_nested_quantifiers(false),
|
||||
m_eliminate_term_ite(false),
|
||||
m_macro_finder(false),
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace smt {
|
|||
m_fparams(p),
|
||||
m_params(_p),
|
||||
m_setup(*this, p),
|
||||
m_asserted_formulas(m, p),
|
||||
m_asserted_formulas(m, p, _p),
|
||||
m_qmanager(alloc(quantifier_manager, *this, p, _p)),
|
||||
m_model_generator(alloc(model_generator, m)),
|
||||
m_relevancy_propagator(mk_relevancy_propagator(*this)),
|
||||
|
@ -132,6 +132,10 @@ namespace smt {
|
|||
return !m_manager.limit().inc();
|
||||
}
|
||||
|
||||
void context::updt_params(params_ref const& p) {
|
||||
m_params.append(p);
|
||||
m_asserted_formulas.updt_params(p);
|
||||
}
|
||||
|
||||
void context::copy(context& src_ctx, context& dst_ctx) {
|
||||
ast_manager& dst_m = dst_ctx.get_manager();
|
||||
|
@ -3143,6 +3147,7 @@ namespace smt {
|
|||
push_scope();
|
||||
for (unsigned i = 0; i < num_assumptions; i++) {
|
||||
expr * curr_assumption = assumptions[i];
|
||||
if (m_manager.is_true(curr_assumption)) continue;
|
||||
SASSERT(is_valid_assumption(m_manager, curr_assumption));
|
||||
proof * pr = m_manager.mk_asserted(curr_assumption);
|
||||
internalize_assertion(curr_assumption, pr, 0);
|
||||
|
@ -4313,9 +4318,7 @@ namespace smt {
|
|||
if (m_fparams.m_model_compact)
|
||||
m_proto_model->compress();
|
||||
TRACE("mbqi_bug", tout << "after cleanup:\n"; model_pp(tout, *m_proto_model););
|
||||
}
|
||||
else {
|
||||
|
||||
IF_VERBOSE(11, model_pp(verbose_stream(), *m_proto_model););
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -262,6 +262,8 @@ namespace smt {
|
|||
return m_params;
|
||||
}
|
||||
|
||||
void updt_params(params_ref const& p);
|
||||
|
||||
bool get_cancel_flag();
|
||||
|
||||
region & get_region() {
|
||||
|
@ -1387,7 +1389,7 @@ namespace smt {
|
|||
void flush();
|
||||
config_mode get_config_mode(bool use_static_features) const;
|
||||
virtual void setup_context(bool use_static_features);
|
||||
void setup_components(void);
|
||||
void setup_components();
|
||||
void pop_to_base_lvl();
|
||||
void pop_to_search_lvl();
|
||||
#ifdef Z3DEBUG
|
||||
|
|
|
@ -123,7 +123,6 @@ namespace smt {
|
|||
return m_kernel.preferred_sat(asms, cores);
|
||||
}
|
||||
|
||||
|
||||
lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
return m_kernel.find_mutexes(vars, mutexes);
|
||||
}
|
||||
|
@ -196,9 +195,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
// We don't need params2smt_params anymore. smt_params has support for reading params_ref.
|
||||
// The update is performed at smt_kernel "users".
|
||||
// params2smt_params(p, fparams());
|
||||
m_kernel.updt_params(p);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -218,7 +215,6 @@ namespace smt {
|
|||
imp::copy(*src.m_imp, *dst.m_imp);
|
||||
}
|
||||
|
||||
|
||||
bool kernel::set_logic(symbol logic) {
|
||||
return m_imp->set_logic(logic);
|
||||
}
|
||||
|
@ -263,9 +259,9 @@ namespace smt {
|
|||
}
|
||||
|
||||
void kernel::reset() {
|
||||
ast_manager & _m = m();
|
||||
ast_manager & _m = m();
|
||||
smt_params & fps = m_imp->fparams();
|
||||
params_ref ps = m_imp->params();
|
||||
params_ref ps = m_imp->params();
|
||||
#pragma omp critical (smt_kernel)
|
||||
{
|
||||
m_imp->~imp();
|
||||
|
|
|
@ -914,6 +914,7 @@ namespace smt {
|
|||
func_interp * fi = m_model->get_func_interp(f);
|
||||
if (fi == nullptr) {
|
||||
fi = alloc(func_interp, m, f->get_arity());
|
||||
TRACE("model_finder", tout << "register " << f->get_name() << "\n";);
|
||||
m_model->register_decl(f, fi);
|
||||
SASSERT(fi->is_partial());
|
||||
}
|
||||
|
@ -1784,13 +1785,8 @@ namespace smt {
|
|||
return !m_cond_macros.empty();
|
||||
}
|
||||
|
||||
macro_iterator begin_macros() const {
|
||||
return m_cond_macros.begin();
|
||||
}
|
||||
ptr_vector<cond_macro> const& macros() const { return m_cond_macros; }
|
||||
|
||||
macro_iterator end_macros() const {
|
||||
return m_cond_macros.end();
|
||||
}
|
||||
|
||||
void set_the_one(func_decl * m) {
|
||||
m_the_one = m;
|
||||
|
@ -2445,6 +2441,7 @@ namespace smt {
|
|||
m_model->register_decl(f, fi);
|
||||
}
|
||||
fi->set_else(f_else);
|
||||
TRACE("model_finder", tout << f->get_name() << " " << mk_pp(f_else, m_manager) << "\n";);
|
||||
}
|
||||
|
||||
virtual bool process(ptr_vector<quantifier> const & qs, ptr_vector<quantifier> & new_qs, ptr_vector<quantifier> & residue) = 0;
|
||||
|
@ -2499,10 +2496,7 @@ namespace smt {
|
|||
|
||||
bool process(quantifier * q, ptr_vector<quantifier> const & qs) {
|
||||
quantifier_info * qi = get_qinfo(q);
|
||||
quantifier_info::macro_iterator it = qi->begin_macros();
|
||||
quantifier_info::macro_iterator end = qi->end_macros();
|
||||
for (; it != end; ++it) {
|
||||
cond_macro * m = *it;
|
||||
for (cond_macro* m : qi->macros()) {
|
||||
if (!m->satisfy_atom())
|
||||
continue;
|
||||
func_decl * f = m->get_f();
|
||||
|
@ -2548,10 +2542,10 @@ namespace smt {
|
|||
where Q_{f_i} is the set of quantifiers that contain the function f_i.
|
||||
Let f_i = def_i be macros (in this solver conditions are ignored).
|
||||
Let Q_{f_i = def_i} be the set of quantifiers where f_i = def_i is a macro.
|
||||
Then, the set Q can be satisfied using f_1 = def_1 ... f_n = d_n
|
||||
Then, the set Q can be satisfied using f_1 = def_1 ... f_n = def_n
|
||||
when
|
||||
|
||||
Q_{f_1} union ... union Q_{f_n} = Q_{f_1 = def_1} ... Q_{f_n = d_n} (*)
|
||||
Q_{f_1} union ... union Q_{f_n} = Q_{f_1 = def_1} ... Q_{f_n = def_n} (*)
|
||||
|
||||
So, given a set of macros f_1 = def_1, ..., f_n = d_n, it is very easy to check
|
||||
whether they can be used to satisfy all quantifiers that use f_1, ..., f_n in
|
||||
|
@ -2630,12 +2624,7 @@ namespace smt {
|
|||
s->insert(q);
|
||||
}
|
||||
|
||||
quantifier_set * get_q_f(func_decl * f) {
|
||||
quantifier_set * s = nullptr;
|
||||
m_q_f.find(f, s);
|
||||
SASSERT(s != 0);
|
||||
return s;
|
||||
}
|
||||
quantifier_set * get_q_f(func_decl * f) { return m_q_f[f]; }
|
||||
|
||||
quantifier_set * get_q_f_def(func_decl * f, expr * def) {
|
||||
quantifier_set * s = nullptr;
|
||||
|
@ -2644,12 +2633,7 @@ namespace smt {
|
|||
return s;
|
||||
}
|
||||
|
||||
expr_set * get_f_defs(func_decl * f) {
|
||||
expr_set * s = nullptr;
|
||||
m_f2defs.find(f, s);
|
||||
SASSERT(s != 0);
|
||||
return s;
|
||||
}
|
||||
expr_set * get_f_defs(func_decl * f) { return m_f2defs[f]; }
|
||||
|
||||
void reset_q_fs() {
|
||||
std::for_each(m_qsets.begin(), m_qsets.end(), delete_proc<quantifier_set>());
|
||||
|
@ -2666,10 +2650,7 @@ namespace smt {
|
|||
|
||||
bool is_candidate(quantifier * q) const {
|
||||
quantifier_info * qi = get_qinfo(q);
|
||||
quantifier_info::macro_iterator it = qi->begin_macros();
|
||||
quantifier_info::macro_iterator end = qi->end_macros();
|
||||
for (; it != end; ++it) {
|
||||
cond_macro * m = *it;
|
||||
for (cond_macro * m : qi->macros()) {
|
||||
if (m->satisfy_atom() && !m_forbidden.contains(m->get_f()))
|
||||
return true;
|
||||
}
|
||||
|
@ -2712,10 +2693,7 @@ namespace smt {
|
|||
if (!m_forbidden.contains(f))
|
||||
insert_q_f(q, f);
|
||||
}
|
||||
quantifier_info::macro_iterator it3 = qi->begin_macros();
|
||||
quantifier_info::macro_iterator end3 = qi->end_macros();
|
||||
for (; it3 != end3; ++it3) {
|
||||
cond_macro * m = *it3;
|
||||
for (cond_macro * m : qi->macros()) {
|
||||
if (m->satisfy_atom() && !m_forbidden.contains(m->get_f())) {
|
||||
insert_q_f_def(q, m->get_f(), m->get_def());
|
||||
m_candidates.insert(m->get_f());
|
||||
|
@ -2842,11 +2820,7 @@ namespace smt {
|
|||
void get_candidates_from_residue(func_decl_set & candidates) {
|
||||
for (quantifier * q : m_residue) {
|
||||
quantifier_info * qi = get_qinfo(q);
|
||||
|
||||
quantifier_info::macro_iterator it2 = qi->begin_macros();
|
||||
quantifier_info::macro_iterator end2 = qi->end_macros();
|
||||
for (; it2 != end2; ++it2) {
|
||||
cond_macro * m = *it2;
|
||||
for (cond_macro * m : qi->macros()) {
|
||||
func_decl * f = m->get_f();
|
||||
if (m->satisfy_atom() && !m_forbidden.contains(f) && !m_fs.contains(f)) {
|
||||
candidates.insert(f);
|
||||
|
@ -2875,6 +2849,7 @@ namespace smt {
|
|||
|
||||
m_satisfied.push_scope();
|
||||
m_residue.push_scope();
|
||||
TRACE("model_finder", tout << f->get_name() << " " << mk_pp(def, m_manager) << "\n";);
|
||||
m_fs.insert(f, def);
|
||||
|
||||
if (update_satisfied_residue(f, def)) {
|
||||
|
@ -2889,12 +2864,56 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief check if satisfied subset introduces a cyclic dependency.
|
||||
|
||||
f_1 = def_1(f_2), ..., f_n = def_n(f_1)
|
||||
*/
|
||||
|
||||
expr_mark m_visited;
|
||||
obj_hashtable<func_decl> m_acyclic;
|
||||
bool is_cyclic() {
|
||||
m_acyclic.reset();
|
||||
while (true) {
|
||||
unsigned sz = m_acyclic.size();
|
||||
if (sz == m_fs.size()) return false; // there are no cyclic dependencies
|
||||
for (auto const& kv : m_fs) {
|
||||
func_decl * f = kv.m_key;
|
||||
if (m_acyclic.contains(f)) continue;
|
||||
if (is_acyclic(kv.m_value))
|
||||
m_acyclic.insert(f);
|
||||
}
|
||||
if (sz == m_acyclic.size()) return true; // no progress, so dependency cycle found.
|
||||
}
|
||||
}
|
||||
|
||||
struct occurs {};
|
||||
struct occurs_check {
|
||||
hint_solver& m_cls;
|
||||
occurs_check(hint_solver& hs): m_cls(hs) {}
|
||||
void operator()(app* n) { if (m_cls.m_fs.contains(n->get_decl()) && !m_cls.m_acyclic.contains(n->get_decl())) throw occurs(); }
|
||||
void operator()(var* n) {}
|
||||
void operator()(quantifier* n) {}
|
||||
};
|
||||
bool is_acyclic(expr* def) {
|
||||
m_visited.reset();
|
||||
occurs_check oc(*this);
|
||||
try {
|
||||
for_each_expr(oc, m_visited, def);
|
||||
}
|
||||
catch (occurs) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to reduce m_residue (if not empty) by selecting a function f
|
||||
that is a macro in the residue.
|
||||
*/
|
||||
void greedy(unsigned depth) {
|
||||
if (m_residue.empty()) {
|
||||
if (is_cyclic()) return;
|
||||
TRACE("model_finder_hint",
|
||||
tout << "found subset that is satisfied by macros\n";
|
||||
display_search_state(tout););
|
||||
|
@ -3007,11 +3026,11 @@ namespace smt {
|
|||
qi_params const * m_qi_params;
|
||||
|
||||
bool add_macro(func_decl * f, expr * f_else) {
|
||||
TRACE("non_auf_macro_solver", tout << "trying to add macro for " << f->get_name() << "\n" << mk_pp(f_else, m_manager) << "\n";);
|
||||
TRACE("model_finder", tout << "trying to add macro for " << f->get_name() << "\n" << mk_pp(f_else, m_manager) << "\n";);
|
||||
func_decl_set * s = m_dependencies.mk_func_decl_set();
|
||||
m_dependencies.collect_ng_func_decls(f_else, s);
|
||||
if (!m_dependencies.insert(f, s)) {
|
||||
TRACE("non_auf_macro_solver", tout << "failed to add macro\n";);
|
||||
TRACE("model_finder", tout << "failed to add macro\n";);
|
||||
return false; // cyclic dependency
|
||||
}
|
||||
set_else_interp(f, f_else);
|
||||
|
@ -3033,10 +3052,7 @@ namespace smt {
|
|||
cond_macro * get_macro_for(func_decl * f, quantifier * q) {
|
||||
cond_macro * r = nullptr;
|
||||
quantifier_info * qi = get_qinfo(q);
|
||||
quantifier_info::macro_iterator it = qi->begin_macros();
|
||||
quantifier_info::macro_iterator end = qi->end_macros();
|
||||
for (; it != end; ++it) {
|
||||
cond_macro * m = *it;
|
||||
for (cond_macro * m : qi->macros()) {
|
||||
if (m->get_f() == f && !m->is_hint() && is_better_macro(m, r))
|
||||
r = m;
|
||||
}
|
||||
|
@ -3048,13 +3064,10 @@ namespace smt {
|
|||
void collect_candidates(ptr_vector<quantifier> const & qs, obj_map<func_decl, mq_pair> & full_macros, func_decl_set & cond_macros) {
|
||||
for (quantifier * q : qs) {
|
||||
quantifier_info * qi = get_qinfo(q);
|
||||
quantifier_info::macro_iterator it2 = qi->begin_macros();
|
||||
quantifier_info::macro_iterator end2 = qi->end_macros();
|
||||
for (; it2 != end2; ++it2) {
|
||||
cond_macro * m = *it2;
|
||||
for (cond_macro * m : qi->macros()) {
|
||||
if (!m->is_hint()) {
|
||||
func_decl * f = m->get_f();
|
||||
TRACE("non_auf_macro_solver", tout << "considering macro for: " << f->get_name() << "\n";
|
||||
TRACE("model_finder", tout << "considering macro for: " << f->get_name() << "\n";
|
||||
m->display(tout); tout << "\n";);
|
||||
SASSERT(m_qi_params != 0);
|
||||
if (m->is_unconditional() && (!qi->is_auf() || m->get_weight() >= m_qi_params->m_mbqi_force_template)) {
|
||||
|
|
|
@ -527,7 +527,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool check_relevancy_app(app * n) const {
|
||||
bool check_relevancy_app(app * n) const {
|
||||
SASSERT(is_relevant(n));
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
|
@ -537,7 +537,7 @@ namespace smt {
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool check_relevancy_or(app * n, bool root) const {
|
||||
bool check_relevancy_or(app * n, bool root) const override {
|
||||
lbool val = root ? l_true : m_context.find_assignment(n);
|
||||
if (val == l_false)
|
||||
return check_relevancy_app(n);
|
||||
|
@ -600,7 +600,7 @@ namespace smt {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool check_relevancy(expr_ref_vector const & v) const {
|
||||
bool check_relevancy(expr_ref_vector const & v) const override {
|
||||
SASSERT(!can_propagate());
|
||||
ast_manager & m = get_manager();
|
||||
unsigned sz = v.size();
|
||||
|
|
|
@ -507,7 +507,7 @@ namespace smt {
|
|||
m_params.m_nnf_cnf = false;
|
||||
if (st.m_max_ite_tree_depth > 50) {
|
||||
m_params.m_arith_eq2ineq = false;
|
||||
m_params.m_pull_cheap_ite_trees = true;
|
||||
m_params.m_pull_cheap_ite = true;
|
||||
m_params.m_arith_propagate_eqs = true;
|
||||
m_params.m_relevancy_lvl = 2;
|
||||
m_params.m_relevancy_lemma = false;
|
||||
|
|
|
@ -469,7 +469,8 @@ namespace smt {
|
|||
if (negated) l_conseq.neg();
|
||||
|
||||
TRACE("arith_axiom", tout << mk_pp(ante, m) << "\n" << mk_pp(conseq, m) << "\n";
|
||||
tout << s_ante << "\n" << s_conseq << "\n";);
|
||||
tout << s_ante << "\n" << s_conseq << "\n";
|
||||
tout << l_ante << "\n" << l_conseq << "\n";);
|
||||
|
||||
// literal lits[2] = {l_ante, l_conseq};
|
||||
mk_clause(l_ante, l_conseq, 0, nullptr);
|
||||
|
@ -589,13 +590,13 @@ namespace smt {
|
|||
}
|
||||
|
||||
//
|
||||
// create the term: s := to_real(to_int(x)) - x
|
||||
// create the term: s := x - to_real(to_int(x))
|
||||
// add the bounds 0 <= s < 1
|
||||
//
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::mk_to_int_axiom(app * n) {
|
||||
SASSERT(m_util.is_to_int(n));
|
||||
ast_manager & m = get_manager();
|
||||
ast_manager & m = get_manager();
|
||||
expr* x = n->get_arg(0);
|
||||
|
||||
// to_int (to_real x) = x
|
||||
|
@ -603,11 +604,15 @@ namespace smt {
|
|||
mk_axiom(m.mk_false(), m.mk_eq(to_app(x)->get_arg(0), n));
|
||||
return;
|
||||
}
|
||||
expr* to_r = m_util.mk_to_real(n);
|
||||
expr_ref lo(m_util.mk_le(to_r, x), m);
|
||||
expr_ref hi(m_util.mk_lt(x, m_util.mk_add(to_r, m_util.mk_numeral(rational(1), false))), m);
|
||||
mk_axiom(m.mk_false(), lo);
|
||||
mk_axiom(m.mk_false(), hi);
|
||||
expr_ref to_r(m_util.mk_to_real(n), m);
|
||||
expr_ref diff(m_util.mk_add(x, m_util.mk_mul(m_util.mk_real(-1), to_r)), m);
|
||||
|
||||
expr_ref lo(m_util.mk_ge(diff, m_util.mk_real(0)), m);
|
||||
expr_ref hi(m_util.mk_ge(diff, m_util.mk_real(1)), m);
|
||||
hi = m.mk_not(hi);
|
||||
|
||||
mk_axiom(m.mk_false(), lo, false);
|
||||
mk_axiom(m.mk_false(), hi, false);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
|
@ -1202,7 +1207,7 @@ namespace smt {
|
|||
|
||||
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";);
|
||||
TRACE("arith_internalize", tout << "internalizing atom:\n" << mk_pp(n, this->get_manager()) << "\n";);
|
||||
context & ctx = get_context();
|
||||
SASSERT(m_util.is_le(n) || m_util.is_ge(n) || m_util.is_is_int(n));
|
||||
SASSERT(!ctx.b_internalized(n));
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace smt {
|
|||
func_decl * upd = n->get_decl();
|
||||
func_decl * acc = to_func_decl(upd->get_parameter(0).get_ast());
|
||||
func_decl * con = m_util.get_accessor_constructor(acc);
|
||||
func_decl * rec = m_util.get_constructor_recognizer(con);
|
||||
func_decl * rec = m_util.get_constructor_is(con);
|
||||
ptr_vector<func_decl> const & accessors = *m_util.get_constructor_accessors(con);
|
||||
app_ref rec_app(m.mk_app(rec, arg1), m);
|
||||
ctx.internalize(rec_app, false);
|
||||
|
@ -710,7 +710,7 @@ namespace smt {
|
|||
literal consequent;
|
||||
if (!r) {
|
||||
ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(dt);
|
||||
func_decl * rec = m_util.get_constructor_recognizer(constructors[unassigned_idx]);
|
||||
func_decl * rec = m_util.get_constructor_is(constructors[unassigned_idx]);
|
||||
app * rec_app = get_manager().mk_app(rec, n->get_owner());
|
||||
ctx.internalize(rec_app, false);
|
||||
consequent = literal(ctx.get_bool_var(rec_app));
|
||||
|
@ -751,12 +751,12 @@ namespace smt {
|
|||
m_stats.m_splits++;
|
||||
|
||||
if (d->m_recognizers.empty()) {
|
||||
r = m_util.get_constructor_recognizer(non_rec_c);
|
||||
r = m_util.get_constructor_is(non_rec_c);
|
||||
}
|
||||
else {
|
||||
enode * recognizer = d->m_recognizers[non_rec_idx];
|
||||
if (recognizer == nullptr) {
|
||||
r = m_util.get_constructor_recognizer(non_rec_c);
|
||||
r = m_util.get_constructor_is(non_rec_c);
|
||||
}
|
||||
else if (!ctx.is_relevant(recognizer)) {
|
||||
ctx.mark_as_relevant(recognizer);
|
||||
|
@ -776,7 +776,7 @@ namespace smt {
|
|||
if (curr == nullptr) {
|
||||
ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s);
|
||||
// found empty slot...
|
||||
r = m_util.get_constructor_recognizer(constructors[idx]);
|
||||
r = m_util.get_constructor_is(constructors[idx]);
|
||||
break;
|
||||
}
|
||||
else if (!ctx.is_relevant(curr)) {
|
||||
|
|
|
@ -2346,28 +2346,31 @@ bool theory_seq::check_int_string() {
|
|||
bool change = false;
|
||||
for (unsigned i = 0; i < m_int_string.size(); ++i) {
|
||||
expr* e = m_int_string[i].get(), *n;
|
||||
if (m_util.str.is_itos(e) && add_itos_axiom(e)) {
|
||||
if (m_util.str.is_itos(e) && add_itos_val_axiom(e)) {
|
||||
change = true;
|
||||
}
|
||||
else if (m_util.str.is_stoi(e, n) && add_stoi_axiom(e)) {
|
||||
else if (m_util.str.is_stoi(e, n) && add_stoi_val_axiom(e)) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
bool theory_seq::add_stoi_axiom(expr* e) {
|
||||
void theory_seq::add_stoi_axiom(expr* e) {
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
SASSERT(m_util.str.is_stoi(e));
|
||||
literal l = mk_simplified_literal(m_autil.mk_ge(e, arith_util(m).mk_int(-1)));
|
||||
add_axiom(l);
|
||||
}
|
||||
|
||||
bool theory_seq::add_stoi_val_axiom(expr* e) {
|
||||
context& ctx = get_context();
|
||||
expr* n = nullptr;
|
||||
rational val;
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
VERIFY(m_util.str.is_stoi(e, n));
|
||||
if (!get_num_value(e, val)) {
|
||||
literal l = mk_simplified_literal(m_autil.mk_ge(e, arith_util(m).mk_int(-1)));
|
||||
add_axiom(l);
|
||||
TRACE("seq", tout << l << " " << ctx.get_assignment(l) << "\n";
|
||||
ctx.display(tout););
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (!m_stoi_axioms.contains(val)) {
|
||||
m_stoi_axioms.insert(val);
|
||||
|
@ -2445,54 +2448,60 @@ expr_ref theory_seq::digit2int(expr* ch) {
|
|||
return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, nullptr, nullptr, m_autil.mk_int()), m);
|
||||
}
|
||||
|
||||
bool theory_seq::add_itos_axiom(expr* e) {
|
||||
void theory_seq::add_itos_axiom(expr* e) {
|
||||
rational val;
|
||||
expr* n = nullptr;
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
VERIFY(m_util.str.is_itos(e, n));
|
||||
|
||||
// itos(n) = "" <=> n < 0
|
||||
app_ref e1(m_util.str.mk_empty(m.get_sort(e)), m);
|
||||
expr_ref zero(arith_util(m).mk_int(0), m);
|
||||
literal eq1 = mk_eq(e1, e, false);
|
||||
literal ge0 = mk_literal(m_autil.mk_ge(n, zero));
|
||||
// n >= 0 => itos(n) != ""
|
||||
// itos(n) = "" or n >= 0
|
||||
add_axiom(~eq1, ~ge0);
|
||||
add_axiom(eq1, ge0);
|
||||
|
||||
// n >= 0 => stoi(itos(n)) = n
|
||||
app_ref stoi(m_util.str.mk_stoi(e), m);
|
||||
add_axiom(~ge0, mk_eq(stoi, n, false));
|
||||
|
||||
// n >= 0 => itos(n) in (0-9)+
|
||||
expr_ref num_re(m);
|
||||
num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9")));
|
||||
num_re = m_util.re.mk_plus(num_re);
|
||||
app_ref in_re(m_util.re.mk_in_re(e, num_re), m);
|
||||
add_axiom(~ge0, mk_literal(in_re));
|
||||
}
|
||||
|
||||
bool theory_seq::add_itos_val_axiom(expr* e) {
|
||||
context& ctx = get_context();
|
||||
rational val;
|
||||
expr* n = nullptr;
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
VERIFY(m_util.str.is_itos(e, n));
|
||||
if (get_num_value(n, val)) {
|
||||
if (!m_itos_axioms.contains(val)) {
|
||||
m_itos_axioms.insert(val);
|
||||
app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m);
|
||||
expr_ref n1(arith_util(m).mk_numeral(val, true), m);
|
||||
bool change = false;
|
||||
|
||||
// itos(n) = "25" <=> n = 25
|
||||
literal eq1 = mk_eq(n1, n , false);
|
||||
literal eq2 = mk_eq(e, e1, false);
|
||||
add_axiom(~eq1, eq2);
|
||||
add_axiom(~eq2, eq1);
|
||||
ctx.force_phase(eq1);
|
||||
ctx.force_phase(eq2);
|
||||
|
||||
m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_itos_axioms, val));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
return true;
|
||||
}
|
||||
if (get_num_value(n, val) && !val.is_neg() && !m_itos_axioms.contains(val)) {
|
||||
m_itos_axioms.insert(val);
|
||||
app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m);
|
||||
expr_ref n1(arith_util(m).mk_numeral(val, true), m);
|
||||
|
||||
// itos(n) = "25" <=> n = 25
|
||||
literal eq1 = mk_eq(n1, n , false);
|
||||
literal eq2 = mk_eq(e, e1, false);
|
||||
add_axiom(~eq1, eq2);
|
||||
add_axiom(~eq2, eq1);
|
||||
ctx.force_phase(eq1);
|
||||
ctx.force_phase(eq2);
|
||||
|
||||
m_trail_stack.push(insert_map<theory_seq, rational_set, rational>(m_itos_axioms, val));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
change = true;
|
||||
}
|
||||
else {
|
||||
// stoi(itos(n)) = n
|
||||
app_ref e2(m_util.str.mk_stoi(e), m);
|
||||
if (ctx.e_internalized(e2) && ctx.get_enode(e2)->get_root() == ctx.get_enode(n)->get_root()) {
|
||||
return false;
|
||||
}
|
||||
add_axiom(mk_eq(e2, n, false));
|
||||
|
||||
#if 1
|
||||
expr_ref num_re(m), opt_re(m);
|
||||
num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9")));
|
||||
num_re = m_util.re.mk_plus(num_re);
|
||||
opt_re = m_util.re.mk_opt(m_util.re.mk_to_re(m_util.str.mk_string(symbol("-"))));
|
||||
num_re = m_util.re.mk_concat(opt_re, num_re);
|
||||
app_ref in_re(m_util.re.mk_in_re(e, num_re), m);
|
||||
internalize_term(in_re);
|
||||
propagate_in_re(in_re, true);
|
||||
#endif
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, e)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return change;
|
||||
}
|
||||
|
||||
void theory_seq::apply_sort_cnstr(enode* n, sort* s) {
|
||||
|
@ -2721,13 +2730,12 @@ public:
|
|||
bool is_string = th.m_util.is_string(m_sort);
|
||||
expr_ref result(th.m);
|
||||
if (is_string) {
|
||||
svector<unsigned> sbuffer;
|
||||
unsigned_vector sbuffer;
|
||||
bv_util bv(th.m);
|
||||
rational val;
|
||||
unsigned sz;
|
||||
|
||||
for (unsigned i = 0; i < m_source.size(); ++i) {
|
||||
switch (m_source[i]) {
|
||||
for (source_t src : m_source) {
|
||||
switch (src) {
|
||||
case unit_source: {
|
||||
VERIFY(bv.is_numeral(values[j++], val, sz));
|
||||
sbuffer.push_back(val.get_unsigned());
|
||||
|
@ -2757,12 +2765,13 @@ public:
|
|||
break;
|
||||
}
|
||||
}
|
||||
// TRACE("seq", tout << src << " " << sbuffer << "\n";);
|
||||
}
|
||||
result = th.m_util.str.mk_string(zstring(sbuffer.size(), sbuffer.c_ptr()));
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < m_source.size(); ++i) {
|
||||
switch (m_source[i]) {
|
||||
for (source_t src : m_source) {
|
||||
switch (src) {
|
||||
case unit_source:
|
||||
args.push_back(th.m_util.str.mk_unit(values[j++]));
|
||||
break;
|
||||
|
@ -2804,8 +2813,8 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
|||
seq_value_proc* sv = alloc(seq_value_proc, *this, srt);
|
||||
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
for (unsigned i = 0; i < concats.size(); ++i) {
|
||||
expr* c = concats[i], *c1;
|
||||
for (expr* c : concats) {
|
||||
expr *c1;
|
||||
TRACE("seq", tout << mk_pp(c, m) << "\n";);
|
||||
if (m_util.str.is_unit(c, c1)) {
|
||||
if (ctx.e_internalized(c1)) {
|
||||
|
@ -3048,8 +3057,11 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) {
|
|||
enode* n2 = ctx.get_enode(e1);
|
||||
res = m_util.str.mk_string(symbol(val.to_string().c_str()));
|
||||
#if 1
|
||||
if (val.is_neg()) {
|
||||
result = e;
|
||||
}
|
||||
// TBD remove this: using roots is unsound for propagation.
|
||||
if (n1->get_root() == n2->get_root()) {
|
||||
else if (n1->get_root() == n2->get_root()) {
|
||||
result = res;
|
||||
deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(n1, n2)));
|
||||
}
|
||||
|
@ -3147,6 +3159,9 @@ void theory_seq::deque_axiom(expr* n) {
|
|||
else if (m_util.str.is_itos(n)) {
|
||||
add_itos_axiom(n);
|
||||
}
|
||||
else if (m_util.str.is_stoi(n)) {
|
||||
add_stoi_axiom(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -3366,9 +3381,9 @@ void theory_seq::add_itos_length_axiom(expr* len) {
|
|||
rational len1, len2;
|
||||
rational ten(10);
|
||||
if (get_num_value(n, len1)) {
|
||||
bool neg = len1.is_neg();
|
||||
if (neg) len1.neg();
|
||||
num_char1 = neg?2:1;
|
||||
if (len1.is_neg()) {
|
||||
return;
|
||||
}
|
||||
// 0 <= x < 10
|
||||
// 10 <= x < 100
|
||||
// 100 <= x < 1000
|
||||
|
@ -3387,13 +3402,12 @@ void theory_seq::add_itos_length_axiom(expr* len) {
|
|||
|
||||
literal len_le(mk_literal(m_autil.mk_le(len, m_autil.mk_int(num_char))));
|
||||
literal len_ge(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(num_char))));
|
||||
literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
|
||||
add_axiom(~n_ge_0, mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1))));
|
||||
|
||||
if (num_char == 1) {
|
||||
add_axiom(len_ge);
|
||||
literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
|
||||
literal n_ge_10(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(10))));
|
||||
add_axiom(~n_ge_0, n_ge_10, len_le);
|
||||
add_axiom(~len_le, n_ge_0);
|
||||
add_axiom(~len_le, ~n_ge_10);
|
||||
return;
|
||||
}
|
||||
|
@ -3401,22 +3415,13 @@ void theory_seq::add_itos_length_axiom(expr* len) {
|
|||
for (unsigned i = 2; i < num_char; ++i) {
|
||||
hi *= ten;
|
||||
}
|
||||
// n <= -hi or n >= hi*10 <=> len >= num_chars
|
||||
// -10*hi < n < 100*hi <=> len <= num_chars
|
||||
literal n_le_hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-hi, true)));
|
||||
// n >= hi*10 <=> len >= num_chars
|
||||
// n < 100*hi <=> len <= num_chars
|
||||
literal n_ge_10hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*hi, true)));
|
||||
literal n_le_m10hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-ten*hi, true)));
|
||||
literal n_ge_100hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*ten*hi, true)));
|
||||
|
||||
add_axiom(~n_le_hi, len_ge);
|
||||
add_axiom(~n_ge_10hi, len_ge);
|
||||
add_axiom(n_le_hi, n_ge_10hi, ~len_ge);
|
||||
|
||||
add_axiom(n_le_m10hi, n_ge_100hi, len_le);
|
||||
add_axiom(~n_le_m10hi, ~len_le);
|
||||
add_axiom(~n_ge_100hi, ~len_le);
|
||||
|
||||
add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1))));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3729,6 +3734,7 @@ bool theory_seq::is_extract_suffix(expr* s, expr* i, expr* l) {
|
|||
|
||||
/*
|
||||
0 <= l <= len(s) => s = ey & l = len(e)
|
||||
len(s) < l => s = e
|
||||
*/
|
||||
void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) {
|
||||
TRACE("seq", tout << mk_pp(e, m) << " " << mk_pp(s, m) << " " << mk_pp(l, m) << "\n";);
|
||||
|
@ -3743,6 +3749,7 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) {
|
|||
add_axiom(~l_ge_0, ~l_le_s, mk_seq_eq(s, ey));
|
||||
add_axiom(~l_ge_0, ~l_le_s, mk_eq(l, le, false));
|
||||
add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, m_util.str.mk_length(y), false));
|
||||
add_axiom(l_le_s, mk_eq(e, s, false));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4214,7 +4221,9 @@ void theory_seq::relevant_eh(app* n) {
|
|||
m_util.str.is_extract(n) ||
|
||||
m_util.str.is_at(n) ||
|
||||
m_util.str.is_empty(n) ||
|
||||
m_util.str.is_string(n)) {
|
||||
m_util.str.is_string(n) ||
|
||||
m_util.str.is_itos(n) ||
|
||||
m_util.str.is_stoi(n)) {
|
||||
enque_axiom(n);
|
||||
}
|
||||
|
||||
|
|
|
@ -507,8 +507,10 @@ namespace smt {
|
|||
void add_elim_string_axiom(expr* n);
|
||||
void add_at_axiom(expr* n);
|
||||
void add_in_re_axiom(expr* n);
|
||||
bool add_stoi_axiom(expr* n);
|
||||
bool add_itos_axiom(expr* n);
|
||||
void add_itos_axiom(expr* n);
|
||||
void add_stoi_axiom(expr* n);
|
||||
bool add_stoi_val_axiom(expr* n);
|
||||
bool add_itos_val_axiom(expr* n);
|
||||
literal is_digit(expr* ch);
|
||||
expr_ref digit2int(expr* ch);
|
||||
void add_itos_length_axiom(expr* n);
|
||||
|
|
|
@ -668,7 +668,6 @@ namespace smt {
|
|||
}
|
||||
|
||||
app * theory_str::mk_indexof(expr * haystack, expr * needle) {
|
||||
// TODO check meaning of the third argument here
|
||||
app * indexof = u.str.mk_index(haystack, needle, mk_int(0));
|
||||
m_trail.push_back(indexof);
|
||||
// immediately force internalization so that axiom setup does not fail
|
||||
|
@ -877,14 +876,7 @@ namespace smt {
|
|||
instantiate_axiom_Contains(e);
|
||||
} else if (u.str.is_index(a)) {
|
||||
instantiate_axiom_Indexof(e);
|
||||
/* TODO NEXT: Indexof2/Lastindexof rewrite?
|
||||
} else if (is_Indexof2(e)) {
|
||||
instantiate_axiom_Indexof2(e);
|
||||
} else if (is_LastIndexof(e)) {
|
||||
instantiate_axiom_LastIndexof(e);
|
||||
*/
|
||||
} else if (u.str.is_extract(a)) {
|
||||
// TODO check semantics of substr vs. extract
|
||||
instantiate_axiom_Substr(e);
|
||||
} else if (u.str.is_replace(a)) {
|
||||
instantiate_axiom_Replace(e);
|
||||
|
@ -1265,27 +1257,37 @@ namespace smt {
|
|||
context & ctx = get_context();
|
||||
ast_manager & m = get_manager();
|
||||
|
||||
app * expr = e->get_owner();
|
||||
if (axiomatized_terms.contains(expr)) {
|
||||
TRACE("str", tout << "already set up Indexof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
app * ex = e->get_owner();
|
||||
if (axiomatized_terms.contains(ex)) {
|
||||
TRACE("str", tout << "already set up str.indexof axiom for " << mk_pp(ex, m) << std::endl;);
|
||||
return;
|
||||
}
|
||||
axiomatized_terms.insert(expr);
|
||||
SASSERT(ex->get_num_args() == 3);
|
||||
// if the third argument is exactly the integer 0, we can use this "simple" indexof;
|
||||
// otherwise, we call the "extended" version
|
||||
expr * startingPosition = ex->get_arg(2);
|
||||
rational startingInteger;
|
||||
if (!m_autil.is_numeral(startingPosition, startingInteger) || !startingInteger.is_zero()) {
|
||||
// "extended" indexof term with prefix
|
||||
instantiate_axiom_Indexof_extended(e);
|
||||
return;
|
||||
}
|
||||
axiomatized_terms.insert(ex);
|
||||
|
||||
TRACE("str", tout << "instantiate Indexof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
TRACE("str", tout << "instantiate str.indexof axiom for " << mk_pp(ex, m) << std::endl;);
|
||||
|
||||
expr_ref x1(mk_str_var("x1"), m);
|
||||
expr_ref x2(mk_str_var("x2"), m);
|
||||
expr_ref indexAst(mk_int_var("index"), m);
|
||||
|
||||
expr_ref condAst(mk_contains(expr->get_arg(0), expr->get_arg(1)), m);
|
||||
expr_ref condAst(mk_contains(ex->get_arg(0), ex->get_arg(1)), m);
|
||||
SASSERT(condAst);
|
||||
|
||||
// -----------------------
|
||||
// true branch
|
||||
expr_ref_vector thenItems(m);
|
||||
// args[0] = x1 . args[1] . x2
|
||||
thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x1, mk_concat(expr->get_arg(1), x2))));
|
||||
thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x1, mk_concat(ex->get_arg(1), x2))));
|
||||
// indexAst = |x1|
|
||||
thenItems.push_back(ctx.mk_eq_atom(indexAst, mk_strlen(x1)));
|
||||
// args[0] = x3 . x4
|
||||
|
@ -1293,11 +1295,11 @@ namespace smt {
|
|||
// /\ ! contains(x3, args[1])
|
||||
expr_ref x3(mk_str_var("x3"), m);
|
||||
expr_ref x4(mk_str_var("x4"), m);
|
||||
expr_ref tmpLen(m_autil.mk_add(indexAst, mk_strlen(expr->get_arg(1)), mk_int(-1)), m);
|
||||
expr_ref tmpLen(m_autil.mk_add(indexAst, mk_strlen(ex->get_arg(1)), mk_int(-1)), m);
|
||||
SASSERT(tmpLen);
|
||||
thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4)));
|
||||
thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x3, x4)));
|
||||
thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen));
|
||||
thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1))));
|
||||
thenItems.push_back(mk_not(m, mk_contains(x3, ex->get_arg(1))));
|
||||
expr_ref thenBranch(m.mk_and(thenItems.size(), thenItems.c_ptr()), m);
|
||||
SASSERT(thenBranch);
|
||||
|
||||
|
@ -1309,26 +1311,42 @@ namespace smt {
|
|||
expr_ref breakdownAssert(m.mk_ite(condAst, thenBranch, elseBranch), m);
|
||||
SASSERT(breakdownAssert);
|
||||
|
||||
expr_ref reduceToIndex(ctx.mk_eq_atom(expr, indexAst), m);
|
||||
expr_ref reduceToIndex(ctx.mk_eq_atom(ex, indexAst), m);
|
||||
SASSERT(reduceToIndex);
|
||||
|
||||
expr_ref finalAxiom(m.mk_and(breakdownAssert, reduceToIndex), m);
|
||||
SASSERT(finalAxiom);
|
||||
assert_axiom(finalAxiom);
|
||||
|
||||
{
|
||||
// heuristic: integrate with str.contains information
|
||||
// (but don't introduce it if it isn't already in the instance)
|
||||
expr_ref haystack(ex->get_arg(0), m), needle(ex->get_arg(1), m), startIdx(ex->get_arg(2), m);
|
||||
expr_ref zeroAst(mk_int(0), m);
|
||||
// (H contains N) <==> (H indexof N, i) >= 0
|
||||
expr_ref premise(u.str.mk_contains(haystack, needle), m);
|
||||
ctx.internalize(premise, false);
|
||||
expr_ref conclusion(m_autil.mk_ge(ex, zeroAst), m);
|
||||
expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m);
|
||||
SASSERT(containsAxiom);
|
||||
// we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent
|
||||
m_delayed_axiom_setup_terms.push_back(containsAxiom);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_str::instantiate_axiom_Indexof2(enode * e) {
|
||||
void theory_str::instantiate_axiom_Indexof_extended(enode * e) {
|
||||
context & ctx = get_context();
|
||||
ast_manager & m = get_manager();
|
||||
|
||||
app * expr = e->get_owner();
|
||||
if (axiomatized_terms.contains(expr)) {
|
||||
TRACE("str", tout << "already set up Indexof2 axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
TRACE("str", tout << "already set up extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
return;
|
||||
}
|
||||
SASSERT(expr->get_num_args() == 3);
|
||||
axiomatized_terms.insert(expr);
|
||||
|
||||
TRACE("str", tout << "instantiate Indexof2 axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
TRACE("str", tout << "instantiate extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// if (arg[2] >= length(arg[0])) // ite2
|
||||
|
@ -1360,7 +1378,7 @@ namespace smt {
|
|||
ite2ElseItems.push_back(ctx.mk_eq_atom(indexAst, mk_indexof(suffix, expr->get_arg(1))));
|
||||
ite2ElseItems.push_back(ctx.mk_eq_atom(expr->get_arg(2), prefixLen));
|
||||
ite2ElseItems.push_back(ite3);
|
||||
expr_ref ite2Else(m.mk_and(ite2ElseItems.size(), ite2ElseItems.c_ptr()), m);
|
||||
expr_ref ite2Else(mk_and(ite2ElseItems), m);
|
||||
SASSERT(ite2Else);
|
||||
|
||||
expr_ref ite2(m.mk_ite(
|
||||
|
@ -1383,6 +1401,20 @@ namespace smt {
|
|||
expr_ref reduceTerm(ctx.mk_eq_atom(expr, resAst), m);
|
||||
SASSERT(reduceTerm);
|
||||
assert_axiom(reduceTerm);
|
||||
|
||||
{
|
||||
// heuristic: integrate with str.contains information
|
||||
// (but don't introduce it if it isn't already in the instance)
|
||||
expr_ref haystack(expr->get_arg(0), m), needle(expr->get_arg(1), m), startIdx(expr->get_arg(2), m);
|
||||
// (H contains N) <==> (H indexof N, i) >= 0
|
||||
expr_ref premise(u.str.mk_contains(haystack, needle), m);
|
||||
ctx.internalize(premise, false);
|
||||
expr_ref conclusion(m_autil.mk_ge(expr, zeroAst), m);
|
||||
expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m);
|
||||
SASSERT(containsAxiom);
|
||||
// we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent
|
||||
m_delayed_axiom_setup_terms.push_back(containsAxiom);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_str::instantiate_axiom_LastIndexof(enode * e) {
|
||||
|
@ -1854,8 +1886,11 @@ namespace smt {
|
|||
// trivially true for any string!
|
||||
assert_axiom(ex);
|
||||
} else if (u.re.is_full_char(regex)) {
|
||||
TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;);
|
||||
NOT_IMPLEMENTED_YET();
|
||||
// any char = any string of length 1
|
||||
expr_ref rhs(ctx.mk_eq_atom(mk_strlen(str), mk_int(1)), m);
|
||||
expr_ref finalAxiom(m.mk_iff(ex, rhs), m);
|
||||
SASSERT(finalAxiom);
|
||||
assert_axiom(finalAxiom);
|
||||
} else {
|
||||
TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;);
|
||||
NOT_IMPLEMENTED_YET();
|
||||
|
@ -5602,6 +5637,8 @@ namespace smt {
|
|||
// merge arg0 and arg1
|
||||
expr * arg0 = to_app(node)->get_arg(0);
|
||||
expr * arg1 = to_app(node)->get_arg(1);
|
||||
SASSERT(arg0 != node);
|
||||
SASSERT(arg1 != node);
|
||||
expr * arg0DeAlias = dealias_node(arg0, varAliasMap, concatAliasMap);
|
||||
expr * arg1DeAlias = dealias_node(arg1, varAliasMap, concatAliasMap);
|
||||
get_grounded_concats(arg0DeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap);
|
||||
|
@ -6369,6 +6406,13 @@ namespace smt {
|
|||
make_transition(tmp, ch, tmp);
|
||||
}
|
||||
TRACE("str", tout << "re.all NFA: start = " << start << ", end = " << end << std::endl;);
|
||||
} else if (u.re.is_full_char(e)) {
|
||||
// effectively . (match any one character)
|
||||
for (unsigned int i = 0; i < 256; ++i) {
|
||||
char ch = (char)i;
|
||||
make_transition(start, ch, end);
|
||||
}
|
||||
TRACE("str", tout << "re.allchar NFA: start = " << start << ", end = " << end << std::endl;);
|
||||
} else {
|
||||
TRACE("str", tout << "invalid regular expression" << std::endl;);
|
||||
m_valid = false;
|
||||
|
@ -9678,8 +9722,8 @@ namespace smt {
|
|||
context & ctx = get_context();
|
||||
ast_manager & m = get_manager();
|
||||
|
||||
expr_ref_vector assignments(m);
|
||||
ctx.get_assignments(assignments);
|
||||
//expr_ref_vector assignments(m);
|
||||
//ctx.get_assignments(assignments);
|
||||
|
||||
if (opt_VerifyFinalCheckProgress) {
|
||||
finalCheckProgressIndicator = false;
|
||||
|
|
|
@ -538,7 +538,7 @@ protected:
|
|||
void instantiate_axiom_suffixof(enode * e);
|
||||
void instantiate_axiom_Contains(enode * e);
|
||||
void instantiate_axiom_Indexof(enode * e);
|
||||
void instantiate_axiom_Indexof2(enode * e);
|
||||
void instantiate_axiom_Indexof_extended(enode * e);
|
||||
void instantiate_axiom_LastIndexof(enode * e);
|
||||
void instantiate_axiom_Substr(enode * e);
|
||||
void instantiate_axiom_Replace(enode * e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue