mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
prepare polysat
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
3f5df04dc4
252 changed files with 5792 additions and 2553 deletions
|
@ -40,8 +40,8 @@ void preprocessor_params::display(std::ostream & out) const {
|
|||
pattern_inference_params::display(out);
|
||||
bit_blaster_params::display(out);
|
||||
|
||||
DISPLAY_PARAM(m_lift_ite);
|
||||
DISPLAY_PARAM(m_ng_lift_ite);
|
||||
DISPLAY_PARAM((int)m_lift_ite);
|
||||
DISPLAY_PARAM((int)m_ng_lift_ite);
|
||||
DISPLAY_PARAM(m_pull_cheap_ite);
|
||||
DISPLAY_PARAM(m_pull_nested_quantifiers);
|
||||
DISPLAY_PARAM(m_eliminate_term_ite);
|
||||
|
|
|
@ -21,7 +21,7 @@ Revision History:
|
|||
#include "params/pattern_inference_params.h"
|
||||
#include "params/bit_blaster_params.h"
|
||||
|
||||
enum lift_ite_kind {
|
||||
enum class lift_ite_kind {
|
||||
LI_NONE,
|
||||
LI_CONSERVATIVE,
|
||||
LI_FULL
|
||||
|
@ -50,8 +50,8 @@ struct preprocessor_params : public pattern_inference_params,
|
|||
|
||||
public:
|
||||
preprocessor_params(params_ref const & p = params_ref()):
|
||||
m_lift_ite(LI_NONE),
|
||||
m_ng_lift_ite(LI_NONE),
|
||||
m_lift_ite(lift_ite_kind::LI_NONE),
|
||||
m_ng_lift_ite(lift_ite_kind::LI_NONE),
|
||||
m_pull_cheap_ite(false),
|
||||
m_pull_nested_quantifiers(false),
|
||||
m_eliminate_term_ite(false),
|
||||
|
|
|
@ -28,6 +28,7 @@ void qi_params::updt_params(params_ref const & _p) {
|
|||
m_mbqi_trace = p.mbqi_trace();
|
||||
m_mbqi_force_template = p.mbqi_force_template();
|
||||
m_mbqi_id = p.mbqi_id();
|
||||
m_qe_lite = p.q_lite();
|
||||
m_qi_profile = p.qi_profile();
|
||||
m_qi_profile_freq = p.qi_profile_freq();
|
||||
m_qi_max_instances = p.qi_max_instances();
|
||||
|
|
|
@ -30,26 +30,27 @@ enum quick_checker_mode {
|
|||
struct qi_params {
|
||||
std::string m_qi_cost;
|
||||
std::string m_qi_new_gen;
|
||||
double m_qi_eager_threshold;
|
||||
double m_qi_lazy_threshold;
|
||||
unsigned m_qi_max_eager_multipatterns;
|
||||
unsigned m_qi_max_lazy_multipattern_matching;
|
||||
bool m_qi_profile;
|
||||
unsigned m_qi_profile_freq;
|
||||
quick_checker_mode m_qi_quick_checker;
|
||||
bool m_qi_lazy_quick_checker;
|
||||
bool m_qi_promote_unsat;
|
||||
unsigned m_qi_max_instances;
|
||||
bool m_qi_lazy_instantiation;
|
||||
bool m_qi_conservative_final_check;
|
||||
double m_qi_eager_threshold = 10.0;
|
||||
double m_qi_lazy_threshold = 20.0;
|
||||
unsigned m_qi_max_eager_multipatterns = 0;
|
||||
unsigned m_qi_max_lazy_multipattern_matching = 2;
|
||||
bool m_qi_profile = false;
|
||||
unsigned m_qi_profile_freq = UINT_MAX;
|
||||
quick_checker_mode m_qi_quick_checker = MC_NO;
|
||||
bool m_qi_lazy_quick_checker = true;
|
||||
bool m_qi_promote_unsat = true;
|
||||
unsigned m_qi_max_instances = UINT_MAX;
|
||||
bool m_qi_lazy_instantiation = false;
|
||||
bool m_qi_conservative_final_check = false;
|
||||
bool m_qe_lite = false;
|
||||
|
||||
bool m_mbqi;
|
||||
unsigned m_mbqi_max_cexs;
|
||||
unsigned m_mbqi_max_cexs_incr;
|
||||
unsigned m_mbqi_max_iterations;
|
||||
bool m_mbqi_trace;
|
||||
unsigned m_mbqi_force_template;
|
||||
const char * m_mbqi_id;
|
||||
bool m_mbqi = true;
|
||||
unsigned m_mbqi_max_cexs = 1;
|
||||
unsigned m_mbqi_max_cexs_incr = 1;
|
||||
unsigned m_mbqi_max_iterations = 1000;
|
||||
bool m_mbqi_trace = false;
|
||||
unsigned m_mbqi_force_template = 10;
|
||||
const char * m_mbqi_id = nullptr;
|
||||
|
||||
qi_params(params_ref const & p = params_ref()):
|
||||
/*
|
||||
|
@ -78,26 +79,7 @@ struct qi_params {
|
|||
matching loop detection.
|
||||
*/
|
||||
m_qi_cost("(+ weight generation)"),
|
||||
m_qi_new_gen("cost"),
|
||||
m_qi_eager_threshold(10.0),
|
||||
m_qi_lazy_threshold(20.0), // reduced to give a chance to MBQI
|
||||
m_qi_max_eager_multipatterns(0),
|
||||
m_qi_max_lazy_multipattern_matching(2),
|
||||
m_qi_profile(false),
|
||||
m_qi_profile_freq(UINT_MAX),
|
||||
m_qi_quick_checker(MC_NO),
|
||||
m_qi_lazy_quick_checker(true),
|
||||
m_qi_promote_unsat(true),
|
||||
m_qi_max_instances(UINT_MAX),
|
||||
m_qi_lazy_instantiation(false),
|
||||
m_qi_conservative_final_check(false),
|
||||
m_mbqi(true), // enabled by default
|
||||
m_mbqi_max_cexs(1),
|
||||
m_mbqi_max_cexs_incr(1),
|
||||
m_mbqi_max_iterations(1000),
|
||||
m_mbqi_trace(false),
|
||||
m_mbqi_force_template(10),
|
||||
m_mbqi_id(nullptr)
|
||||
m_qi_new_gen("cost")
|
||||
{
|
||||
updt_params(p);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ def_module_params(module_name='smt',
|
|||
('mbqi.force_template', UINT, 10, 'some quantifiers can be used as templates for building interpretations for functions. Z3 uses heuristics to decide whether a quantifier will be used as a template or not. Quantifiers with weight >= mbqi.force_template are forced to be used as a template'),
|
||||
('mbqi.id', STRING, '', 'Only use model-based instantiation for quantifiers with id\'s beginning with string'),
|
||||
('q.lift_ite', UINT, 0, '0 - don not lift non-ground if-then-else, 1 - use conservative ite lifting, 2 - use full lifting of if-then-else under quantifiers'),
|
||||
('q.lite', BOOL, False, 'Use cheap quantifier elimination during pre-processing'),
|
||||
('qi.profile', BOOL, False, 'profile quantifier instantiation'),
|
||||
('qi.profile_freq', UINT, UINT_MAX, 'how frequent results are reported by qi.profile'),
|
||||
('qi.max_instances', UINT, UINT_MAX, 'maximum number of quantifier instantiations'),
|
||||
|
@ -49,6 +50,7 @@ def_module_params(module_name='smt',
|
|||
('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, True, 'use polysat bit-vector solver'),
|
||||
('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'),
|
||||
|
|
|
@ -28,6 +28,7 @@ void theory_bv_params::updt_params(params_ref const & _p) {
|
|||
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();
|
||||
}
|
||||
|
||||
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
|
||||
|
@ -42,4 +43,5 @@ void theory_bv_params::display(std::ostream & out) const {
|
|||
DISPLAY_PARAM(m_bv_blast_max_size);
|
||||
DISPLAY_PARAM(m_bv_enable_int2bv2int);
|
||||
DISPLAY_PARAM(m_bv_delay);
|
||||
DISPLAY_PARAM(m_bv_polysat);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ struct theory_bv_params {
|
|||
bool m_bv_enable_int2bv2int = true;
|
||||
bool m_bv_watch_diseq = false;
|
||||
bool m_bv_delay = true;
|
||||
bool m_bv_polysat = true;
|
||||
theory_bv_params(params_ref const & p = params_ref()) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
|
|
@ -226,6 +226,7 @@ namespace smt {
|
|||
ebindings[i] = bindings[i]->get_expr();
|
||||
expr_ref instance = m_subst();
|
||||
|
||||
|
||||
TRACE("qi_queue", tout << "new instance:\n" << mk_pp(instance, m) << "\n";);
|
||||
TRACE("qi_queue_instance", tout << "new instance:\n" << mk_pp(instance, m) << "\n";);
|
||||
expr_ref s_instance(m);
|
||||
|
@ -244,6 +245,15 @@ namespace smt {
|
|||
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
std::cout << "instantiate\n";
|
||||
enode_vector _bindings(num_bindings, bindings);
|
||||
for (auto * b : _bindings)
|
||||
std::cout << enode_pp(b, m_context) << " ";
|
||||
std::cout << "\n";
|
||||
std::cout << mk_pp(q, m) << "\n";
|
||||
#endif
|
||||
|
||||
TRACE("qi_queue", tout << "simplified instance:\n" << s_instance << "\n";);
|
||||
stat->inc_num_instances();
|
||||
if (stat->get_num_instances() % m_params.m_qi_profile_freq == 0) {
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace smt {
|
|||
void add_indexof_axiom(expr* n) { m_ax.indexof_axiom(n); }
|
||||
void add_last_indexof_axiom(expr* n) { m_ax.last_indexof_axiom(n); }
|
||||
void add_replace_axiom(expr* n) { m_ax.replace_axiom(n); }
|
||||
void add_replace_all_axiom(expr* n) { m_ax.replace_all_axiom(n); }
|
||||
void add_at_axiom(expr* n) { m_ax.at_axiom(n); }
|
||||
void add_nth_axiom(expr* n) { m_ax.nth_axiom(n); }
|
||||
void add_itos_axiom(expr* n) { m_ax.itos_axiom(n); }
|
||||
|
|
|
@ -375,6 +375,15 @@ bool theory_seq::split_lengths(dependency* dep,
|
|||
SASSERT(X != Y);
|
||||
|
||||
// |b| < |X| <= |b| + |Y| => x = bY1, Y = Y1Y2
|
||||
// at this point |b| = lenB - |Y| which is less than |X|
|
||||
// given how bs is constructed:
|
||||
// bs is constructed as a vector of strings with length >= |X|
|
||||
// but when the last element it removed the length is < |X|
|
||||
// We also have |X| <= |b| + |Y|, also by how bs is constructed.
|
||||
// Therefore the antecedent is true in the current model.
|
||||
// It could be the antecendet is not justified, so we create
|
||||
// literals to justify the antecedent and ensure they are relevant.
|
||||
// If the literals are relevant and assigned they should be true.
|
||||
expr_ref lenXE = mk_len(X);
|
||||
expr_ref lenYE = mk_len(Y);
|
||||
expr_ref lenb = mk_len(b);
|
||||
|
@ -383,7 +392,7 @@ bool theory_seq::split_lengths(dependency* dep,
|
|||
literal_vector lits;
|
||||
lits.push_back(lit1);
|
||||
lits.push_back(lit2);
|
||||
|
||||
|
||||
if (ctx.get_assignment(lit1) != l_true ||
|
||||
ctx.get_assignment(lit2) != l_true) {
|
||||
ctx.mark_as_relevant(lit1);
|
||||
|
|
|
@ -19,6 +19,9 @@ Author:
|
|||
#include "smt/seq_regex.h"
|
||||
#include "smt/theory_seq.h"
|
||||
#include "ast/expr_abstract.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include <ast/rewriter/expr_safe_replace.h>
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -144,38 +147,6 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//if r is uninterpreted then taking a derivative may diverge try to obtain the
|
||||
//value from equations providing r a definition
|
||||
if (is_uninterp(r)) {
|
||||
if (m_const_to_expr.contains(r)) {
|
||||
proof* _not_used = nullptr;
|
||||
m_const_to_expr.get(r, r, _not_used);
|
||||
if (is_uninterp(r)) {
|
||||
if (m_const_to_expr.contains(r)) {
|
||||
m_const_to_expr.get(r, r, _not_used);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//add the literal back
|
||||
expr_ref r_alias(m.mk_fresh_const(symbol(r->get_id()), r->get_sort(), false), m);
|
||||
expr_ref s_in_r_alias(re().mk_in_re(s, r_alias), m);
|
||||
literal s_in_r_alias_lit = th.mk_literal(s_in_r_alias);
|
||||
m_const_to_expr.insert(r_alias, r, nullptr);
|
||||
th.add_axiom(s_in_r_alias_lit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if (is_uninterp(r)) {
|
||||
th.add_unhandled_expr(e);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
expr_ref zero(a().mk_int(0), m);
|
||||
expr_ref acc(sk().mk_accept(s, zero, r), m);
|
||||
literal acc_lit = th.mk_literal(acc);
|
||||
|
@ -235,6 +206,28 @@ namespace smt {
|
|||
|
||||
}
|
||||
|
||||
bool seq_regex::block_if_empty(expr* r, literal lit) {
|
||||
auto info = re().get_info(r);
|
||||
|
||||
//if the minlength of the regex is UINT_MAX then the regex is a deadend
|
||||
if (re().is_empty(r) || info.min_length == UINT_MAX) {
|
||||
STRACE("seq_regex_brief", tout << "(empty) ";);
|
||||
th.add_axiom(~lit);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.interpreted) {
|
||||
update_state_graph(r);
|
||||
if (m_state_graph.is_dead(get_state_id(r))) {
|
||||
STRACE("seq_regex_brief", tout << "(dead) ";);
|
||||
th.add_axiom(~lit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Propagate the atom (accept s i r)
|
||||
*
|
||||
|
@ -271,24 +264,8 @@ namespace smt {
|
|||
<< "PA(" << mk_pp(s, m) << "@" << idx
|
||||
<< "," << state_str(r) << ") ";);
|
||||
|
||||
auto info = re().get_info(r);
|
||||
|
||||
//if the minlength of the regex is UINT_MAX then the regex is a deadend
|
||||
if (re().is_empty(r) || info.min_length == UINT_MAX) {
|
||||
STRACE("seq_regex_brief", tout << "(empty) ";);
|
||||
th.add_axiom(~lit);
|
||||
if (block_if_empty(r, lit))
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.interpreted) {
|
||||
update_state_graph(r);
|
||||
|
||||
if (m_state_graph.is_dead(get_state_id(r))) {
|
||||
STRACE("seq_regex_brief", tout << "(dead) ";);
|
||||
th.add_axiom(~lit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (block_unfolding(lit, idx)) {
|
||||
STRACE("seq_regex_brief", tout << "(blocked) ";);
|
||||
|
@ -459,13 +436,10 @@ namespace smt {
|
|||
STRACE("seq_regex", tout << "derivative(" << mk_pp(ele, m) << "): " << mk_pp(r, m) << std::endl;);
|
||||
|
||||
// Uses canonical variable (:var 0) for the derivative element
|
||||
expr_ref der(seq_rw().mk_derivative(r), m);
|
||||
|
||||
// Substitute (:var 0) with the actual element
|
||||
expr_ref der = seq_rw().mk_derivative(r);
|
||||
var_subst subst(m);
|
||||
expr_ref_vector sub(m);
|
||||
sub.push_back(ele);
|
||||
der = subst(der, sub);
|
||||
der = subst(der, ele);
|
||||
|
||||
STRACE("seq_regex", tout << "derivative result: " << mk_pp(der, m) << std::endl;);
|
||||
STRACE("seq_regex_brief", tout << "d(" << state_str(r) << ")="
|
||||
|
@ -480,17 +454,6 @@ namespace smt {
|
|||
TRACE("seq_regex", tout << "propagate EQ: " << mk_pp(r1, m) << ", " << mk_pp(r2, m) << std::endl;);
|
||||
STRACE("seq_regex_brief", tout << "PEQ ";);
|
||||
|
||||
/*
|
||||
if (is_uninterp(r1) || is_uninterp(r2)) {
|
||||
th.add_axiom(th.mk_eq(r1, r2, false));
|
||||
if (is_uninterp(r1))
|
||||
m_const_to_expr.insert(r1, r2, nullptr);
|
||||
else
|
||||
m_const_to_expr.insert(r2, r1, nullptr);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
sort* seq_sort = nullptr;
|
||||
VERIFY(u().is_re(r1, seq_sort));
|
||||
expr_ref r = symmetric_diff(r1, r2);
|
||||
|
@ -512,13 +475,11 @@ namespace smt {
|
|||
void seq_regex::propagate_ne(expr* r1, expr* r2) {
|
||||
TRACE("seq_regex", tout << "propagate NEQ: " << mk_pp(r1, m) << ", " << mk_pp(r2, m) << std::endl;);
|
||||
STRACE("seq_regex_brief", tout << "PNEQ ";);
|
||||
// TBD: rewrite to use state_graph
|
||||
// why is is_non_empty even needed, why not just not(in_empty)
|
||||
sort* seq_sort = nullptr;
|
||||
VERIFY(u().is_re(r1, seq_sort));
|
||||
expr_ref r = symmetric_diff(r1, r2);
|
||||
expr_ref emp(re().mk_empty(r->get_sort()), m);
|
||||
expr_ref n(m.mk_fresh_const("re.char", seq_sort), m);
|
||||
expr_ref n(m.mk_fresh_const("re.char", seq_sort), m);
|
||||
expr_ref is_non_empty = sk().mk_is_non_empty(r, r, n);
|
||||
th.add_axiom(th.mk_eq(r1, r2, false), th.mk_literal(is_non_empty));
|
||||
}
|
||||
|
@ -544,6 +505,10 @@ namespace smt {
|
|||
expr* e = ctx.bool_var2expr(lit.var()), *r = nullptr, *u = nullptr, *n = nullptr;
|
||||
VERIFY(sk().is_is_non_empty(e, r, u, n));
|
||||
|
||||
if (block_if_empty(r, lit))
|
||||
return;
|
||||
|
||||
|
||||
TRACE("seq_regex", tout << "propagate nonempty: " << mk_pp(e, m) << std::endl;);
|
||||
STRACE("seq_regex_brief", tout
|
||||
<< std::endl << "PNE(" << expr_id_str(e) << "," << state_str(r)
|
||||
|
@ -553,6 +518,7 @@ namespace smt {
|
|||
if (m.is_true(is_nullable))
|
||||
return;
|
||||
|
||||
|
||||
literal null_lit = th.mk_literal(is_nullable);
|
||||
expr_ref hd = mk_first(r, n);
|
||||
expr_ref d(m);
|
||||
|
@ -566,8 +532,8 @@ namespace smt {
|
|||
expr_ref_pair_vector cofactors(m);
|
||||
get_cofactors(d, cofactors);
|
||||
for (auto const& p : cofactors) {
|
||||
if (is_member(p.second, u))
|
||||
continue;
|
||||
if (is_member(p.second, u))
|
||||
continue;
|
||||
expr_ref cond(p.first, m);
|
||||
seq_rw().elim_condition(hd, cond);
|
||||
rewrite(cond);
|
||||
|
@ -641,23 +607,6 @@ namespace smt {
|
|||
// s[i..] in .* <==> true, also: s[i..] in .+ <==> true when |s|>i
|
||||
re_to_accept.find(e) = m.mk_true();
|
||||
}
|
||||
/*
|
||||
else if (re().is_epsilon(e))
|
||||
{
|
||||
expr* one = a().mk_int(1);
|
||||
_temp_bool_owner.push_back(one);
|
||||
//the substring starting after position i must be empty
|
||||
expr* s_end = str().mk_substr(s, i_int, one);
|
||||
expr* s_end_is_epsilon = m.mk_eq(s_end, str().mk_empty(m.get_sort(s)));
|
||||
|
||||
_temp_bool_owner.push_back(s_end_is_epsilon);
|
||||
re_to_accept.find(e) = s_end_is_epsilon;
|
||||
|
||||
STRACE("seq_regex_verbose", tout
|
||||
<< "added empty sequence leaf: "
|
||||
<< mk_pp(s_end_is_epsilon, m) << std::endl;);
|
||||
}
|
||||
*/
|
||||
else if (re().is_union(e, e1, e2)) {
|
||||
expr* b1 = re_to_accept.find(e1);
|
||||
expr* b2 = re_to_accept.find(e2);
|
||||
|
@ -728,39 +677,47 @@ namespace smt {
|
|||
Return a list of all (cond, leaf) pairs in a given derivative
|
||||
expression r.
|
||||
|
||||
Note: this recursive implementation is inefficient, since if nodes
|
||||
are repeated often in the expression DAG, they may be visited
|
||||
many times. For this reason, prefer mk_deriv_accept and
|
||||
get_all_derivatives when possible.
|
||||
Note: this implementation is inefficient: it simply collects all expressions under an if and
|
||||
iterates over all combinations.
|
||||
|
||||
This method is still used by:
|
||||
propagate_is_empty
|
||||
propagate_is_non_empty
|
||||
*/
|
||||
void seq_regex::get_cofactors(expr* r, expr_ref_pair_vector& result) {
|
||||
expr_ref_vector conds(m);
|
||||
get_cofactors_rec(r, conds, result);
|
||||
STRACE("seq_regex", tout << "Number of derivatives: "
|
||||
<< result.size() << std::endl;);
|
||||
STRACE("seq_regex_brief", tout << "#derivs=" << result.size() << " ";);
|
||||
}
|
||||
void seq_regex::get_cofactors_rec(expr* r, expr_ref_vector& conds,
|
||||
expr_ref_pair_vector& result) {
|
||||
expr* cond = nullptr, *r1 = nullptr, *r2 = nullptr;
|
||||
if (m.is_ite(r, cond, r1, r2)) {
|
||||
conds.push_back(cond);
|
||||
get_cofactors_rec(r1, conds, result);
|
||||
conds.pop_back();
|
||||
conds.push_back(mk_not(m, cond));
|
||||
get_cofactors_rec(r2, conds, result);
|
||||
conds.pop_back();
|
||||
obj_hashtable<expr> ifs;
|
||||
expr* cond = nullptr, * r1 = nullptr, * r2 = nullptr;
|
||||
for (expr* e : subterms::ground(expr_ref(r, m)))
|
||||
if (m.is_ite(e, cond, r1, r2))
|
||||
ifs.insert(cond);
|
||||
|
||||
expr_ref_vector rs(m);
|
||||
vector<expr_ref_vector> conds;
|
||||
conds.push_back(expr_ref_vector(m));
|
||||
rs.push_back(r);
|
||||
for (expr* c : ifs) {
|
||||
unsigned sz = conds.size();
|
||||
expr_safe_replace rep1(m);
|
||||
expr_safe_replace rep2(m);
|
||||
rep1.insert(c, m.mk_true());
|
||||
rep2.insert(c, m.mk_false());
|
||||
expr_ref r2(m);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr_ref_vector cs = conds[i];
|
||||
cs.push_back(mk_not(m, c));
|
||||
conds.push_back(cs);
|
||||
conds[i].push_back(c);
|
||||
expr_ref r1(rs.get(i), m);
|
||||
rep1(r1, r2);
|
||||
rs[i] = r2;
|
||||
rep2(r1, r2);
|
||||
rs.push_back(r2);
|
||||
}
|
||||
}
|
||||
else if (re().is_union(r, r1, r2)) {
|
||||
get_cofactors_rec(r1, conds, result);
|
||||
get_cofactors_rec(r2, conds, result);
|
||||
}
|
||||
else {
|
||||
expr_ref conj = mk_and(conds);
|
||||
for (unsigned i = 0; i < conds.size(); ++i) {
|
||||
expr_ref conj = mk_and(conds[i]);
|
||||
expr_ref r(rs.get(i), m);
|
||||
ctx.get_rewriter()(r);
|
||||
if (!m.is_false(conj) && !re().is_empty(r))
|
||||
result.push_back(conj, r);
|
||||
}
|
||||
|
@ -845,7 +802,6 @@ namespace smt {
|
|||
return m_state_to_expr.get(id - 1);
|
||||
}
|
||||
|
||||
|
||||
bool seq_regex::can_be_in_cycle(expr *r1, expr *r2) {
|
||||
// TBD: This can be used to optimize the state graph:
|
||||
// return false here if it is known that r1 -> r2 can never be
|
||||
|
@ -904,6 +860,7 @@ namespace smt {
|
|||
}
|
||||
m_state_graph.mark_done(r_id);
|
||||
}
|
||||
|
||||
STRACE("seq_regex", m_state_graph.display(tout););
|
||||
STRACE("seq_regex_brief", tout << std::endl;);
|
||||
STRACE("seq_regex_brief", m_state_graph.display(tout););
|
||||
|
|
|
@ -165,8 +165,6 @@ namespace smt {
|
|||
expr_ref mk_deriv_accept(expr* s, unsigned i, expr* r);
|
||||
void get_derivative_targets(expr* r, expr_ref_vector& targets);
|
||||
void get_cofactors(expr* r, expr_ref_pair_vector& result);
|
||||
void get_cofactors_rec(expr* r, expr_ref_vector& conds,
|
||||
expr_ref_pair_vector& result);
|
||||
|
||||
/*
|
||||
Pretty print the regex of the state id to the out stream,
|
||||
|
@ -184,6 +182,8 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
bool block_if_empty(expr* r, literal lit);
|
||||
|
||||
public:
|
||||
|
||||
seq_regex(theory_seq& th);
|
||||
|
@ -201,11 +201,11 @@ namespace smt {
|
|||
|
||||
void propagate_eq(expr* r1, expr* r2);
|
||||
|
||||
void propagate_ne(expr* r1, expr* r2);
|
||||
|
||||
void propagate_is_non_empty(literal lit);
|
||||
void propagate_ne(expr* r1, expr* r2);
|
||||
|
||||
void propagate_is_empty(literal lit);
|
||||
|
||||
void propagate_is_non_empty(literal lit);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -2906,6 +2906,30 @@ namespace smt {
|
|||
m_user_propagator->new_fixed_eh(v, val, sz, explain);
|
||||
}
|
||||
|
||||
bool context::is_fixed(enode* n, expr_ref& val, literal_vector& explain) {
|
||||
if (m.is_bool(n->get_expr())) {
|
||||
literal lit = get_literal(n->get_expr());
|
||||
switch (get_assignment(lit)) {
|
||||
case l_true:
|
||||
val = m.mk_true(); explain.push_back(lit); return true;
|
||||
case l_false:
|
||||
val = m.mk_false(); explain.push_back(~lit); return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
theory_var_list * l = n->get_th_var_list();
|
||||
while (l) {
|
||||
theory_id tid = l->get_id();
|
||||
auto* p = m_theories.get_plugin(tid);
|
||||
if (p && p->is_fixed_propagated(l->get_var(), val, explain))
|
||||
return true;
|
||||
l = l->get_next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void context::push() {
|
||||
pop_to_base_lvl();
|
||||
setup_context(false);
|
||||
|
|
|
@ -1723,12 +1723,18 @@ namespace smt {
|
|||
m_user_propagator->register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register(expr* e) {
|
||||
unsigned 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);
|
||||
}
|
||||
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r) {
|
||||
if (!m_user_propagator)
|
||||
throw default_exception("user propagator must be initialized");
|
||||
m_user_propagator->register_created(r);
|
||||
}
|
||||
|
||||
bool watches_fixed(enode* n) const;
|
||||
|
||||
void assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain);
|
||||
|
@ -1741,6 +1747,8 @@ namespace smt {
|
|||
assign_fixed(n, val, 1, &explain);
|
||||
}
|
||||
|
||||
bool is_fixed(enode* n, expr_ref& val, literal_vector& explain);
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
|
||||
void display_unsat_core(std::ostream & out) const;
|
||||
|
|
|
@ -158,7 +158,6 @@ namespace smt {
|
|||
|
||||
void mark_as_interpreted() {
|
||||
SASSERT(!m_interpreted);
|
||||
SASSERT(m_owner->get_num_args() == 0);
|
||||
SASSERT(m_class_size == 1);
|
||||
m_interpreted = true;
|
||||
}
|
||||
|
|
|
@ -974,7 +974,7 @@ namespace smt {
|
|||
}
|
||||
enode * e = enode::mk(m, m_region, m_app2enode, n, generation, suppress_args, merge_tf, m_scope_lvl, cgc_enabled, true);
|
||||
TRACE("mk_enode_detail", tout << "e.get_num_args() = " << e->get_num_args() << "\n";);
|
||||
if (n->get_num_args() == 0 && m.is_unique_value(n))
|
||||
if (m.is_unique_value(n))
|
||||
e->mark_as_interpreted();
|
||||
TRACE("mk_var_bug", tout << "mk_enode: " << id << "\n";);
|
||||
TRACE("generation", tout << "mk_enode: " << id << " " << generation << "\n";);
|
||||
|
|
|
@ -32,31 +32,11 @@ namespace smt {
|
|||
m_kernel(m, fp, p),
|
||||
m_params(p) {
|
||||
}
|
||||
|
||||
static void copy(imp& src, imp& dst) {
|
||||
context::copy(src.m_kernel, dst.m_kernel);
|
||||
}
|
||||
|
||||
smt_params & fparams() {
|
||||
return m_kernel.get_fparams();
|
||||
}
|
||||
|
||||
params_ref const & params() {
|
||||
return m_params;
|
||||
}
|
||||
|
||||
ast_manager & m() const {
|
||||
return m_kernel.get_manager();
|
||||
}
|
||||
|
||||
bool set_logic(symbol logic) {
|
||||
return m_kernel.set_logic(logic);
|
||||
}
|
||||
|
||||
void set_progress_callback(progress_callback * callback) {
|
||||
return m_kernel.set_progress_callback(callback);
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
// m_kernel.display(out); <<< for external users it is just junk
|
||||
// TODO: it will be replaced with assertion_stack.display
|
||||
|
@ -67,187 +47,7 @@ namespace smt {
|
|||
out << "\n " << mk_ismt2_pp(f, m(), 2);
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void assert_expr(expr * e) {
|
||||
TRACE("smt_kernel", tout << "assert:\n" << mk_ismt2_pp(e, m()) << "\n";);
|
||||
m_kernel.assert_expr(e);
|
||||
}
|
||||
|
||||
void assert_expr(expr * e, proof * pr) {
|
||||
m_kernel.assert_expr(e, pr);
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_kernel.get_num_asserted_formulas();
|
||||
}
|
||||
|
||||
void get_formulas(ptr_vector<expr>& fmls) const {
|
||||
m_kernel.get_asserted_formulas(fmls);
|
||||
}
|
||||
|
||||
expr* get_formula(unsigned i) const {
|
||||
return m_kernel.get_asserted_formula(i);
|
||||
}
|
||||
|
||||
void push() {
|
||||
TRACE("smt_kernel", tout << "push()\n";);
|
||||
m_kernel.push();
|
||||
}
|
||||
|
||||
void pop(unsigned num_scopes) {
|
||||
TRACE("smt_kernel", tout << "pop()\n";);
|
||||
m_kernel.pop(num_scopes);
|
||||
}
|
||||
|
||||
unsigned get_scope_level() const {
|
||||
return m_kernel.get_scope_level();
|
||||
}
|
||||
|
||||
lbool setup_and_check() {
|
||||
return m_kernel.setup_and_check();
|
||||
}
|
||||
|
||||
bool inconsistent() {
|
||||
return m_kernel.inconsistent();
|
||||
}
|
||||
|
||||
lbool check(unsigned num_assumptions, expr * const * assumptions) {
|
||||
return m_kernel.check(num_assumptions, assumptions);
|
||||
}
|
||||
|
||||
lbool check(expr_ref_vector const& cube, vector<expr_ref_vector> const& clause) {
|
||||
return m_kernel.check(cube, clause);
|
||||
}
|
||||
|
||||
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) {
|
||||
return m_kernel.get_consequences(assumptions, vars, conseq, unfixed);
|
||||
}
|
||||
|
||||
lbool preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores) {
|
||||
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);
|
||||
}
|
||||
|
||||
void get_model(model_ref & m) {
|
||||
m_kernel.get_model(m);
|
||||
}
|
||||
|
||||
proof * get_proof() {
|
||||
return m_kernel.get_proof();
|
||||
}
|
||||
|
||||
unsigned get_unsat_core_size() const {
|
||||
return m_kernel.get_unsat_core_size();
|
||||
}
|
||||
|
||||
expr * get_unsat_core_expr(unsigned idx) const {
|
||||
return m_kernel.get_unsat_core_expr(idx);
|
||||
}
|
||||
|
||||
void get_levels(ptr_vector<expr> const& vars, unsigned_vector& depth) {
|
||||
m_kernel.get_levels(vars, depth);
|
||||
}
|
||||
|
||||
expr_ref_vector get_trail() {
|
||||
return m_kernel.get_trail();
|
||||
}
|
||||
|
||||
failure last_failure() const {
|
||||
return m_kernel.get_last_search_failure();
|
||||
}
|
||||
|
||||
std::string last_failure_as_string() const {
|
||||
return m_kernel.last_failure_as_string();
|
||||
}
|
||||
|
||||
void set_reason_unknown(char const* msg) {
|
||||
m_kernel.set_reason_unknown(msg);
|
||||
}
|
||||
|
||||
void get_assignments(expr_ref_vector & result) {
|
||||
m_kernel.get_assignments(result);
|
||||
}
|
||||
|
||||
void get_relevant_labels(expr * cnstr, buffer<symbol> & result) {
|
||||
m_kernel.get_relevant_labels(cnstr, result);
|
||||
}
|
||||
|
||||
void get_relevant_labeled_literals(bool at_lbls, expr_ref_vector & result) {
|
||||
m_kernel.get_relevant_labeled_literals(at_lbls, result);
|
||||
}
|
||||
|
||||
void get_relevant_literals(expr_ref_vector & result) {
|
||||
m_kernel.get_relevant_literals(result);
|
||||
}
|
||||
|
||||
void get_guessed_literals(expr_ref_vector & result) {
|
||||
m_kernel.get_guessed_literals(result);
|
||||
}
|
||||
|
||||
expr_ref next_cube() {
|
||||
lookahead lh(m_kernel);
|
||||
return lh.choose();
|
||||
}
|
||||
|
||||
expr_ref_vector cubes(unsigned depth) {
|
||||
lookahead lh(m_kernel);
|
||||
return lh.choose_rec(depth);
|
||||
}
|
||||
|
||||
void collect_statistics(::statistics & st) const {
|
||||
m_kernel.collect_statistics(st);
|
||||
}
|
||||
|
||||
void reset_statistics() {
|
||||
}
|
||||
|
||||
void display_statistics(std::ostream & out) const {
|
||||
m_kernel.display_statistics(out);
|
||||
}
|
||||
|
||||
void display_istatistics(std::ostream & out) const {
|
||||
m_kernel.display_istatistics(out);
|
||||
}
|
||||
|
||||
bool canceled() {
|
||||
return m_kernel.get_cancel_flag();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_kernel.updt_params(p);
|
||||
}
|
||||
|
||||
void user_propagate_init(
|
||||
void* ctx,
|
||||
user_propagator::push_eh_t& push_eh,
|
||||
user_propagator::pop_eh_t& pop_eh,
|
||||
user_propagator::fresh_eh_t& fresh_eh) {
|
||||
m_kernel.user_propagate_init(ctx, push_eh, pop_eh, fresh_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_final(user_propagator::final_eh_t& final_eh) {
|
||||
m_kernel.user_propagate_register_final(final_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) {
|
||||
m_kernel.user_propagate_register_fixed(fixed_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_eq(user_propagator::eq_eh_t& eq_eh) {
|
||||
m_kernel.user_propagate_register_eq(eq_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh) {
|
||||
m_kernel.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register(expr* e) {
|
||||
return m_kernel.user_propagate_register(e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@ -260,148 +60,148 @@ namespace smt {
|
|||
}
|
||||
|
||||
ast_manager & kernel::m() const {
|
||||
return m_imp->m();
|
||||
return m_imp->m_kernel.get_manager();
|
||||
}
|
||||
|
||||
void kernel::copy(kernel& src, kernel& dst) {
|
||||
imp::copy(*src.m_imp, *dst.m_imp);
|
||||
context::copy(src.m_imp->m_kernel, dst.m_imp->m_kernel);
|
||||
}
|
||||
|
||||
bool kernel::set_logic(symbol logic) {
|
||||
return m_imp->set_logic(logic);
|
||||
return m_imp->m_kernel.set_logic(logic);
|
||||
}
|
||||
|
||||
void kernel::set_progress_callback(progress_callback * callback) {
|
||||
m_imp->set_progress_callback(callback);
|
||||
m_imp->m_kernel.set_progress_callback(callback);
|
||||
}
|
||||
|
||||
void kernel::assert_expr(expr * e) {
|
||||
m_imp->assert_expr(e);
|
||||
m_imp->m_kernel.assert_expr(e);
|
||||
}
|
||||
|
||||
void kernel::assert_expr(expr_ref_vector const& es) {
|
||||
for (unsigned i = 0; i < es.size(); ++i) {
|
||||
m_imp->assert_expr(es[i]);
|
||||
}
|
||||
for (unsigned i = 0; i < es.size(); ++i)
|
||||
m_imp->m_kernel.assert_expr(es[i]);
|
||||
}
|
||||
|
||||
void kernel::assert_expr(expr * e, proof * pr) {
|
||||
m_imp->assert_expr(e, pr);
|
||||
m_imp->m_kernel.assert_expr(e, pr);
|
||||
}
|
||||
|
||||
unsigned kernel::size() const {
|
||||
return m_imp->size();
|
||||
return m_imp->m_kernel.get_num_asserted_formulas();
|
||||
}
|
||||
|
||||
expr* kernel::get_formula(unsigned i) const {
|
||||
return m_imp->get_formula(i);
|
||||
return m_imp->m_kernel.get_asserted_formula(i);
|
||||
}
|
||||
|
||||
|
||||
void kernel::push() {
|
||||
m_imp->push();
|
||||
m_imp->m_kernel.push();
|
||||
}
|
||||
|
||||
void kernel::pop(unsigned num_scopes) {
|
||||
m_imp->pop(num_scopes);
|
||||
m_imp->m_kernel.pop(num_scopes);
|
||||
}
|
||||
|
||||
unsigned kernel::get_scope_level() const {
|
||||
return m_imp->get_scope_level();
|
||||
return m_imp->m_kernel.get_scope_level();
|
||||
}
|
||||
|
||||
void kernel::reset() {
|
||||
ast_manager & _m = m();
|
||||
smt_params & fps = m_imp->fparams();
|
||||
params_ref ps = m_imp->params();
|
||||
smt_params& fps = m_imp->m_kernel.get_fparams();
|
||||
params_ref ps = m_imp->m_params;
|
||||
m_imp->~imp();
|
||||
m_imp = new (m_imp) imp(_m, fps, ps);
|
||||
}
|
||||
|
||||
bool kernel::inconsistent() {
|
||||
return m_imp->inconsistent();
|
||||
return m_imp->m_kernel.inconsistent();
|
||||
}
|
||||
|
||||
lbool kernel::setup_and_check() {
|
||||
return m_imp->setup_and_check();
|
||||
return m_imp->m_kernel.setup_and_check();
|
||||
}
|
||||
|
||||
lbool kernel::check(unsigned num_assumptions, expr * const * assumptions) {
|
||||
lbool r = m_imp->check(num_assumptions, assumptions);
|
||||
lbool r = m_imp->m_kernel.check(num_assumptions, assumptions);
|
||||
TRACE("smt_kernel", tout << "check result: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
lbool kernel::check(expr_ref_vector const& cube, vector<expr_ref_vector> const& clauses) {
|
||||
return m_imp->check(cube, clauses);
|
||||
return m_imp->m_kernel.check(cube, clauses);
|
||||
}
|
||||
|
||||
lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) {
|
||||
return m_imp->get_consequences(assumptions, vars, conseq, unfixed);
|
||||
return m_imp->m_kernel.get_consequences(assumptions, vars, conseq, unfixed);
|
||||
}
|
||||
|
||||
lbool kernel::preferred_sat(expr_ref_vector const& asms, vector<expr_ref_vector>& cores) {
|
||||
return m_imp->preferred_sat(asms, cores);
|
||||
return m_imp->m_kernel.preferred_sat(asms, cores);
|
||||
}
|
||||
|
||||
lbool kernel::find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
|
||||
return m_imp->find_mutexes(vars, mutexes);
|
||||
return m_imp->m_kernel.find_mutexes(vars, mutexes);
|
||||
}
|
||||
|
||||
void kernel::get_model(model_ref & m) {
|
||||
m_imp->get_model(m);
|
||||
m_imp->m_kernel.get_model(m);
|
||||
}
|
||||
|
||||
proof * kernel::get_proof() {
|
||||
return m_imp->get_proof();
|
||||
return m_imp->m_kernel.get_proof();
|
||||
}
|
||||
|
||||
unsigned kernel::get_unsat_core_size() const {
|
||||
return m_imp->get_unsat_core_size();
|
||||
return m_imp->m_kernel.get_unsat_core_size();
|
||||
}
|
||||
|
||||
expr * kernel::get_unsat_core_expr(unsigned idx) const {
|
||||
return m_imp->get_unsat_core_expr(idx);
|
||||
return m_imp->m_kernel.get_unsat_core_expr(idx);
|
||||
}
|
||||
|
||||
failure kernel::last_failure() const {
|
||||
return m_imp->last_failure();
|
||||
return m_imp->m_kernel.get_last_search_failure();
|
||||
}
|
||||
|
||||
std::string kernel::last_failure_as_string() const {
|
||||
return m_imp->last_failure_as_string();
|
||||
return m_imp->m_kernel.last_failure_as_string();
|
||||
}
|
||||
|
||||
void kernel::set_reason_unknown(char const* msg) {
|
||||
m_imp->set_reason_unknown(msg);
|
||||
m_imp->m_kernel.set_reason_unknown(msg);
|
||||
}
|
||||
|
||||
void kernel::get_assignments(expr_ref_vector & result) {
|
||||
m_imp->get_assignments(result);
|
||||
m_imp->m_kernel.get_assignments(result);
|
||||
}
|
||||
|
||||
void kernel::get_relevant_labels(expr * cnstr, buffer<symbol> & result) {
|
||||
m_imp->get_relevant_labels(cnstr, result);
|
||||
m_imp->m_kernel.get_relevant_labels(cnstr, result);
|
||||
}
|
||||
|
||||
void kernel::get_relevant_labeled_literals(bool at_lbls, expr_ref_vector & result) {
|
||||
m_imp->get_relevant_labeled_literals(at_lbls, result);
|
||||
m_imp->m_kernel.get_relevant_labeled_literals(at_lbls, result);
|
||||
}
|
||||
|
||||
void kernel::get_relevant_literals(expr_ref_vector & result) {
|
||||
m_imp->get_relevant_literals(result);
|
||||
m_imp->m_kernel.get_relevant_literals(result);
|
||||
}
|
||||
|
||||
void kernel::get_guessed_literals(expr_ref_vector & result) {
|
||||
m_imp->get_guessed_literals(result);
|
||||
m_imp->m_kernel.get_guessed_literals(result);
|
||||
}
|
||||
|
||||
expr_ref kernel::next_cube() {
|
||||
return m_imp->next_cube();
|
||||
lookahead lh(m_imp->m_kernel);
|
||||
return lh.choose();
|
||||
}
|
||||
|
||||
expr_ref_vector kernel::cubes(unsigned depth) {
|
||||
return m_imp->cubes(depth);
|
||||
lookahead lh(m_imp->m_kernel);
|
||||
return lh.choose_rec(depth);
|
||||
}
|
||||
|
||||
std::ostream& kernel::display(std::ostream & out) const {
|
||||
|
@ -410,27 +210,26 @@ namespace smt {
|
|||
}
|
||||
|
||||
void kernel::collect_statistics(::statistics & st) const {
|
||||
m_imp->collect_statistics(st);
|
||||
m_imp->m_kernel.collect_statistics(st);
|
||||
}
|
||||
|
||||
void kernel::reset_statistics() {
|
||||
m_imp->reset_statistics();
|
||||
}
|
||||
|
||||
void kernel::display_statistics(std::ostream & out) const {
|
||||
m_imp->display_statistics(out);
|
||||
m_imp->m_kernel.display_statistics(out);
|
||||
}
|
||||
|
||||
void kernel::display_istatistics(std::ostream & out) const {
|
||||
m_imp->display_istatistics(out);
|
||||
m_imp->m_kernel.display_istatistics(out);
|
||||
}
|
||||
|
||||
bool kernel::canceled() const {
|
||||
return m_imp->canceled();
|
||||
return m_imp->m_kernel.get_cancel_flag();
|
||||
}
|
||||
|
||||
void kernel::updt_params(params_ref const & p) {
|
||||
return m_imp->updt_params(p);
|
||||
return m_imp->m_kernel.updt_params(p);
|
||||
}
|
||||
|
||||
void kernel::collect_param_descrs(param_descrs & d) {
|
||||
|
@ -442,11 +241,11 @@ namespace smt {
|
|||
}
|
||||
|
||||
void kernel::get_levels(ptr_vector<expr> const& vars, unsigned_vector& depth) {
|
||||
m_imp->get_levels(vars, depth);
|
||||
m_imp->m_kernel.get_levels(vars, depth);
|
||||
}
|
||||
|
||||
expr_ref_vector kernel::get_trail() {
|
||||
return m_imp->get_trail();
|
||||
return m_imp->m_kernel.get_trail();
|
||||
}
|
||||
|
||||
void kernel::user_propagate_init(
|
||||
|
@ -454,27 +253,31 @@ namespace smt {
|
|||
user_propagator::push_eh_t& push_eh,
|
||||
user_propagator::pop_eh_t& pop_eh,
|
||||
user_propagator::fresh_eh_t& fresh_eh) {
|
||||
m_imp->user_propagate_init(ctx, push_eh, pop_eh, fresh_eh);
|
||||
m_imp->m_kernel.user_propagate_init(ctx, push_eh, pop_eh, fresh_eh);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) {
|
||||
m_imp->user_propagate_register_fixed(fixed_eh);
|
||||
m_imp->m_kernel.user_propagate_register_fixed(fixed_eh);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_register_final(user_propagator::final_eh_t& final_eh) {
|
||||
m_imp->user_propagate_register_final(final_eh);
|
||||
m_imp->m_kernel.user_propagate_register_final(final_eh);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_register_eq(user_propagator::eq_eh_t& eq_eh) {
|
||||
m_imp->user_propagate_register_eq(eq_eh);
|
||||
m_imp->m_kernel.user_propagate_register_eq(eq_eh);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh) {
|
||||
m_imp->user_propagate_register_diseq(diseq_eh);
|
||||
m_imp->m_kernel.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned kernel::user_propagate_register(expr* e) {
|
||||
return m_imp->user_propagate_register(e);
|
||||
unsigned kernel::user_propagate_register_expr(expr* e) {
|
||||
return 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);
|
||||
}
|
||||
|
||||
};
|
|
@ -301,22 +301,19 @@ namespace smt {
|
|||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh);
|
||||
|
||||
|
||||
/**
|
||||
\brief register an expression to be tracked fro user propagation.
|
||||
*/
|
||||
unsigned user_propagate_register(expr* e);
|
||||
unsigned user_propagate_register_expr(expr* e);
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r);
|
||||
|
||||
/**
|
||||
\brief Return a reference to smt::context.
|
||||
This is a temporary hack to support user theories.
|
||||
TODO: remove this hack.
|
||||
We need to revamp user theories too.
|
||||
This breaks abstractions.
|
||||
|
||||
It is currently used by the opt-solver
|
||||
to access optimization services from arithmetic solvers
|
||||
and to ensure that the solver has registered PB theory solver.
|
||||
|
||||
This method breaks the abstraction barrier.
|
||||
|
||||
\warning We should not use this method
|
||||
\warning This method should not be used in new code.
|
||||
*/
|
||||
context & get_context();
|
||||
};
|
||||
|
|
|
@ -134,11 +134,11 @@ namespace smt {
|
|||
obj_map<expr, relevancy_ehs *> m_relevant_ehs;
|
||||
obj_map<expr, relevancy_ehs *> m_watches[2];
|
||||
struct eh_trail {
|
||||
enum kind { POS_WATCH, NEG_WATCH, HANDLER };
|
||||
enum class kind { POS_WATCH, NEG_WATCH, HANDLER };
|
||||
kind m_kind;
|
||||
expr * m_node;
|
||||
eh_trail(expr * n):m_kind(HANDLER), m_node(n) {}
|
||||
eh_trail(expr * n, bool val):m_kind(val ? POS_WATCH : NEG_WATCH), m_node(n) {}
|
||||
eh_trail(expr * n):m_kind(kind::HANDLER), m_node(n) {}
|
||||
eh_trail(expr * n, bool val):m_kind(val ? kind::POS_WATCH : kind::NEG_WATCH), m_node(n) {}
|
||||
kind get_kind() const { return m_kind; }
|
||||
expr * get_node() const { return m_node; }
|
||||
};
|
||||
|
@ -292,9 +292,9 @@ namespace smt {
|
|||
expr * n = t.get_node();
|
||||
relevancy_ehs * ehs;
|
||||
switch (t.get_kind()) {
|
||||
case eh_trail::POS_WATCH: ehs = get_watches(n, true); SASSERT(ehs); set_watches(n, true, ehs->tail()); break;
|
||||
case eh_trail::NEG_WATCH: ehs = get_watches(n, false); SASSERT(ehs); set_watches(n, false, ehs->tail()); break;
|
||||
case eh_trail::HANDLER: ehs = get_handlers(n); SASSERT(ehs); set_handlers(n, ehs->tail()); break;
|
||||
case eh_trail::kind::POS_WATCH: ehs = get_watches(n, true); SASSERT(ehs); set_watches(n, true, ehs->tail()); break;
|
||||
case eh_trail::kind::NEG_WATCH: ehs = get_watches(n, false); SASSERT(ehs); set_watches(n, false, ehs->tail()); break;
|
||||
case eh_trail::kind::HANDLER: ehs = get_handlers(n); SASSERT(ehs); set_handlers(n, ehs->tail()); break;
|
||||
default: UNREACHABLE(); break;
|
||||
}
|
||||
m.dec_ref(n);
|
||||
|
@ -378,9 +378,7 @@ namespace smt {
|
|||
break;
|
||||
case l_true: {
|
||||
expr * true_arg = nullptr;
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = n->get_arg(i);
|
||||
for (expr* arg : *n) {
|
||||
if (m_context.find_assignment(arg) == l_true) {
|
||||
if (is_relevant_core(arg))
|
||||
return;
|
||||
|
@ -402,9 +400,7 @@ namespace smt {
|
|||
switch (val) {
|
||||
case l_false: {
|
||||
expr * false_arg = nullptr;
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = n->get_arg(i);
|
||||
for (expr* arg : *n) {
|
||||
if (m_context.find_assignment(arg) == l_false) {
|
||||
if (is_relevant_core(arg))
|
||||
return;
|
||||
|
|
|
@ -643,8 +643,8 @@ namespace smt {
|
|||
// It destroys the existing patterns.
|
||||
// m_params.m_macro_finder = true;
|
||||
|
||||
if (m_params.m_ng_lift_ite == LI_NONE)
|
||||
m_params.m_ng_lift_ite = LI_CONSERVATIVE;
|
||||
if (m_params.m_ng_lift_ite == lift_ite_kind::LI_NONE)
|
||||
m_params.m_ng_lift_ite = lift_ite_kind::LI_CONSERVATIVE;
|
||||
TRACE("setup", tout << "max_eager_multipatterns: " << m_params.m_qi_max_eager_multipatterns << "\n";);
|
||||
m_context.register_plugin(alloc(smt::theory_i_arith, m_context));
|
||||
setup_arrays();
|
||||
|
@ -668,8 +668,8 @@ namespace smt {
|
|||
m_params.m_qi_lazy_threshold = 20;
|
||||
//
|
||||
m_params.m_macro_finder = true;
|
||||
if (m_params.m_ng_lift_ite == LI_NONE)
|
||||
m_params.m_ng_lift_ite = LI_CONSERVATIVE;
|
||||
if (m_params.m_ng_lift_ite == lift_ite_kind::LI_NONE)
|
||||
m_params.m_ng_lift_ite = lift_ite_kind::LI_CONSERVATIVE;
|
||||
m_params.m_pi_max_multi_patterns = 10; //<< it was used for SMT-COMP
|
||||
m_params.m_array_lazy_ieq = true;
|
||||
m_params.m_array_lazy_ieq_delay = 4;
|
||||
|
|
|
@ -124,7 +124,7 @@ namespace {
|
|||
smt_params m_smt_params_save;
|
||||
|
||||
void push_params() override {
|
||||
m_params_save = params_ref();
|
||||
m_params_save.reset();
|
||||
m_params_save.copy(solver::get_params());
|
||||
m_smt_params_save = m_smt_params;
|
||||
}
|
||||
|
@ -200,7 +200,6 @@ namespace {
|
|||
return m_context.check(num_assumptions, assumptions);
|
||||
}
|
||||
|
||||
|
||||
lbool check_sat_cc_core(expr_ref_vector const& cube, vector<expr_ref_vector> const& clauses) override {
|
||||
return m_context.check(cube, clauses);
|
||||
}
|
||||
|
@ -237,8 +236,12 @@ namespace {
|
|||
m_context.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register(expr* e) override {
|
||||
return m_context.user_propagate_register(e);
|
||||
unsigned user_propagate_register_expr(expr* e) override {
|
||||
return 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);
|
||||
}
|
||||
|
||||
struct scoped_minimize_core {
|
||||
|
|
|
@ -615,6 +615,12 @@ namespace smt {
|
|||
bool is_relevant_and_shared(enode * n) const;
|
||||
|
||||
bool assume_eq(enode * n1, enode * n2);
|
||||
|
||||
|
||||
/**
|
||||
* \brief theory plugin for fixed values.
|
||||
*/
|
||||
virtual bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector & explain) { return false; }
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -127,7 +127,8 @@ public:
|
|||
|
||||
scoped_init_ctx(smt_tactic & o, ast_manager & m):m_owner(o) {
|
||||
m_params = o.fparams();
|
||||
m_params_ref = o.params();
|
||||
m_params_ref.reset();
|
||||
m_params_ref.append(o.params());
|
||||
smt::kernel * new_ctx = alloc(smt::kernel, m, m_params, m_params_ref);
|
||||
TRACE("smt_tactic", tout << "logic: " << o.m_logic << "\n";);
|
||||
new_ctx->set_logic(o.m_logic);
|
||||
|
@ -319,15 +320,21 @@ public:
|
|||
user_propagator::final_eh_t m_final_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;
|
||||
|
||||
expr_ref_vector m_vars;
|
||||
unsigned_vector m_var2internal;
|
||||
unsigned_vector m_internal2var;
|
||||
unsigned_vector m_limit;
|
||||
|
||||
|
||||
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 {
|
||||
|
@ -403,19 +410,48 @@ public:
|
|||
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;
|
||||
m_ctx->user_propagate_init(m_user_ctx, m_push_eh, m_pop_eh, m_fresh_eh);
|
||||
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();
|
||||
|
||||
unsigned i = 0;
|
||||
for (expr* v : m_vars) {
|
||||
unsigned j = m_ctx->user_propagate_register(v);
|
||||
unsigned j = m_ctx->user_propagate_register_expr(v);
|
||||
m_var2internal.setx(i, j, 0);
|
||||
m_internal2var.setx(j, i, 0);
|
||||
++i;
|
||||
|
@ -429,6 +465,7 @@ public:
|
|||
m_final_eh = nullptr;
|
||||
m_eq_eh = nullptr;
|
||||
m_diseq_eh = nullptr;
|
||||
m_created_eh = nullptr;
|
||||
}
|
||||
|
||||
void user_propagate_init(
|
||||
|
@ -459,10 +496,14 @@ public:
|
|||
m_diseq_eh = diseq_eh;
|
||||
}
|
||||
|
||||
unsigned user_propagate_register(expr* e) override {
|
||||
unsigned 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 {
|
||||
m_created_eh = created_eh;
|
||||
}
|
||||
};
|
||||
|
||||
static tactic * mk_seq_smt_tactic(ast_manager& m, params_ref const & p) {
|
||||
|
|
|
@ -50,7 +50,7 @@ struct unit_subsumption_tactic : public tactic {
|
|||
}
|
||||
|
||||
void updt_params(params_ref const& p) override {
|
||||
m_params = p;
|
||||
m_params.append(p);
|
||||
// m_context.updt_params(p); does not exist.
|
||||
}
|
||||
|
||||
|
|
|
@ -519,6 +519,21 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
bool theory_bv::is_fixed_propagated(theory_var v, expr_ref& val, literal_vector& lits) {
|
||||
numeral r;
|
||||
enode* n = get_enode(v);
|
||||
if (!get_fixed_value(v, r))
|
||||
return false;
|
||||
val = m_util.mk_numeral(r, n->get_sort());
|
||||
for (literal b : m_bits[v]) {
|
||||
if (ctx.get_assignment(b) == l_false)
|
||||
b.neg();
|
||||
lits.push_back(b);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool theory_bv::get_fixed_value(theory_var v, numeral & result) const {
|
||||
result.reset();
|
||||
unsigned i = 0;
|
||||
|
|
|
@ -282,6 +282,7 @@ namespace smt {
|
|||
void collect_statistics(::statistics & st) const override;
|
||||
|
||||
bool get_fixed_value(app* x, numeral & result) const;
|
||||
bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector& explain) override;
|
||||
|
||||
bool check_assignment(theory_var v);
|
||||
bool check_invariant();
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace smt {
|
|||
ctx.internalize(arg, false);
|
||||
}
|
||||
if (!ctx.e_internalized(atom)) {
|
||||
ctx.mk_enode(atom, false, true, false);
|
||||
ctx.mk_enode(atom, false, true, true);
|
||||
}
|
||||
if (!ctx.b_internalized(atom)) {
|
||||
bool_var v = ctx.mk_bool_var(atom);
|
||||
|
@ -214,7 +214,7 @@ namespace smt {
|
|||
void theory_recfun::assign_eh(bool_var v, bool is_true) {
|
||||
expr* e = ctx.bool_var2expr(v);
|
||||
if (is_true && u().is_case_pred(e)) {
|
||||
TRACEFN("assign_case_pred_true " << mk_pp(e, m));
|
||||
TRACEFN("assign_case_pred_true " << v << " " << mk_pp(e, m));
|
||||
// body-expand
|
||||
push_body_expand(e);
|
||||
}
|
||||
|
@ -343,6 +343,7 @@ namespace smt {
|
|||
activate_guard(pred_applied, guards);
|
||||
}
|
||||
|
||||
TRACEFN("assert core " << preds);
|
||||
// the disjunction of branches is asserted
|
||||
// to close the available cases.
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ final_check_status theory_seq::final_check_eh() {
|
|||
TRACEFIN("propagate_contains");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (fixed_length(true)) {
|
||||
if (check_fixed_length(true, false)) {
|
||||
++m_stats.m_fixed_length;
|
||||
TRACEFIN("zero_length");
|
||||
return FC_CONTINUE;
|
||||
|
@ -359,7 +359,7 @@ final_check_status theory_seq::final_check_eh() {
|
|||
TRACEFIN("split_based_on_length");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (fixed_length()) {
|
||||
if (check_fixed_length(false, false)) {
|
||||
++m_stats.m_fixed_length;
|
||||
TRACEFIN("fixed_length");
|
||||
return FC_CONTINUE;
|
||||
|
@ -413,6 +413,11 @@ final_check_status theory_seq::final_check_eh() {
|
|||
TRACEFIN("branch_itos");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (check_fixed_length(false, true)) {
|
||||
++m_stats.m_fixed_length;
|
||||
TRACEFIN("fixed_length");
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
if (m_unhandled_expr) {
|
||||
TRACEFIN("give_up");
|
||||
TRACE("seq", tout << "unhandled: " << mk_pp(m_unhandled_expr, m) << "\n";);
|
||||
|
@ -461,18 +466,18 @@ bool theory_seq::enforce_length(expr_ref_vector const& es, vector<rational> & le
|
|||
}
|
||||
|
||||
|
||||
bool theory_seq::fixed_length(bool is_zero) {
|
||||
bool theory_seq::check_fixed_length(bool is_zero, bool check_long_strings) {
|
||||
bool found = false;
|
||||
for (unsigned i = 0; i < m_length.size(); ++i) {
|
||||
expr* e = m_length.get(i);
|
||||
if (fixed_length(e, is_zero)) {
|
||||
if (fixed_length(e, is_zero, check_long_strings)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool theory_seq::fixed_length(expr* len_e, bool is_zero) {
|
||||
bool theory_seq::fixed_length(expr* len_e, bool is_zero, bool check_long_strings) {
|
||||
rational lo, hi;
|
||||
expr* e = nullptr;
|
||||
VERIFY(m_util.str.is_length(len_e, e));
|
||||
|
@ -493,12 +498,21 @@ bool theory_seq::fixed_length(expr* len_e, bool is_zero) {
|
|||
|
||||
expr_ref seq(e, m), head(m), tail(m);
|
||||
|
||||
|
||||
TRACE("seq", tout << "Fixed: " << mk_bounded_pp(e, m, 2) << " " << lo << "\n";);
|
||||
literal a = mk_eq(len_e, m_autil.mk_numeral(lo, true), false);
|
||||
if (ctx.get_assignment(a) == l_false)
|
||||
return false;
|
||||
|
||||
if (!check_long_strings && lo > 20 && !is_zero)
|
||||
return false;
|
||||
|
||||
if (lo.is_zero()) {
|
||||
seq = m_util.str.mk_empty(e->get_sort());
|
||||
}
|
||||
else if (!is_zero) {
|
||||
unsigned _lo = lo.get_unsigned();
|
||||
expr_ref_vector elems(m);
|
||||
expr_ref_vector elems(m);
|
||||
for (unsigned j = 0; j < _lo; ++j) {
|
||||
m_sk.decompose(seq, head, tail);
|
||||
elems.push_back(head);
|
||||
|
@ -506,10 +520,6 @@ bool theory_seq::fixed_length(expr* len_e, bool is_zero) {
|
|||
}
|
||||
seq = mk_concat(elems.size(), elems.data());
|
||||
}
|
||||
TRACE("seq", tout << "Fixed: " << mk_bounded_pp(e, m, 2) << " " << lo << "\n";);
|
||||
literal a = mk_eq(len_e, m_autil.mk_numeral(lo, true), false);
|
||||
if (ctx.get_assignment(a) == l_false)
|
||||
return false;
|
||||
literal b = mk_seq_eq(seq, e);
|
||||
if (ctx.get_assignment(b) == l_true)
|
||||
return false;
|
||||
|
@ -2636,6 +2646,9 @@ void theory_seq::deque_axiom(expr* n) {
|
|||
else if (m_util.str.is_replace(n)) {
|
||||
m_ax.add_replace_axiom(n);
|
||||
}
|
||||
else if (m_util.str.is_replace_all(n)) {
|
||||
m_ax.add_replace_all_axiom(n);
|
||||
}
|
||||
else if (m_util.str.is_extract(n)) {
|
||||
m_ax.add_extract_axiom(n);
|
||||
}
|
||||
|
@ -2873,7 +2886,7 @@ void theory_seq::add_axiom(literal_vector & lits) {
|
|||
for (literal lit : lits)
|
||||
ctx.mark_as_relevant(lit);
|
||||
|
||||
IF_VERBOSE(10, verbose_stream() << "ax ";
|
||||
IF_VERBOSE(10, verbose_stream() << "ax";
|
||||
for (literal l : lits) ctx.display_literal_smt2(verbose_stream() << " ", l);
|
||||
verbose_stream() << "\n");
|
||||
m_new_propagation = true;
|
||||
|
@ -3014,10 +3027,6 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
|
|||
if (is_true)
|
||||
m_regex.propagate_is_empty(lit);
|
||||
}
|
||||
else if (m_sk.is_is_non_empty(e)) {
|
||||
if (is_true)
|
||||
m_regex.propagate_is_non_empty(lit);
|
||||
}
|
||||
else if (m_sk.is_eq(e, e1, e2)) {
|
||||
if (is_true) {
|
||||
propagate_eq(lit, e1, e2, true);
|
||||
|
@ -3037,6 +3046,10 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
|
|||
propagate_length_limit(e);
|
||||
}
|
||||
}
|
||||
else if (m_sk.is_is_non_empty(e)) {
|
||||
if (is_true)
|
||||
m_regex.propagate_is_non_empty(lit);
|
||||
}
|
||||
else if (m_util.str.is_lt(e) || m_util.str.is_le(e)) {
|
||||
m_lts.push_back(e);
|
||||
}
|
||||
|
@ -3180,6 +3193,7 @@ void theory_seq::relevant_eh(app* n) {
|
|||
m_util.str.is_to_code(n) ||
|
||||
m_util.str.is_unit(n) ||
|
||||
m_util.str.is_length(n) ||
|
||||
/* m_util.str.is_replace_all(n) || uncomment to enable axiomatization */
|
||||
m_util.str.is_le(n)) {
|
||||
enque_axiom(n);
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ namespace smt {
|
|||
replay_fixed_length(ast_manager& m, expr* e) : m_e(e, m) {}
|
||||
~replay_fixed_length() override {}
|
||||
void operator()(theory_seq& th) override {
|
||||
th.fixed_length(m_e);
|
||||
th.fixed_length(m_e, false, false);
|
||||
m_e.reset();
|
||||
}
|
||||
};
|
||||
|
@ -436,8 +436,8 @@ namespace smt {
|
|||
bool check_length_coherence();
|
||||
bool check_length_coherence0(expr* e);
|
||||
bool check_length_coherence(expr* e);
|
||||
bool fixed_length(bool is_zero = false);
|
||||
bool fixed_length(expr* e, bool is_zero);
|
||||
bool check_fixed_length(bool is_zero, bool check_long_strings);
|
||||
bool fixed_length(expr* e, bool is_zero, bool check_long_strings);
|
||||
bool branch_variable_eq(depeq const& e);
|
||||
bool branch_binary_variable(depeq const& e);
|
||||
bool can_align_from_lhs(expr_ref_vector const& ls, expr_ref_vector const& rs);
|
||||
|
|
|
@ -23,7 +23,7 @@ Author:
|
|||
using namespace smt;
|
||||
|
||||
theory_user_propagator::theory_user_propagator(context& ctx):
|
||||
theory(ctx, ctx.get_manager().mk_family_id("user_propagator"))
|
||||
theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name()))
|
||||
{}
|
||||
|
||||
theory_user_propagator::~theory_user_propagator() {
|
||||
|
@ -40,11 +40,31 @@ void theory_user_propagator::force_push() {
|
|||
|
||||
unsigned theory_user_propagator::add_expr(expr* e) {
|
||||
force_push();
|
||||
expr_ref r(m);
|
||||
ctx.get_rewriter()(e, r);
|
||||
if (r != e) {
|
||||
r = m.mk_fresh_const("aux-expr", e->get_sort());
|
||||
expr_ref eq(m.mk_eq(r, e), m);
|
||||
ctx.assert_expr(eq);
|
||||
ctx.internalize_assertions();
|
||||
e = r;
|
||||
ctx.mark_as_relevant(eq.get());
|
||||
}
|
||||
enode* n = ensure_enode(e);
|
||||
if (is_attached_to_var(n))
|
||||
return n->get_th_var(get_id());
|
||||
theory_var v = mk_var(n);
|
||||
if (m.is_bool(e) && !ctx.b_internalized(e)) {
|
||||
bool_var bv = ctx.mk_bool_var(e);
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
ctx.set_enode_flag(bv, true);
|
||||
}
|
||||
SASSERT(!m.is_bool(e) || ctx.b_internalized(e));
|
||||
|
||||
ctx.attach_th_var(n, this, v);
|
||||
literal_vector explain;
|
||||
if (ctx.is_fixed(n, r, explain))
|
||||
m_prop.push_back(prop_info(explain, v, r));
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -118,54 +138,66 @@ bool theory_user_propagator::can_propagate() {
|
|||
return m_qhead < m_prop.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 (auto const& p : prop.m_eqs)
|
||||
m_eqs.push_back(enode_pair(get_enode(p.first), get_enode(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 (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");
|
||||
|
||||
if (m.is_false(prop.m_conseq)) {
|
||||
js = ctx.mk_justification(
|
||||
ext_theory_conflict_justification(
|
||||
get_id(), ctx.get_region(), m_lits.size(), m_lits.data(), m_eqs.size(), m_eqs.data(), 0, nullptr));
|
||||
ctx.set_conflict(js);
|
||||
}
|
||||
else {
|
||||
for (auto& lit : m_lits)
|
||||
lit.neg();
|
||||
for (auto const& [a,b] : m_eqs)
|
||||
m_lits.push_back(~mk_eq(a->get_expr(), b->get_expr(), false));
|
||||
|
||||
literal lit;
|
||||
if (has_quantifiers(prop.m_conseq)) {
|
||||
expr_ref fn(m.mk_fresh_const("aux-literal", m.mk_bool_sort()), m);
|
||||
expr_ref eq(m.mk_eq(fn, prop.m_conseq), m);
|
||||
ctx.assert_expr(eq);
|
||||
ctx.internalize_assertions();
|
||||
lit = mk_literal(fn);
|
||||
}
|
||||
else
|
||||
lit = mk_literal(prop.m_conseq);
|
||||
ctx.mark_as_relevant(lit);
|
||||
m_lits.push_back(lit);
|
||||
ctx.mk_th_lemma(get_id(), m_lits);
|
||||
TRACE("user_propagate", ctx.display(tout););
|
||||
}
|
||||
}
|
||||
|
||||
void theory_user_propagator::propagate_new_fixed(prop_info const& prop) {
|
||||
new_fixed_eh(prop.m_var, prop.m_conseq, prop.m_lits.size(), prop.m_lits.data());
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
return;
|
||||
force_push();
|
||||
unsigned qhead = m_qhead;
|
||||
justification* js;
|
||||
while (qhead < m_prop.size() && !ctx.inconsistent()) {
|
||||
auto const& prop = m_prop[qhead];
|
||||
m_lits.reset();
|
||||
m_eqs.reset();
|
||||
for (unsigned id : prop.m_ids)
|
||||
m_lits.append(m_id2justification[id]);
|
||||
for (auto const& p : prop.m_eqs)
|
||||
m_eqs.push_back(enode_pair(get_enode(p.first), get_enode(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 (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");
|
||||
|
||||
if (m.is_false(prop.m_conseq)) {
|
||||
js = ctx.mk_justification(
|
||||
ext_theory_conflict_justification(
|
||||
get_id(), ctx.get_region(), m_lits.size(), m_lits.data(), m_eqs.size(), m_eqs.data(), 0, nullptr));
|
||||
ctx.set_conflict(js);
|
||||
}
|
||||
else {
|
||||
for (auto& lit : m_lits)
|
||||
lit.neg();
|
||||
for (auto const& [a,b] : m_eqs)
|
||||
m_lits.push_back(~mk_eq(a->get_expr(), b->get_expr(), false));
|
||||
|
||||
literal lit;
|
||||
if (has_quantifiers(prop.m_conseq)) {
|
||||
expr_ref fn(m.mk_fresh_const("aux-literal", m.mk_bool_sort()), m);
|
||||
expr_ref eq(m.mk_eq(fn, prop.m_conseq), m);
|
||||
ctx.assert_expr(eq);
|
||||
ctx.internalize_assertions();
|
||||
lit = mk_literal(fn);
|
||||
}
|
||||
else
|
||||
lit = mk_literal(prop.m_conseq);
|
||||
ctx.mark_as_relevant(lit);
|
||||
m_lits.push_back(lit);
|
||||
ctx.mk_th_lemma(get_id(), m_lits);
|
||||
TRACE("user_propagate", ctx.display(tout););
|
||||
}
|
||||
if (prop.m_var == null_theory_var)
|
||||
propagate_consequence(prop);
|
||||
else
|
||||
propagate_new_fixed(prop);
|
||||
++m_stats.m_num_propagations;
|
||||
++qhead;
|
||||
}
|
||||
|
@ -173,6 +205,26 @@ void theory_user_propagator::propagate() {
|
|||
m_qhead = qhead;
|
||||
}
|
||||
|
||||
|
||||
bool theory_user_propagator::internalize_atom(app* atom, bool gate_ctx) {
|
||||
return internalize_term(atom);
|
||||
}
|
||||
|
||||
bool theory_user_propagator::internalize_term(app* term) {
|
||||
for (auto arg : *term)
|
||||
ensure_enode(arg);
|
||||
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))
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
void theory_user_propagator::collect_statistics(::statistics & st) const {
|
||||
st.update("user-propagations", m_stats.m_num_propagations);
|
||||
st.update("user-watched", get_num_vars());
|
||||
|
|
|
@ -30,16 +30,24 @@ namespace smt {
|
|||
class theory_user_propagator : public theory, public user_propagator::callback {
|
||||
|
||||
struct prop_info {
|
||||
unsigned_vector m_ids;
|
||||
expr_ref m_conseq;
|
||||
unsigned_vector m_ids;
|
||||
expr_ref m_conseq;
|
||||
svector<std::pair<unsigned, unsigned>> m_eqs;
|
||||
prop_info(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr_ref const& c):
|
||||
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):
|
||||
m_ids(num_fixed, fixed_ids),
|
||||
m_conseq(c)
|
||||
{
|
||||
m_conseq(c) {
|
||||
for (unsigned i = 0; i < num_eqs; ++i)
|
||||
m_eqs.push_back(std::make_pair(eq_lhs[i], eq_rhs[i]));
|
||||
}
|
||||
|
||||
prop_info(literal_vector const& lits, theory_var v, expr_ref const& val):
|
||||
m_conseq(val),
|
||||
m_lits(lits),
|
||||
m_var(v) {}
|
||||
|
||||
};
|
||||
|
||||
struct stats {
|
||||
|
@ -56,6 +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::context_obj* m_api_context = nullptr;
|
||||
unsigned m_qhead = 0;
|
||||
uint_set m_fixed;
|
||||
|
@ -69,6 +79,9 @@ namespace smt {
|
|||
|
||||
void force_push();
|
||||
|
||||
void propagate_consequence(prop_info const& prop);
|
||||
void propagate_new_fixed(prop_info const& prop);
|
||||
|
||||
public:
|
||||
theory_user_propagator(context& ctx);
|
||||
|
||||
|
@ -94,6 +107,7 @@ namespace smt {
|
|||
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; }
|
||||
|
||||
bool has_fixed() const { return (bool)m_fixed_eh; }
|
||||
|
||||
|
@ -103,8 +117,8 @@ namespace smt {
|
|||
void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits);
|
||||
|
||||
theory * mk_fresh(context * new_ctx) override;
|
||||
bool internalize_atom(app * atom, bool gate_ctx) override { UNREACHABLE(); return false; }
|
||||
bool internalize_term(app * term) override { UNREACHABLE(); return false; }
|
||||
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); }
|
||||
bool use_diseqs() const override { return ((bool)m_diseq_eh); }
|
||||
|
@ -119,7 +133,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 false; }
|
||||
bool include_func_interp(func_decl* f) override { return true; }
|
||||
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