3
0
Fork 0
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:
Nikolaj Bjorner 2022-01-26 06:19:24 +01:00
commit 3f5df04dc4
252 changed files with 5792 additions and 2553 deletions

View file

@ -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);

View file

@ -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),

View file

@ -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();

View file

@ -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);
}

View file

@ -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'),

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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); }

View file

@ -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);

View file

@ -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););

View file

@ -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);
};

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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";);

View file

@ -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);
}
};

View file

@ -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();
};

View file

@ -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;

View file

@ -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;

View file

@ -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 {

View file

@ -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; }
};
};

View file

@ -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) {

View file

@ -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.
}

View file

@ -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;

View file

@ -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();

View file

@ -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.

View file

@ -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);
}

View file

@ -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);

View file

@ -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());

View file

@ -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 {}