mirror of
https://github.com/Z3Prover/z3
synced 2025-10-07 00:11:55 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
e5e79c1d4b
398 changed files with 24548 additions and 4983 deletions
|
@ -78,7 +78,7 @@ namespace {
|
|||
|
||||
public:
|
||||
unsigned char operator()(func_decl * lbl) {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
if (lbl_id >= m_lbl2hash.size())
|
||||
m_lbl2hash.resize(lbl_id + 1, -1);
|
||||
if (m_lbl2hash[lbl_id] == -1) {
|
||||
|
@ -1952,7 +1952,7 @@ namespace {
|
|||
m_args[i] = m_registers[pc->m_iregs[i]]->get_root();
|
||||
SASSERT(n != 0);
|
||||
do {
|
||||
if (n->get_decl() == f) {
|
||||
if (n->get_decl() == f && n->get_num_args() == num_args) {
|
||||
unsigned i = 0;
|
||||
for (; i < num_args; i++) {
|
||||
if (n->get_arg(i)->get_root() != m_args[i])
|
||||
|
@ -2906,7 +2906,7 @@ namespace {
|
|||
SASSERT(first_idx < mp->get_num_args());
|
||||
app * p = to_app(mp->get_arg(first_idx));
|
||||
func_decl * lbl = p->get_decl();
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
m_trees.reserve(lbl_id+1, nullptr);
|
||||
if (m_trees[lbl_id] == nullptr) {
|
||||
m_trees[lbl_id] = m_compiler.mk_tree(qa, mp, first_idx, false);
|
||||
|
@ -2935,7 +2935,7 @@ namespace {
|
|||
}
|
||||
|
||||
code_tree * get_code_tree_for(func_decl * lbl) const {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
if (lbl_id < m_trees.size())
|
||||
return m_trees[lbl_id];
|
||||
else
|
||||
|
@ -3165,11 +3165,11 @@ namespace {
|
|||
}
|
||||
|
||||
bool is_plbl(func_decl * lbl) const {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
return lbl_id < m_is_plbl.size() && m_is_plbl[lbl_id];
|
||||
}
|
||||
bool is_clbl(func_decl * lbl) const {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
return lbl_id < m_is_clbl.size() && m_is_clbl[lbl_id];
|
||||
}
|
||||
|
||||
|
@ -3182,7 +3182,7 @@ namespace {
|
|||
}
|
||||
|
||||
void update_clbls(func_decl * lbl) {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
m_is_clbl.reserve(lbl_id+1, false);
|
||||
TRACE("trigger_bug", tout << "update_clbls: " << lbl->get_name() << " is already clbl: " << m_is_clbl[lbl_id] << "\n";);
|
||||
TRACE("mam_bug", tout << "update_clbls: " << lbl->get_name() << " is already clbl: " << m_is_clbl[lbl_id] << "\n";);
|
||||
|
@ -3222,7 +3222,7 @@ namespace {
|
|||
}
|
||||
|
||||
void update_plbls(func_decl * lbl) {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
m_is_plbl.reserve(lbl_id+1, false);
|
||||
TRACE("trigger_bug", tout << "update_plbls: " << lbl->get_name() << " is already plbl: " << m_is_plbl[lbl_id] << ", lbl_id: " << lbl_id << "\n";
|
||||
tout << "mam: " << this << "\n";);
|
||||
|
@ -3744,7 +3744,7 @@ namespace {
|
|||
app * p = to_app(mp->get_arg(0));
|
||||
func_decl * lbl = p->get_decl();
|
||||
if (m_context.get_num_enodes_of(lbl) > 0) {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
m_tmp_trees.reserve(lbl_id+1, 0);
|
||||
if (m_tmp_trees[lbl_id] == 0) {
|
||||
m_tmp_trees[lbl_id] = m_compiler.mk_tree(qa, mp, 0, false);
|
||||
|
@ -3757,7 +3757,7 @@ namespace {
|
|||
}
|
||||
|
||||
for (func_decl * lbl : m_tmp_trees_to_delete) {
|
||||
unsigned lbl_id = lbl->get_decl_id();
|
||||
unsigned lbl_id = lbl->get_small_id();
|
||||
code_tree * tmp_tree = m_tmp_trees[lbl_id];
|
||||
SASSERT(tmp_tree != 0);
|
||||
SASSERT(m_context.get_num_enodes_of(lbl) > 0);
|
||||
|
@ -3963,7 +3963,7 @@ namespace {
|
|||
unsigned h = m_lbl_hasher(lbl);
|
||||
TRACE("trigger_bug", tout << "lbl: " << lbl->get_name() << " is_clbl(lbl): " << is_clbl(lbl)
|
||||
<< ", is_plbl(lbl): " << is_plbl(lbl) << ", h: " << h << "\n";
|
||||
tout << "lbl_id: " << lbl->get_decl_id() << "\n";);
|
||||
tout << "lbl_id: " << lbl->get_small_id() << "\n";);
|
||||
if (is_clbl(lbl))
|
||||
update_lbls(n, h);
|
||||
if (is_plbl(lbl))
|
||||
|
|
|
@ -232,6 +232,7 @@ namespace smt {
|
|||
expr_ref s_instance(m);
|
||||
proof_ref pr(m);
|
||||
m_context.get_rewriter()(instance, s_instance, pr);
|
||||
|
||||
TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << s_instance << "\n";);
|
||||
if (m.is_true(s_instance)) {
|
||||
TRACE("checker", tout << "reduced to true, before:\n" << mk_ll_pp(instance, m););
|
||||
|
|
|
@ -42,6 +42,7 @@ Revision History:
|
|||
#include "smt/smt_model_finder.h"
|
||||
#include "smt/smt_parallel.h"
|
||||
#include "smt/smt_arith_value.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -1847,24 +1848,30 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
bool_var var;
|
||||
lbool phase = l_undef;
|
||||
m_case_split_queue->next_case_split(var, phase);
|
||||
bool is_pos;
|
||||
bool used_queue = false;
|
||||
|
||||
if (!has_split_candidate(var, is_pos)) {
|
||||
lbool phase = l_undef;
|
||||
m_case_split_queue->next_case_split(var, phase);
|
||||
used_queue = true;
|
||||
if (var == null_bool_var)
|
||||
return false;
|
||||
|
||||
if (var == null_bool_var) {
|
||||
return false;
|
||||
TRACE_CODE({
|
||||
static unsigned counter = 0;
|
||||
counter++;
|
||||
if (counter % 100 == 0) {
|
||||
TRACE("activity_profile",
|
||||
for (unsigned i=0; i<get_num_bool_vars(); i++) {
|
||||
tout << get_activity(i) << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
}});
|
||||
|
||||
is_pos = guess(var, phase);
|
||||
}
|
||||
|
||||
TRACE_CODE({
|
||||
static unsigned counter = 0;
|
||||
counter++;
|
||||
if (counter % 100 == 0) {
|
||||
TRACE("activity_profile",
|
||||
for (unsigned i=0; i<get_num_bool_vars(); i++) {
|
||||
tout << get_activity(i) << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
}});
|
||||
|
||||
m_stats.m_num_decisions++;
|
||||
|
||||
push_scope();
|
||||
|
@ -1872,13 +1879,13 @@ namespace smt {
|
|||
|
||||
TRACE("decide_detail", tout << mk_pp(bool_var2expr(var), m) << "\n";);
|
||||
|
||||
bool is_pos = guess(var, phase);
|
||||
literal l(var, false);
|
||||
|
||||
bool_var original_choice = var;
|
||||
|
||||
if (decide_user_interference(var, is_pos)) {
|
||||
m_case_split_queue->unassign_var_eh(original_choice);
|
||||
if (used_queue)
|
||||
m_case_split_queue->unassign_var_eh(original_choice);
|
||||
l = literal(var, false);
|
||||
}
|
||||
|
||||
|
@ -2904,8 +2911,14 @@ namespace smt {
|
|||
return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_family_id()) != null_theory_var;
|
||||
}
|
||||
|
||||
bool context::has_split_candidate(bool_var& var, bool& is_pos) {
|
||||
if (!m_user_propagator)
|
||||
return false;
|
||||
return m_user_propagator->get_case_split(var, is_pos);
|
||||
}
|
||||
|
||||
bool context::decide_user_interference(bool_var& var, bool& is_pos) {
|
||||
if (!m_user_propagator || !m_user_propagator->has_decide())
|
||||
if (!m_user_propagator)
|
||||
return false;
|
||||
bool_var old = var;
|
||||
m_user_propagator->decide(var, is_pos);
|
||||
|
@ -3168,7 +3181,7 @@ namespace smt {
|
|||
}
|
||||
else {
|
||||
expr_ref proxy(m), fml(m);
|
||||
proxy = m.mk_fresh_const("proxy", m.mk_bool_sort());
|
||||
proxy = m.mk_fresh_const(symbol(), m.mk_bool_sort());
|
||||
fml = m.mk_implies(proxy, e);
|
||||
m_asserted_formulas.assert_expr(fml);
|
||||
asm2proxy.push_back(std::make_pair(e, proxy));
|
||||
|
@ -3737,15 +3750,12 @@ namespace smt {
|
|||
|
||||
reset_model();
|
||||
|
||||
if (m_last_search_failure != OK) {
|
||||
if (m_last_search_failure != OK)
|
||||
return false;
|
||||
}
|
||||
if (status == l_false) {
|
||||
if (status == l_false)
|
||||
return false;
|
||||
}
|
||||
if (status == l_true && !m_qmanager->has_quantifiers() && !m_has_lambda) {
|
||||
if (status == l_true && !m_qmanager->has_quantifiers() && !has_lambda())
|
||||
return false;
|
||||
}
|
||||
if (status == l_true && m_qmanager->has_quantifiers()) {
|
||||
// possible outcomes DONE l_true, DONE l_undef, CONTINUE
|
||||
mk_proto_model();
|
||||
|
@ -3766,7 +3776,7 @@ namespace smt {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (status == l_true && m_has_lambda) {
|
||||
if (status == l_true && has_lambda()) {
|
||||
m_last_search_failure = LAMBDAS;
|
||||
status = l_undef;
|
||||
return false;
|
||||
|
@ -3946,8 +3956,7 @@ namespace smt {
|
|||
if (m_fparams.m_model_on_final_check) {
|
||||
mk_proto_model();
|
||||
model_pp(std::cout, *m_proto_model);
|
||||
std::cout << "END_OF_MODEL\n";
|
||||
std::cout.flush();
|
||||
std::cout << "END_OF_MODEL" << std::endl;
|
||||
}
|
||||
|
||||
m_stats.m_num_final_checks++;
|
||||
|
@ -4010,7 +4019,7 @@ namespace smt {
|
|||
TRACE("final_check_step", tout << "RESULT final_check: " << result << "\n";);
|
||||
if (result == FC_GIVEUP && f != OK)
|
||||
m_last_search_failure = f;
|
||||
if (result == FC_DONE && m_has_lambda) {
|
||||
if (result == FC_DONE && has_lambda()) {
|
||||
m_last_search_failure = LAMBDAS;
|
||||
result = FC_GIVEUP;
|
||||
}
|
||||
|
@ -4468,9 +4477,8 @@ namespace smt {
|
|||
return false;
|
||||
}
|
||||
case 1: {
|
||||
if (m_qmanager->is_shared(n)) {
|
||||
if (m_qmanager->is_shared(n) && !m.is_lambda_def(n->get_expr()) && !m_lambdas.contains(n))
|
||||
return true;
|
||||
}
|
||||
|
||||
// the variable is shared if the equivalence class of n
|
||||
// contains a parent application.
|
||||
|
@ -4482,6 +4490,8 @@ namespace smt {
|
|||
app* p = parent->get_expr();
|
||||
family_id fid = p->get_family_id();
|
||||
if (fid != th_id && fid != m.get_basic_family_id()) {
|
||||
if (is_beta_redex(parent, n))
|
||||
continue;
|
||||
TRACE("is_shared", tout << enode_pp(n, *this)
|
||||
<< "\nis shared because of:\n"
|
||||
<< enode_pp(parent, *this) << "\n";);
|
||||
|
@ -4522,6 +4532,12 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
bool context::is_beta_redex(enode* p, enode* n) const {
|
||||
family_id th_id = p->get_expr()->get_family_id();
|
||||
theory * th = get_theory(th_id);
|
||||
return th && th->is_beta_redex(p, n);
|
||||
}
|
||||
|
||||
bool context::get_value(enode * n, expr_ref & value) {
|
||||
sort * s = n->get_sort();
|
||||
family_id fid = s->get_family_id();
|
||||
|
|
|
@ -531,22 +531,22 @@ namespace smt {
|
|||
}
|
||||
|
||||
unsigned get_num_enodes_of(func_decl const * decl) const {
|
||||
unsigned id = decl->get_decl_id();
|
||||
unsigned id = decl->get_small_id();
|
||||
return id < m_decl2enodes.size() ? m_decl2enodes[id].size() : 0;
|
||||
}
|
||||
|
||||
enode_vector const& enodes_of(func_decl const * d) const {
|
||||
unsigned id = d->get_decl_id();
|
||||
unsigned id = d->get_small_id();
|
||||
return id < m_decl2enodes.size() ? m_decl2enodes[id] : m_empty_vector;
|
||||
}
|
||||
|
||||
enode_vector::const_iterator begin_enodes_of(func_decl const * decl) const {
|
||||
unsigned id = decl->get_decl_id();
|
||||
unsigned id = decl->get_small_id();
|
||||
return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : nullptr;
|
||||
}
|
||||
|
||||
enode_vector::const_iterator end_enodes_of(func_decl const * decl) const {
|
||||
unsigned id = decl->get_decl_id();
|
||||
unsigned id = decl->get_small_id();
|
||||
return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : nullptr;
|
||||
}
|
||||
|
||||
|
@ -773,7 +773,12 @@ namespace smt {
|
|||
|
||||
void internalize_quantifier(quantifier * q, bool gate_ctx);
|
||||
|
||||
bool m_has_lambda = false;
|
||||
obj_map<enode, quantifier*> m_lambdas;
|
||||
|
||||
bool has_lambda();
|
||||
|
||||
bool is_beta_redex(enode* p, enode* n) const;
|
||||
|
||||
void internalize_lambda(quantifier * q);
|
||||
|
||||
void internalize_formula_core(app * n, bool gate_ctx);
|
||||
|
@ -783,6 +788,7 @@ namespace smt {
|
|||
friend class set_enode_flag_trail;
|
||||
|
||||
public:
|
||||
|
||||
void set_enode_flag(bool_var v, bool is_new_var);
|
||||
|
||||
protected:
|
||||
|
@ -1748,6 +1754,8 @@ namespace smt {
|
|||
|
||||
bool watches_fixed(enode* n) const;
|
||||
|
||||
bool has_split_candidate(bool_var& var, bool& is_pos);
|
||||
|
||||
bool decide_user_interference(bool_var& var, bool& is_pos);
|
||||
|
||||
void assign_fixed(enode* n, expr* val, unsigned sz, literal const* explain);
|
||||
|
|
|
@ -415,6 +415,7 @@ namespace smt {
|
|||
st.update("final checks", m_stats.m_num_final_checks);
|
||||
st.update("added eqs", m_stats.m_num_add_eq);
|
||||
st.update("mk clause", m_stats.m_num_mk_clause);
|
||||
st.update("mk clause binary", m_stats.m_num_mk_bin_clause);
|
||||
st.update("del clause", m_stats.m_num_del_clause);
|
||||
st.update("dyn ack", m_stats.m_num_dyn_ack);
|
||||
st.update("interface eqs", m_stats.m_num_interface_eqs);
|
||||
|
|
|
@ -136,9 +136,9 @@ namespace smt {
|
|||
}
|
||||
|
||||
void context::display_profile_res_sub(std::ostream & out) const {
|
||||
display_var_occs_histogram(std::cerr);
|
||||
display_num_min_occs(std::cerr);
|
||||
std::cerr << "\n";
|
||||
display_var_occs_histogram(out);
|
||||
display_num_min_occs(out);
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
void context::display_profile(std::ostream & out) const {
|
||||
|
|
|
@ -78,6 +78,8 @@ namespace smt {
|
|||
unsigned m_merge_tf:1; //!< True if the enode should be merged with true/false when the associated boolean variable is assigned.
|
||||
unsigned m_cgc_enabled:1; //!< True if congruence closure is enabled for this enode.
|
||||
unsigned m_iscope_lvl; //!< When the enode was internalized
|
||||
bool m_proof_is_logged; //!< Indicates that the proof for the enode being equal to its root is in the log.
|
||||
signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern
|
||||
/*
|
||||
The following property is valid for m_parents
|
||||
|
||||
|
@ -96,8 +98,6 @@ namespace smt {
|
|||
enode_vector m_parents; //!< Parent enodes of the equivalence class.
|
||||
id_var_list<> m_th_var_list; //!< List of theories that 'care' about this enode.
|
||||
trans_justification m_trans; //!< A justification for the enode being equal to its root.
|
||||
bool m_proof_is_logged; //!< Indicates that the proof for the enode being equal to its root is in the log.
|
||||
signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern
|
||||
approx_set m_lbls;
|
||||
approx_set m_plbls;
|
||||
enode * m_args[0]; //!< Cached args
|
||||
|
@ -171,7 +171,7 @@ namespace smt {
|
|||
unsigned get_expr_id() const { return m_owner->get_id(); }
|
||||
|
||||
func_decl * get_decl() const { return m_owner->get_decl(); }
|
||||
unsigned get_decl_id() const { return m_owner->get_decl()->get_decl_id(); }
|
||||
unsigned get_decl_id() const { return m_owner->get_decl()->get_small_id(); }
|
||||
|
||||
sort* get_sort() const { return m_owner->get_sort(); }
|
||||
|
||||
|
|
|
@ -350,6 +350,8 @@ namespace smt {
|
|||
- gate_ctx is true if the expression is in the context of a logical gate.
|
||||
*/
|
||||
void context::internalize(expr * n, bool gate_ctx) {
|
||||
if (memory::above_high_watermark())
|
||||
throw default_exception("resource limit exceeded during internalization");
|
||||
internalize_deep(n);
|
||||
internalize_rec(n, gate_ctx);
|
||||
}
|
||||
|
@ -576,20 +578,19 @@ namespace smt {
|
|||
m_qmanager->add(q, generation);
|
||||
}
|
||||
|
||||
|
||||
void context::internalize_lambda(quantifier * q) {
|
||||
TRACE("internalize_quantifier", tout << mk_pp(q, m) << "\n";);
|
||||
SASSERT(is_lambda(q));
|
||||
if (e_internalized(q)) {
|
||||
if (e_internalized(q))
|
||||
return;
|
||||
}
|
||||
app_ref lam_name(m.mk_fresh_const("lambda", q->get_sort()), m);
|
||||
app_ref eq(m), lam_app(m);
|
||||
expr_ref_vector vars(m);
|
||||
vars.push_back(lam_name);
|
||||
unsigned sz = q->get_num_decls();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
for (unsigned i = 0; i < sz; ++i)
|
||||
vars.push_back(m.mk_var(sz - i - 1, q->get_decl_sort(i)));
|
||||
}
|
||||
array_util autil(m);
|
||||
lam_app = autil.mk_select(vars.size(), vars.data());
|
||||
eq = m.mk_eq(lam_app, q->get_expr());
|
||||
|
@ -597,15 +598,28 @@ namespace smt {
|
|||
expr * patterns[1] = { m.mk_pattern(lam_app) };
|
||||
fa = m.mk_forall(sz, q->get_decl_sorts(), q->get_decl_names(), eq, 0, m.lambda_def_qid(), symbol::null, 1, patterns);
|
||||
internalize_quantifier(fa, true);
|
||||
if (!e_internalized(lam_name)) internalize_uninterpreted(lam_name);
|
||||
m_app2enode.setx(q->get_id(), get_enode(lam_name), nullptr);
|
||||
if (!e_internalized(lam_name))
|
||||
internalize_uninterpreted(lam_name);
|
||||
enode* lam_node = get_enode(lam_name);
|
||||
push_trail(insert_obj_map<enode, quantifier*>(m_lambdas, lam_node));
|
||||
m_lambdas.insert(lam_node, q);
|
||||
m_app2enode.setx(q->get_id(), lam_node, nullptr);
|
||||
m_l_internalized_stack.push_back(q);
|
||||
m_trail_stack.push_back(&m_mk_lambda_trail);
|
||||
bool_var bv = get_bool_var(fa);
|
||||
assign(literal(bv, false), nullptr);
|
||||
mark_as_relevant(bv);
|
||||
push_trail(value_trail<bool>(m_has_lambda));
|
||||
m_has_lambda = true;
|
||||
}
|
||||
|
||||
bool context::has_lambda() {
|
||||
for (auto const & [n, q] : m_lambdas) {
|
||||
if (n->get_class_size() != 1)
|
||||
return true;
|
||||
for (enode* p : enode::parents(n))
|
||||
if (!is_beta_redex(p, n))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1008,7 +1022,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
if (!e->is_eq()) {
|
||||
unsigned decl_id = n->get_decl()->get_decl_id();
|
||||
unsigned decl_id = n->get_decl()->get_small_id();
|
||||
if (decl_id >= m_decl2enodes.size())
|
||||
m_decl2enodes.resize(decl_id+1);
|
||||
m_decl2enodes[decl_id].push_back(e);
|
||||
|
@ -1052,7 +1066,7 @@ namespace smt {
|
|||
m_cg_table.erase(e);
|
||||
}
|
||||
if (e->get_num_args() > 0 && !e->is_eq()) {
|
||||
unsigned decl_id = to_app(n)->get_decl()->get_decl_id();
|
||||
unsigned decl_id = to_app(n)->get_decl()->get_small_id();
|
||||
SASSERT(decl_id < m_decl2enodes.size());
|
||||
SASSERT(m_decl2enodes[decl_id].back() == e);
|
||||
m_decl2enodes[decl_id].pop_back();
|
||||
|
|
|
@ -18,8 +18,6 @@ Revision History:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include<iostream>
|
||||
|
||||
namespace smt {
|
||||
|
||||
struct statistics {
|
||||
|
|
|
@ -321,6 +321,13 @@ namespace smt {
|
|||
virtual bool is_shared(theory_var v) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Determine if node \c n under parent \c p is in a beta redex position.
|
||||
*/
|
||||
virtual bool is_beta_redex(enode* p, enode* n) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the theory has something to propagate
|
||||
|
|
|
@ -974,7 +974,7 @@ namespace smt {
|
|||
/**
|
||||
\brief A monomial is 'pure' if does not have a numeric coefficient.
|
||||
*/
|
||||
bool is_pure_monomial(expr * m) const { return m_util.is_mul(m) && (to_app(m)->get_num_args() > 2 || !m_util.is_numeral(to_app(m)->get_arg(0))); }
|
||||
bool is_pure_monomial(expr * m) const;
|
||||
bool is_pure_monomial(theory_var v) const { return is_pure_monomial(get_enode(v)->get_expr()); }
|
||||
void mark_var(theory_var v, svector<theory_var> & vars, var_set & already_found);
|
||||
void mark_dependents(theory_var v, svector<theory_var> & vars, var_set & already_found, row_set & already_visited_rows);
|
||||
|
|
|
@ -574,7 +574,8 @@ namespace smt {
|
|||
lower = m_util.mk_ge(mod, zero);
|
||||
upper = m_util.mk_le(mod, abs_divisor);
|
||||
TRACE("div_axiom_bug",
|
||||
tout << "eqz: " << eqz << " neq: " << eq << "\n";
|
||||
tout << "eqz: " << eqz << "\n";
|
||||
tout << "neq: " << eq << "\n";
|
||||
tout << "lower: " << lower << "\n";
|
||||
tout << "upper: " << upper << "\n";);
|
||||
|
||||
|
@ -583,14 +584,18 @@ namespace smt {
|
|||
mk_axiom(eqz, upper, !m_util.is_numeral(abs_divisor));
|
||||
rational k;
|
||||
|
||||
if (!m_util.is_numeral(divisor)) {
|
||||
// (=> (> y 0) (<= (* y (div x y)) x))
|
||||
// (=> (< y 0) ???)
|
||||
expr_ref div_ge(m), div_non_pos(m);
|
||||
if (m_util.is_zero(dividend)) {
|
||||
mk_axiom(eqz, m.mk_eq(div, zero));
|
||||
mk_axiom(eqz, m.mk_eq(mod, zero));
|
||||
}
|
||||
|
||||
// (or (= y 0) (<= (* y (div x y)) x))
|
||||
else if (!m_util.is_numeral(divisor)) {
|
||||
expr_ref div_ge(m), div_le(m), ge(m), le(m);
|
||||
div_ge = m_util.mk_ge(m_util.mk_sub(dividend, m_util.mk_mul(divisor, div)), zero);
|
||||
s(div_ge);
|
||||
div_non_pos = m_util.mk_le(divisor, zero);
|
||||
mk_axiom(div_non_pos, div_ge, false);
|
||||
s(div_ge);
|
||||
mk_axiom(eqz, div_ge, false);
|
||||
TRACE("arith", tout << eqz << " " << div_ge << "\n");
|
||||
}
|
||||
|
||||
if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) &&
|
||||
|
@ -3097,6 +3102,8 @@ namespace smt {
|
|||
m_stats.m_conflicts++;
|
||||
m_num_conflicts++;
|
||||
TRACE("arith_conflict",
|
||||
if (proof_rule)
|
||||
tout << proof_rule << "\n";
|
||||
tout << "scope: " << ctx.get_scope_level() << "\n";
|
||||
for (unsigned i = 0; i < num_literals; i++) {
|
||||
ctx.display_detailed_literal(tout, lits[i]);
|
||||
|
|
|
@ -624,11 +624,9 @@ template<typename Ext>
|
|||
bool theory_arith<Ext>::check_monomial_assignments() {
|
||||
bool computed_epsilon = false;
|
||||
for (theory_var v : m_nl_monomials) {
|
||||
TRACE("non_linear", tout << "v" << v << " is relevant: " << ctx.is_relevant(get_enode(v)) << "\n";
|
||||
tout << "check_monomial_assignments result: " << check_monomial_assignment(v, computed_epsilon) << "\n";
|
||||
tout << "computed_epsilon: " << computed_epsilon << "\n";);
|
||||
TRACE("non_linear", tout << "v" << v << " is relevant: " << ctx.is_relevant(get_enode(v)) << "\n");
|
||||
if (ctx.is_relevant(get_enode(v)) && !check_monomial_assignment(v, computed_epsilon)) {
|
||||
TRACE("non_linear_failed", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(v), get_manager()) << "\n";
|
||||
TRACE("non_linear", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(v), get_manager()) << "\n";
|
||||
display_var(tout, v););
|
||||
return false;
|
||||
}
|
||||
|
@ -1254,6 +1252,17 @@ bool theory_arith<Ext>::in_monovariate_monomials(buffer<coeff_expr> & p, expr *
|
|||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::is_pure_monomial(expr* mon) const {
|
||||
if (!m_util.is_mul(mon))
|
||||
return false;
|
||||
app* p = to_app(mon);
|
||||
for (expr* arg : *p)
|
||||
if (m_util.is_numeral(arg) || m_util.is_mul(arg))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Display a nested form expression
|
||||
*/
|
||||
|
@ -2145,13 +2154,14 @@ void theory_arith<Ext>::set_gb_exhausted() {
|
|||
// Scan the grobner basis eqs, and look for inconsistencies.
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::get_gb_eqs_and_look_for_conflict(ptr_vector<grobner::equation>& eqs, grobner& gb) {
|
||||
TRACE("grobner", );
|
||||
|
||||
eqs.reset();
|
||||
gb.get_equations(eqs);
|
||||
TRACE("grobner_bug", tout << "after gb\n";);
|
||||
TRACE("grobner", tout << "after gb\n";
|
||||
for (grobner::equation* eq : eqs)
|
||||
gb.display_equation(tout, *eq);
|
||||
);
|
||||
for (grobner::equation* eq : eqs) {
|
||||
TRACE("grobner_bug", gb.display_equation(tout, *eq););
|
||||
if (is_inconsistent(eq, gb) || is_inconsistent2(eq, gb)) {
|
||||
TRACE("grobner", tout << "inconsistent: "; gb.display_equation(tout, *eq););
|
||||
return true;
|
||||
|
|
|
@ -239,7 +239,6 @@ namespace smt {
|
|||
//
|
||||
bool theory_array::internalize_term_core(app * n) {
|
||||
TRACE("array_bug", tout << mk_bounded_pp(n, m) << "\n";);
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (expr* arg : *n)
|
||||
ctx.internalize(arg, false);
|
||||
// force merge-tf by re-internalizing expression.
|
||||
|
|
|
@ -272,12 +272,14 @@ namespace smt {
|
|||
std::cout << smt << "\n";
|
||||
std::cout << tns << "\n";
|
||||
#endif
|
||||
#if 0
|
||||
if (tns == sz1) {
|
||||
std::cout << "SEEN " << tms << "\n";
|
||||
}
|
||||
if (tns == sz2) {
|
||||
std::cout << "SEEN " << smt << "\n";
|
||||
}
|
||||
#endif
|
||||
ctx().push_trail(value_trail<bool>(i1.m_is_leaf, false));
|
||||
ctx().push_trail(value_trail<bool>(i2.m_is_leaf, false));
|
||||
expr_ref k1(m), k2(m), k3(m);
|
||||
|
|
|
@ -473,39 +473,21 @@ namespace smt {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void theory_array_base::collect_shared_vars(sbuffer<theory_var> & result) {
|
||||
TRACE("array_shared", tout << "collecting shared vars...\n";);
|
||||
ptr_buffer<enode> to_unmark;
|
||||
unsigned num_vars = get_num_vars();
|
||||
for (unsigned i = 0; i < num_vars; i++) {
|
||||
enode * n = get_enode(i);
|
||||
if (ctx.is_relevant(n) && ctx.is_shared(n)) {
|
||||
enode * r = n->get_root();
|
||||
if (!r->is_marked() && is_array_sort(r)) {
|
||||
TRACE("array_shared", tout << "new shared var: #" << r->get_expr_id() << "\n";);
|
||||
r->set_mark();
|
||||
to_unmark.push_back(r);
|
||||
theory_var r_th_var = r->get_var(get_id());
|
||||
SASSERT(r_th_var != null_theory_var);
|
||||
result.push_back(r_th_var);
|
||||
}
|
||||
}
|
||||
}
|
||||
unmark_enodes(to_unmark.size(), to_unmark.c_ptr());
|
||||
bool theory_array_base::is_beta_redex(enode* p, enode* n) const {
|
||||
if (is_select(p))
|
||||
return p->get_arg(0)->get_root() == n->get_root();
|
||||
if (is_map(p))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
bool theory_array_base::is_select_arg(enode* r) {
|
||||
for (enode* n : r->get_parents()) {
|
||||
if (is_select(n)) {
|
||||
for (unsigned i = 1; i < n->get_num_args(); ++i) {
|
||||
if (r == n->get_arg(i)->get_root()) {
|
||||
for (enode* n : r->get_parents())
|
||||
if (is_select(n))
|
||||
for (unsigned i = 1; i < n->get_num_args(); ++i)
|
||||
if (r == n->get_arg(i)->get_root())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -536,7 +518,6 @@ namespace smt {
|
|||
TRACE("array", tout << "collecting shared vars...\n" << unsigned_vector(result.size(), (unsigned*)result.data()) << "\n";);
|
||||
unmark_enodes(to_unmark.size(), to_unmark.data());
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Create interface variables for shared array variables.
|
||||
|
|
|
@ -142,6 +142,7 @@ namespace smt {
|
|||
//
|
||||
// --------------------------------------------------
|
||||
bool is_shared(theory_var v) const override;
|
||||
bool is_beta_redex(enode* p, enode* n) const override;
|
||||
void collect_shared_vars(sbuffer<theory_var> & result);
|
||||
unsigned mk_interface_eqs();
|
||||
|
||||
|
|
|
@ -1842,11 +1842,11 @@ namespace smt {
|
|||
unsigned sz = bits.size();
|
||||
|
||||
for (unsigned i = start_bit; i < sz; ++i) {
|
||||
if (ctx.get_assignment(bits[i].var()) != l_undef)
|
||||
if (ctx.get_assignment(bits[i].var()) == l_undef)
|
||||
return bits[i].var();
|
||||
}
|
||||
for (unsigned i = 0; i < start_bit; ++i) {
|
||||
if (ctx.get_assignment(bits[i].var()) != l_undef)
|
||||
if (ctx.get_assignment(bits[i].var()) == l_undef)
|
||||
return bits[i].var();
|
||||
}
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ namespace smt {
|
|||
else if (is_update_field(n)) {
|
||||
assert_update_field_axioms(n);
|
||||
}
|
||||
else {
|
||||
else if (m_util.is_datatype(n->get_sort())) {
|
||||
sort * s = n->get_sort();
|
||||
if (m_util.get_datatype_num_constructors(s) == 1) {
|
||||
func_decl * c = m_util.get_datatype_constructors(s)->get(0);
|
||||
|
@ -343,7 +343,7 @@ namespace smt {
|
|||
}
|
||||
arg = ctx.get_enode(def);
|
||||
}
|
||||
if (!m_util.is_datatype(s))
|
||||
if (!m_util.is_datatype(s) && !m_sutil.is_seq(s))
|
||||
continue;
|
||||
if (is_attached_to_var(arg))
|
||||
continue;
|
||||
|
@ -393,7 +393,7 @@ namespace smt {
|
|||
|
||||
if (!is_attached_to_var(n) &&
|
||||
(ctx.has_quantifiers() ||
|
||||
(m_util.is_datatype(s) && m_util.has_nested_arrays()) ||
|
||||
(m_util.is_datatype(s) && m_util.has_nested_rec()) ||
|
||||
(m_util.is_datatype(s) && !s->is_infinite()))) {
|
||||
mk_var(n);
|
||||
}
|
||||
|
@ -485,7 +485,10 @@ namespace smt {
|
|||
for (int v = 0; v < num_vars; v++) {
|
||||
if (v == static_cast<int>(m_find.find(v))) {
|
||||
enode * node = get_enode(v);
|
||||
if (m_util.is_recursive(node->get_sort()) && !oc_cycle_free(node) && occurs_check(node)) {
|
||||
sort* s = node->get_sort();
|
||||
if (!m_util.is_datatype(s))
|
||||
continue;
|
||||
if (m_util.is_recursive(s) && !oc_cycle_free(node) && occurs_check(node)) {
|
||||
// conflict was detected...
|
||||
// return...
|
||||
return FC_CONTINUE;
|
||||
|
@ -541,6 +544,17 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
}
|
||||
sort* se = nullptr;
|
||||
if (m_sutil.is_seq(s, se) && m_util.is_datatype(se)) {
|
||||
for (enode* aarg : get_seq_args(arg)) {
|
||||
if (aarg->get_root() == child->get_root()) {
|
||||
if (aarg != child) {
|
||||
m_used_eqs.push_back(enode_pair(aarg, child));
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY(found);
|
||||
}
|
||||
|
@ -587,6 +601,20 @@ namespace smt {
|
|||
}
|
||||
enode * parent = d->m_constructor;
|
||||
oc_mark_on_stack(parent);
|
||||
auto process_arg = [&](enode* aarg) {
|
||||
if (oc_cycle_free(aarg))
|
||||
return false;
|
||||
if (oc_on_stack(aarg)) {
|
||||
occurs_check_explain(parent, aarg);
|
||||
return true;
|
||||
}
|
||||
if (m_util.is_datatype(aarg->get_sort())) {
|
||||
m_parent.insert(aarg->get_root(), parent);
|
||||
oc_push_stack(aarg);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (enode * arg : enode::args(parent)) {
|
||||
if (oc_cycle_free(arg)) {
|
||||
continue;
|
||||
|
@ -598,39 +626,61 @@ namespace smt {
|
|||
}
|
||||
// explore `arg` (with parent)
|
||||
expr* earg = arg->get_expr();
|
||||
sort* s = earg->get_sort();
|
||||
sort* s = earg->get_sort(), *se = nullptr;
|
||||
if (m_util.is_datatype(s)) {
|
||||
m_parent.insert(arg->get_root(), parent);
|
||||
oc_push_stack(arg);
|
||||
}
|
||||
else if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) {
|
||||
for (enode* aarg : get_array_args(arg)) {
|
||||
if (oc_cycle_free(aarg)) {
|
||||
continue;
|
||||
}
|
||||
if (oc_on_stack(aarg)) {
|
||||
occurs_check_explain(parent, aarg);
|
||||
else if (m_sutil.is_seq(s, se) && m_util.is_datatype(se)) {
|
||||
for (enode* sarg : get_seq_args(arg))
|
||||
if (process_arg(sarg))
|
||||
return true;
|
||||
}
|
||||
if (m_util.is_datatype(aarg->get_sort())) {
|
||||
m_parent.insert(aarg->get_root(), parent);
|
||||
oc_push_stack(aarg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) {
|
||||
for (enode* aarg : get_array_args(arg))
|
||||
if (process_arg(aarg))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ptr_vector<enode> const& theory_datatype::get_array_args(enode* n) {
|
||||
m_array_args.reset();
|
||||
theory_array* th = dynamic_cast<theory_array*>(ctx.get_theory(m_autil.get_family_id()));
|
||||
for (enode* p : th->parent_selects(n)) {
|
||||
m_array_args.push_back(p);
|
||||
ptr_vector<enode> const& theory_datatype::get_seq_args(enode* n) {
|
||||
m_args.reset();
|
||||
m_todo.reset();
|
||||
auto add_todo = [&](enode* n) {
|
||||
if (!n->is_marked()) {
|
||||
n->set_mark();
|
||||
m_todo.push_back(n);
|
||||
}
|
||||
};
|
||||
|
||||
for (enode* sib : *n)
|
||||
add_todo(sib);
|
||||
|
||||
for (unsigned i = 0; i < m_todo.size(); ++i) {
|
||||
enode* n = m_todo[i];
|
||||
expr* e = n->get_expr();
|
||||
if (m_sutil.str.is_unit(e))
|
||||
m_args.push_back(n->get_arg(0));
|
||||
else if (m_sutil.str.is_concat(e))
|
||||
for (expr* arg : *to_app(e))
|
||||
add_todo(ctx.get_enode(arg));
|
||||
}
|
||||
for (enode* n : m_todo)
|
||||
n->unset_mark();
|
||||
|
||||
return m_args;
|
||||
}
|
||||
|
||||
ptr_vector<enode> const& theory_datatype::get_array_args(enode* n) {
|
||||
m_args.reset();
|
||||
theory_array* th = dynamic_cast<theory_array*>(ctx.get_theory(m_autil.get_family_id()));
|
||||
for (enode* p : th->parent_selects(n))
|
||||
m_args.push_back(p);
|
||||
app_ref def(m_autil.mk_default(n->get_expr()), m);
|
||||
m_array_args.push_back(ctx.get_enode(def));
|
||||
return m_array_args;
|
||||
m_args.push_back(ctx.get_enode(def));
|
||||
return m_args;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -653,18 +703,19 @@ namespace smt {
|
|||
enode * app = m_stack.back().second;
|
||||
m_stack.pop_back();
|
||||
|
||||
if (oc_cycle_free(app)) continue;
|
||||
if (oc_cycle_free(app))
|
||||
continue;
|
||||
|
||||
TRACE("datatype", tout << "occurs check loop: " << enode_pp(app, ctx) << (op==ENTER?" enter":" exit")<< "\n";);
|
||||
|
||||
switch (op) {
|
||||
case ENTER:
|
||||
res = occurs_check_enter(app);
|
||||
break;
|
||||
res = occurs_check_enter(app);
|
||||
break;
|
||||
|
||||
case EXIT:
|
||||
oc_mark_cycle_free(app);
|
||||
break;
|
||||
oc_mark_cycle_free(app);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,6 +753,7 @@ namespace smt {
|
|||
theory(ctx, ctx.get_manager().mk_family_id("datatype")),
|
||||
m_util(m),
|
||||
m_autil(m),
|
||||
m_sutil(m),
|
||||
m_find(*this),
|
||||
m_trail_stack() {
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
|||
|
||||
#include "util/union_find.h"
|
||||
#include "ast/array_decl_plugin.h"
|
||||
#include "ast/seq_decl_plugin.h"
|
||||
#include "ast/datatype_decl_plugin.h"
|
||||
#include "model/datatype_factory.h"
|
||||
#include "smt/smt_theory.h"
|
||||
|
@ -46,6 +47,7 @@ namespace smt {
|
|||
|
||||
datatype_util m_util;
|
||||
array_util m_autil;
|
||||
seq_util m_sutil;
|
||||
ptr_vector<var_data> m_var_data;
|
||||
th_union_find m_find;
|
||||
trail_stack m_trail_stack;
|
||||
|
@ -90,8 +92,9 @@ namespace smt {
|
|||
bool oc_cycle_free(enode * n) const { return n->get_root()->is_marked2(); }
|
||||
|
||||
void oc_push_stack(enode * n);
|
||||
ptr_vector<enode> m_array_args;
|
||||
ptr_vector<enode> m_args, m_todo;
|
||||
ptr_vector<enode> const& get_array_args(enode* n);
|
||||
ptr_vector<enode> const& get_seq_args(enode* n);
|
||||
|
||||
// class for managing state of final_check
|
||||
class final_check_st {
|
||||
|
|
|
@ -1539,6 +1539,8 @@ public:
|
|||
return FC_CONTINUE;
|
||||
case l_undef:
|
||||
TRACE("arith", tout << "check-lia giveup\n";);
|
||||
if (ctx().get_fparams().m_arith_ignore_int)
|
||||
return FC_GIVEUP;
|
||||
st = FC_CONTINUE;
|
||||
break;
|
||||
}
|
||||
|
@ -1866,7 +1868,11 @@ public:
|
|||
return l_undef;
|
||||
}
|
||||
lbool lia_check = l_undef;
|
||||
switch (m_lia->check(&m_explanation)) {
|
||||
auto cr = m_lia->check(&m_explanation);
|
||||
if (cr != lp::lia_move::sat && ctx().get_fparams().m_arith_ignore_int)
|
||||
return l_undef;
|
||||
|
||||
switch (cr) {
|
||||
case lp::lia_move::sat:
|
||||
lia_check = l_true;
|
||||
break;
|
||||
|
@ -1896,6 +1902,8 @@ public:
|
|||
break;
|
||||
}
|
||||
case lp::lia_move::cut: {
|
||||
if (ctx().get_fparams().m_arith_ignore_int)
|
||||
return l_undef;
|
||||
TRACE("arith", tout << "cut\n";);
|
||||
++m_stats.m_gomory_cuts;
|
||||
// m_explanation implies term <= k
|
||||
|
@ -3151,11 +3159,15 @@ public:
|
|||
// lp().shrink_explanation_to_minimum(m_explanation); // todo, enable when perf is fixed
|
||||
++m_num_conflicts;
|
||||
++m_stats.m_conflicts;
|
||||
TRACE("arith", tout << "scope: " << ctx().get_scope_level() << "\n"; display_evidence(tout, m_explanation); );
|
||||
TRACE("arith", display(tout << "is-conflict: " << is_conflict << "\n"););
|
||||
for (auto ev : m_explanation) {
|
||||
TRACE("arith",
|
||||
tout << "lemma scope: " << ctx().get_scope_level();
|
||||
for (auto const& p : m_params) tout << " " << p;
|
||||
tout << "\n";
|
||||
display_evidence(tout, m_explanation);
|
||||
display(tout << "is-conflict: " << is_conflict << "\n"););
|
||||
for (auto ev : m_explanation)
|
||||
set_evidence(ev.ci(), m_core, m_eqs);
|
||||
}
|
||||
|
||||
// SASSERT(validate_conflict(m_core, m_eqs));
|
||||
dump_conflict(m_core, m_eqs);
|
||||
if (is_conflict) {
|
||||
|
|
|
@ -1598,10 +1598,12 @@ namespace smt {
|
|||
lbool is_sat = k.check();
|
||||
validating = false;
|
||||
// std::cout << is_sat << "\n";
|
||||
#if 0
|
||||
if (is_sat == l_true) {
|
||||
std::cout << A << "\n";
|
||||
std::cout << B << "\n";
|
||||
}
|
||||
#endif
|
||||
SASSERT(is_sat != l_true);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -467,6 +467,15 @@ namespace smt {
|
|||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* n is an argument of p, if p is a function definition or case predicate,
|
||||
* then there is no reason for the solver to enforce that equality on n is
|
||||
* fully determined. It is a beta-redex with respect to expanding p.
|
||||
*/
|
||||
bool theory_recfun::is_beta_redex(enode* p, enode* n) const {
|
||||
return is_defined(p) || is_case_pred(p);
|
||||
}
|
||||
|
||||
void theory_recfun::display(std::ostream & out) const {
|
||||
out << "recfun\n";
|
||||
out << "disabled guards:\n" << m_disabled_guards << "\n";
|
||||
|
|
|
@ -99,6 +99,7 @@ namespace smt {
|
|||
bool can_propagate() override;
|
||||
void propagate() override;
|
||||
bool should_research(expr_ref_vector &) override;
|
||||
bool is_beta_redex(enode* p, enode* n) const override;
|
||||
|
||||
void new_eq_eh(theory_var v1, theory_var v2) override {}
|
||||
void new_diseq_eh(theory_var v1, theory_var v2) override {}
|
||||
|
|
|
@ -1455,7 +1455,7 @@ bool theory_seq::internalize_term(app* term) {
|
|||
if (ctx.e_internalized(term)) {
|
||||
mk_var(ctx.get_enode(term));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m.is_bool(term) &&
|
||||
(m_util.str.is_in_re(term) || m_sk.is_skolem(term))) {
|
||||
|
@ -1484,12 +1484,21 @@ bool theory_seq::internalize_term(app* term) {
|
|||
mk_var(e);
|
||||
if (!ctx.relevancy()) {
|
||||
relevant_eh(term);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool theory_seq::is_beta_redex(enode* p, enode* n) const {
|
||||
expr* term = p->get_expr();
|
||||
if (!m_util.str.is_map(term) && !m_util.str.is_mapi(term) &&
|
||||
!m_util.str.is_foldl(term) && !m_util.str.is_foldli(term))
|
||||
return false;
|
||||
if (p->get_arg(0)->get_root() == n->get_root())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void theory_seq::add_length(expr* l) {
|
||||
expr* e = nullptr;
|
||||
VERIFY(m_util.str.is_length(l, e));
|
||||
|
@ -3273,7 +3282,7 @@ bool theory_seq::should_research(expr_ref_vector & unsat_core) {
|
|||
k_min *= 2;
|
||||
if (m_util.is_seq(s_min))
|
||||
k_min = std::max(m_util.str.min_length(s_min), k_min);
|
||||
IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-length " << mk_pp(s_min, m) << " " << k_min << ")\n");
|
||||
IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-length " << mk_bounded_pp(s_min, m, 3) << " " << k_min << ")\n");
|
||||
add_length_limit(s_min, k_min, false);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -412,6 +412,7 @@ namespace smt {
|
|||
void finalize_model(model_generator & mg) override;
|
||||
void init_search_eh() override;
|
||||
void validate_model(model& mdl) override;
|
||||
bool is_beta_redex(enode* p, enode* n) const override;
|
||||
|
||||
void init_model(expr_ref_vector const& es);
|
||||
app* get_ite_value(expr* a);
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace smt {
|
|||
if (!m_next) {
|
||||
sort* s = decl()->get_domain(0);
|
||||
sort* domain[2] = {s, s};
|
||||
m_next = m.mk_fresh_func_decl("next", "", 2, domain, s);
|
||||
m_next = m.mk_fresh_func_decl("specrel.next", "", 2, domain, s, false);
|
||||
}
|
||||
return m_next;
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
void theory_str::assert_axiom(expr * _e) {
|
||||
if (_e == nullptr)
|
||||
if (_e == nullptr)
|
||||
return;
|
||||
if (opt_VerifyFinalCheckProgress) {
|
||||
finalCheckProgressIndicator = true;
|
||||
|
@ -1100,9 +1100,10 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate CharAt axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
|
||||
expr_ref ts0(mk_str_var("ts0"), m);
|
||||
expr_ref ts1(mk_str_var("ts1"), m);
|
||||
expr_ref ts2(mk_str_var("ts2"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref ts0(mk_str_var("ch_ts0"), m);
|
||||
expr_ref ts1(mk_str_var("ch_ts1"), m);
|
||||
expr_ref ts2(mk_str_var("ch_ts2"), m);
|
||||
|
||||
expr_ref cond(m.mk_and(
|
||||
m_autil.mk_ge(arg1, mk_int(0)),
|
||||
|
@ -1134,8 +1135,9 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate prefixof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
|
||||
expr_ref ts0(mk_str_var("ts0"), m);
|
||||
expr_ref ts1(mk_str_var("ts1"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref ts0(mk_str_var("p_ts0"), m);
|
||||
expr_ref ts1(mk_str_var("p_ts1"), m);
|
||||
|
||||
expr_ref_vector innerItems(m);
|
||||
innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1)));
|
||||
|
@ -1170,8 +1172,9 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate suffixof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
|
||||
expr_ref ts0(mk_str_var("ts0"), m);
|
||||
expr_ref ts1(mk_str_var("ts1"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref ts0(mk_str_var("s_ts0"), m);
|
||||
expr_ref ts1(mk_str_var("s_ts1"), m);
|
||||
|
||||
expr_ref_vector innerItems(m);
|
||||
innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1)));
|
||||
|
@ -1235,8 +1238,9 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate Contains axiom for " << mk_pp(ex, m) << std::endl;);
|
||||
|
||||
expr_ref ts0(mk_str_var("ts0"), m);
|
||||
expr_ref ts1(mk_str_var("ts1"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref ts0(mk_str_var("c_ts0"), m);
|
||||
expr_ref ts1(mk_str_var("c_ts1"), m);
|
||||
|
||||
expr_ref breakdownAssert(ctx.mk_eq_atom(ex, ctx.mk_eq_atom(ex->get_arg(0), mk_concat(ts0, mk_concat(ex->get_arg(1), ts1)))), m);
|
||||
SASSERT(breakdownAssert);
|
||||
|
@ -1287,8 +1291,9 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate str.indexof axiom for " << mk_pp(ex, m) << std::endl;);
|
||||
|
||||
expr_ref x1(mk_str_var("x1"), m);
|
||||
expr_ref x2(mk_str_var("x2"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref x1(mk_str_var("i_x1"), m);
|
||||
expr_ref x2(mk_str_var("i_x2"), m);
|
||||
|
||||
expr_ref condAst1(mk_contains(exHaystack, exNeedle), m);
|
||||
expr_ref condAst2(m.mk_not(ctx.mk_eq_atom(exNeedle, mk_string(""))), m);
|
||||
|
@ -1305,8 +1310,9 @@ namespace smt {
|
|||
// args[0] = x3 . x4
|
||||
// /\ |x3| = |x1| + |args[1]| - 1
|
||||
// /\ ! contains(x3, args[1])
|
||||
expr_ref x3(mk_str_var("x3"), m);
|
||||
expr_ref x4(mk_str_var("x4"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref x3(mk_str_var("i_x3"), m);
|
||||
expr_ref x4(mk_str_var("i_x4"), m);
|
||||
expr_ref tmpLen(m_autil.mk_add(ex, mk_strlen(ex->get_arg(1)), mk_int(-1)), m);
|
||||
SASSERT(tmpLen);
|
||||
thenItems.push_back(ctx.mk_eq_atom(exHaystack, mk_concat(x3, x4)));
|
||||
|
@ -1501,8 +1507,9 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate LastIndexof axiom for " << mk_pp(expr, m) << std::endl;);
|
||||
|
||||
expr_ref x1(mk_str_var("x1"), m);
|
||||
expr_ref x2(mk_str_var("x2"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref x1(mk_str_var("li_x1"), m);
|
||||
expr_ref x2(mk_str_var("li_x2"), m);
|
||||
expr_ref indexAst(mk_int_var("index"), m);
|
||||
expr_ref_vector items(m);
|
||||
|
||||
|
@ -1532,8 +1539,9 @@ namespace smt {
|
|||
|
||||
if (!canSkip) {
|
||||
// args[0] = x3 . x4 /\ |x3| = |x1| + 1 /\ ! contains(x4, args[1])
|
||||
expr_ref x3(mk_str_var("x3"), m);
|
||||
expr_ref x4(mk_str_var("x4"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref x3(mk_str_var("li_x3"), m);
|
||||
expr_ref x4(mk_str_var("li_x4"), m);
|
||||
expr_ref tmpLen(m_autil.mk_add(indexAst, mk_int(1)), m);
|
||||
thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4)));
|
||||
thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen));
|
||||
|
@ -1690,10 +1698,11 @@ namespace smt {
|
|||
|
||||
TRACE("str", tout << "instantiate Replace axiom for " << mk_pp(ex, m) << std::endl;);
|
||||
|
||||
expr_ref x1(mk_str_var("x1"), m);
|
||||
expr_ref x2(mk_str_var("x2"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref x1(mk_str_var("rp_x1"), m);
|
||||
expr_ref x2(mk_str_var("rp_x2"), m);
|
||||
expr_ref i1(mk_int_var("i1"), m);
|
||||
expr_ref result(mk_str_var("result"), m);
|
||||
expr_ref result(mk_str_var("rp_result"), m);
|
||||
|
||||
expr * replaceS = nullptr;
|
||||
expr * replaceT = nullptr;
|
||||
|
@ -1714,8 +1723,9 @@ namespace smt {
|
|||
// i1 = |x1|
|
||||
thenItems.push_back(ctx.mk_eq_atom(i1, mk_strlen(x1)));
|
||||
// args[0] = x3 . x4 /\ |x3| = |x1| + |args[1]| - 1 /\ ! contains(x3, args[1])
|
||||
expr_ref x3(mk_str_var("x3"), m);
|
||||
expr_ref x4(mk_str_var("x4"), m);
|
||||
// change subvaribale names to solve some invalide model problems
|
||||
expr_ref x3(mk_str_var("rp_x3"), m);
|
||||
expr_ref x4(mk_str_var("rp_x4"), m);
|
||||
expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(ex->get_arg(1)), mk_int(-1)), m);
|
||||
thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x3, x4)));
|
||||
thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen));
|
||||
|
@ -1812,7 +1822,7 @@ namespace smt {
|
|||
expr_ref zero(mk_string("0"), m);
|
||||
// let (the result starts with a "0") be p
|
||||
expr_ref starts_with_zero(u.str.mk_prefix(zero, ex), m);
|
||||
// let (the result is "0") be q
|
||||
// let (the result is "0") be q
|
||||
expr_ref is_zero(ctx.mk_eq_atom(ex, zero), m);
|
||||
// encoding: the result does NOT start with a "0" (~p) xor the result is "0" (q)
|
||||
// ~p xor q == (~p or q) and (p or ~q)
|
||||
|
@ -1847,7 +1857,7 @@ namespace smt {
|
|||
expr_ref axiom(ctx.mk_eq_atom(ex, rhs), m);
|
||||
assert_axiom_rw(axiom);
|
||||
}
|
||||
|
||||
|
||||
void theory_str::instantiate_axiom_str_from_code(enode * e) {
|
||||
ast_manager & m = get_manager();
|
||||
|
||||
|
@ -3245,7 +3255,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
assert_implication(ax_l, m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
assert_implication(ax_l, new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
}
|
||||
} else if (splitType == 1) {
|
||||
|
@ -3303,7 +3317,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
assert_implication(ax_l, m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
assert_implication(ax_l, new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3355,7 +3373,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
arrangement_disjunction.push_back(new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3400,7 +3422,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
arrangement_disjunction.push_back(new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3641,7 +3667,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
assert_implication(ax_l, m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
assert_implication(ax_l, new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3742,7 +3772,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
arrangement_disjunction.push_back(new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4037,7 +4071,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
assert_implication(ax_l, m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
assert_implication(ax_l, new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4116,7 +4154,11 @@ namespace smt {
|
|||
|
||||
if (!overlapAssumptionUsed) {
|
||||
overlapAssumptionUsed = true;
|
||||
arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
arrangement_disjunction.push_back(new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4513,7 +4555,11 @@ namespace smt {
|
|||
|
||||
// only add the overlap assumption one time
|
||||
if (!overlapAssumptionUsed) {
|
||||
arrangement_disjunction.push_back(m_theoryStrOverlapAssumption_term);
|
||||
// add context dependent formula overlap predicate and relate it to the global overlap predicate
|
||||
sort * s = get_manager().mk_bool_sort();
|
||||
expr_ref new_OverlapAssumption_term = expr_ref(mk_fresh_const(newOverlapStr, s), get_manager());
|
||||
arrangement_disjunction.push_back(new_OverlapAssumption_term);
|
||||
assert_implication(new_OverlapAssumption_term, m_theoryStrOverlapAssumption_term);
|
||||
overlapAssumptionUsed = true;
|
||||
}
|
||||
|
||||
|
@ -4577,7 +4623,7 @@ namespace smt {
|
|||
u.str.is_string(strExpr, stringVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Look through the equivalence class of n to find a string constant.
|
||||
* Return that constant if it is found, and set hasEqcValue to true.
|
||||
|
@ -4604,7 +4650,7 @@ namespace smt {
|
|||
return a;
|
||||
}
|
||||
curr = m_find.next(curr);
|
||||
}
|
||||
}
|
||||
while (curr != first && curr != null_theory_var);
|
||||
}
|
||||
hasEqcValue = false;
|
||||
|
@ -4781,10 +4827,13 @@ namespace smt {
|
|||
//} else if (getNodeType(t, node) == my_Z3_Func) {
|
||||
} else if (is_app(node)) {
|
||||
app * func_app = to_app(node);
|
||||
unsigned int argCount = func_app->get_num_args();
|
||||
for (unsigned int i = 0; i < argCount; i++) {
|
||||
expr * argAst = func_app->get_arg(i);
|
||||
get_const_str_asts_in_node(argAst, astList);
|
||||
// the following check is only valid when the operator is string concatenate
|
||||
if (u.str.is_concat(func_app)) {
|
||||
unsigned int argCount = func_app->get_num_args();
|
||||
for (unsigned int i = 0; i < argCount; i++) {
|
||||
expr * argAst = func_app->get_arg(i);
|
||||
get_const_str_asts_in_node(argAst, astList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6885,7 +6934,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
// heuristics
|
||||
|
||||
|
||||
if (u.str.is_prefix(e)) {
|
||||
check_consistency_prefix(e, is_true);
|
||||
} else if (u.str.is_suffix(e)) {
|
||||
|
@ -6905,7 +6954,7 @@ namespace smt {
|
|||
|
||||
VERIFY(u.str.is_prefix(e, needle, haystack));
|
||||
TRACE("str", tout << "check consistency of prefix predicate: " << mk_pp(needle, m) << " prefixof " << mk_pp(haystack, m) << std::endl;);
|
||||
|
||||
|
||||
zstring needleStringConstant;
|
||||
if (get_string_constant_eqc(needle, needleStringConstant)) {
|
||||
if (u.str.is_itos(haystack) && is_true) {
|
||||
|
@ -6932,7 +6981,7 @@ namespace smt {
|
|||
|
||||
VERIFY(u.str.is_suffix(e, needle, haystack));
|
||||
TRACE("str", tout << "check consistency of suffix predicate: " << mk_pp(needle, m) << " suffixof " << mk_pp(haystack, m) << std::endl;);
|
||||
|
||||
|
||||
zstring needleStringConstant;
|
||||
if (get_string_constant_eqc(needle, needleStringConstant)) {
|
||||
if (u.str.is_itos(haystack) && is_true) {
|
||||
|
@ -6959,7 +7008,7 @@ namespace smt {
|
|||
|
||||
VERIFY(u.str.is_contains(e, haystack, needle)); // first string contains second one
|
||||
TRACE("str", tout << "check consistency of contains predicate: " << mk_pp(haystack, m) << " contains " << mk_pp(needle, m) << std::endl;);
|
||||
|
||||
|
||||
zstring needleStringConstant;
|
||||
if (get_string_constant_eqc(needle, needleStringConstant)) {
|
||||
if (u.str.is_itos(haystack) && is_true) {
|
||||
|
@ -7052,7 +7101,7 @@ namespace smt {
|
|||
m_concat_eval_todo.reset();
|
||||
m_delayed_axiom_setup_terms.reset();
|
||||
m_delayed_assertions_todo.reset();
|
||||
|
||||
|
||||
TRACE_CODE(if (is_trace_enabled("t_str_dump_assign_on_scope_change")) { dump_assignments(); });
|
||||
|
||||
// list of expr* to remove from cut_var_map
|
||||
|
@ -8386,7 +8435,7 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!needToAssignFreeVars) {
|
||||
|
||||
// check string-int terms
|
||||
|
@ -8685,7 +8734,7 @@ namespace smt {
|
|||
} else if (u.str.is_itos(ex)) {
|
||||
expr* fromInt = nullptr;
|
||||
u.str.is_itos(ex, fromInt);
|
||||
|
||||
|
||||
arith_value v(m);
|
||||
v.init(&ctx);
|
||||
rational val;
|
||||
|
@ -8808,7 +8857,7 @@ namespace smt {
|
|||
if (!u.str.is_string(to_app(Gamma.get(left_count)))) {
|
||||
rational offsetLen = offset - left_length + 1;
|
||||
extra_left_cond = m_autil.mk_ge(u.str.mk_length(Gamma.get(left_count)), mk_int(offsetLen));
|
||||
}
|
||||
}
|
||||
|
||||
// find len(Delta[:j])
|
||||
unsigned right_count = 0;
|
||||
|
@ -8887,7 +8936,7 @@ namespace smt {
|
|||
|
||||
expr* theory_str::refine_dis(expr* lhs, expr* rhs) {
|
||||
ast_manager & m = get_manager();
|
||||
|
||||
|
||||
expr_ref lesson(m);
|
||||
lesson = m.mk_not(m.mk_eq(lhs, rhs));
|
||||
TRACE("str", tout << "learning not " << mk_pp(lesson, m) << std::endl;);
|
||||
|
|
|
@ -393,6 +393,8 @@ protected:
|
|||
// does not introduce equalities when they weren't enforced.
|
||||
unsigned m_unused_id;
|
||||
|
||||
const char* newOverlapStr = "!!NewOverlapAssumption!!";
|
||||
|
||||
// terms we couldn't go through set_up_axioms() with because they weren't internalized
|
||||
expr_ref_vector m_delayed_axiom_setup_terms;
|
||||
|
||||
|
@ -492,7 +494,7 @@ protected:
|
|||
obj_map<expr, std::tuple<rational, expr*, expr*>> fixed_length_lesson; //keep track of information for the lesson
|
||||
unsigned preprocessing_iteration_count; // number of attempts we've made to solve by preprocessing length information
|
||||
obj_map<expr, zstring> candidate_model;
|
||||
|
||||
|
||||
stats m_stats;
|
||||
|
||||
protected:
|
||||
|
@ -777,4 +779,3 @@ protected:
|
|||
};
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ Author:
|
|||
#include "smt/theory_bv.h"
|
||||
#include "smt/theory_user_propagator.h"
|
||||
#include "smt/smt_context.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
|
||||
using namespace smt;
|
||||
|
||||
|
@ -49,6 +50,7 @@ void theory_user_propagator::add_expr(expr* term, bool ensure_enode) {
|
|||
expr_ref r(m);
|
||||
expr* e = term;
|
||||
ctx.get_rewriter()(e, r);
|
||||
TRACE("user_propagate", tout << "add " << mk_bounded_pp(e, m) << "\n");
|
||||
if (r != e) {
|
||||
r = m.mk_fresh_const("aux-expr", e->get_sort());
|
||||
expr_ref eq(m.mk_eq(r, e), m);
|
||||
|
@ -102,6 +104,17 @@ void theory_user_propagator::register_cb(expr* e) {
|
|||
add_expr(e, true);
|
||||
}
|
||||
|
||||
void theory_user_propagator::next_split_cb(expr* e, unsigned idx, lbool phase) {
|
||||
if (e == nullptr) { // clear
|
||||
m_next_split_expr = nullptr;
|
||||
return;
|
||||
}
|
||||
ensure_enode(e);
|
||||
m_next_split_expr = e;
|
||||
m_next_split_idx = idx;
|
||||
m_next_split_phase = phase;
|
||||
}
|
||||
|
||||
theory * theory_user_propagator::mk_fresh(context * new_ctx) {
|
||||
auto* th = alloc(theory_user_propagator, *new_ctx);
|
||||
void* ctx;
|
||||
|
@ -156,40 +169,71 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu
|
|||
}
|
||||
}
|
||||
|
||||
bool_var theory_user_propagator::enode_to_bool(enode* n, unsigned bit) {
|
||||
if (n->is_bool()) {
|
||||
// expression is a boolean
|
||||
bool_var new_var = ctx.enode2bool_var(n);
|
||||
if (ctx.get_assignment(new_var) == l_undef)
|
||||
return new_var;
|
||||
return null_bool_var;
|
||||
}
|
||||
// expression is a bit-vector
|
||||
bv_util bv(m);
|
||||
auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid());
|
||||
return th_bv->get_first_unassigned(bit, n);
|
||||
}
|
||||
|
||||
void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
|
||||
|
||||
if (!m_decide_eh)
|
||||
return;
|
||||
|
||||
const bool_var_data& d = ctx.get_bdata(var);
|
||||
|
||||
if (!d.is_theory_atom())
|
||||
|
||||
if (!d.is_enode() && !d.is_theory_atom())
|
||||
return;
|
||||
|
||||
enode* original_enode = nullptr;
|
||||
unsigned original_bit = 0;
|
||||
bv_util bv(m);
|
||||
theory* th = nullptr;
|
||||
theory_var v = null_theory_var;
|
||||
|
||||
// get the associated theory
|
||||
if (!d.is_enode()) {
|
||||
// it might be a value that does not have an enode
|
||||
th = ctx.get_theory(d.get_theory());
|
||||
}
|
||||
else {
|
||||
original_enode = ctx.bool_var2enode(var);
|
||||
v = original_enode->get_th_var(get_family_id());
|
||||
if (v == null_theory_var) {
|
||||
// it is not a registered boolean expression
|
||||
th = ctx.get_theory(d.get_theory());
|
||||
}
|
||||
}
|
||||
|
||||
if (v == null_theory_var && !th)
|
||||
return;
|
||||
|
||||
theory* th = ctx.get_theory(d.get_theory());
|
||||
if (v == null_theory_var && th->get_family_id() != bv.get_fid())
|
||||
return;
|
||||
|
||||
bv_util bv(m);
|
||||
enode* original_enode = nullptr;
|
||||
unsigned original_bit = 0;
|
||||
|
||||
if (d.is_enode() && th->get_family_id() == get_family_id()) {
|
||||
// variable is just a registered expression
|
||||
original_enode = ctx.bool_var2enode(var);
|
||||
}
|
||||
else if (th->get_family_id() == bv.get_fid()) {
|
||||
// it might be a registered bit-vector
|
||||
if (v == null_theory_var) {
|
||||
// it is not a registered boolean value but it is a bitvector
|
||||
auto registered_bv = ((theory_bv*)th)->get_bv_with_theory(var, get_family_id());
|
||||
if (!registered_bv.first)
|
||||
// there is no registered bv associated with the bit
|
||||
return;
|
||||
original_enode = registered_bv.first;
|
||||
original_bit = registered_bv.second;
|
||||
v = original_enode->get_th_var(get_family_id());
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// call the registered callback
|
||||
unsigned new_bit = original_bit;
|
||||
lbool phase = is_pos ? l_true : l_false;
|
||||
|
||||
expr* e = var2expr(original_enode->get_th_var(get_family_id()));
|
||||
|
||||
expr* e = var2expr(v);
|
||||
m_decide_eh(m_user_context, this, &e, &new_bit, &phase);
|
||||
enode* new_enode = ctx.get_enode(e);
|
||||
|
||||
|
@ -201,28 +245,28 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool_var old_var = var;
|
||||
if (new_enode->is_bool()) {
|
||||
// expression was set to a boolean
|
||||
bool_var new_var = ctx.enode2bool_var(new_enode);
|
||||
if (ctx.get_assignment(new_var) == l_undef) {
|
||||
var = new_var;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// expression was set to a bit-vector
|
||||
auto th_bv = (theory_bv*)ctx.get_theory(bv.get_fid());
|
||||
bool_var new_var = th_bv->get_first_unassigned(new_bit, new_enode);
|
||||
|
||||
if (new_var != null_bool_var) {
|
||||
var = new_var;
|
||||
}
|
||||
}
|
||||
// get unassigned variable from enode
|
||||
var = enode_to_bool(new_enode, new_bit);
|
||||
|
||||
// in case the callback did not decide on a truth value -> let Z3 decide
|
||||
is_pos = ctx.guess(var, phase);
|
||||
}
|
||||
|
||||
bool theory_user_propagator::get_case_split(bool_var& var, bool& is_pos){
|
||||
if (!m_next_split_expr)
|
||||
return false;
|
||||
enode* n = ctx.get_enode(m_next_split_expr);
|
||||
|
||||
var = enode_to_bool(n, m_next_split_idx);
|
||||
|
||||
if (var == null_bool_var)
|
||||
return false;
|
||||
|
||||
is_pos = ctx.guess(var, m_next_split_phase);
|
||||
m_next_split_expr = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void theory_user_propagator::push_scope_eh() {
|
||||
++m_num_scopes;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,9 @@ namespace smt {
|
|||
expr_ref_vector m_to_add;
|
||||
unsigned_vector m_to_add_lim;
|
||||
unsigned m_to_add_qhead = 0;
|
||||
expr* m_next_split_expr = nullptr;
|
||||
unsigned m_next_split_idx;
|
||||
lbool m_next_split_phase;
|
||||
|
||||
expr* var2expr(theory_var v) { return m_var2expr.get(v); }
|
||||
theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; }
|
||||
|
@ -95,6 +98,8 @@ namespace smt {
|
|||
|
||||
void propagate_consequence(prop_info const& prop);
|
||||
void propagate_new_fixed(prop_info const& prop);
|
||||
|
||||
bool_var enode_to_bool(enode* n, unsigned bit);
|
||||
|
||||
public:
|
||||
theory_user_propagator(context& ctx);
|
||||
|
@ -125,13 +130,14 @@ namespace smt {
|
|||
void register_decide(user_propagator::decide_eh_t& decide_eh) { m_decide_eh = decide_eh; }
|
||||
|
||||
bool has_fixed() const { return (bool)m_fixed_eh; }
|
||||
bool has_decide() const { return (bool)m_decide_eh; }
|
||||
|
||||
void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override;
|
||||
void register_cb(expr* e) override;
|
||||
void next_split_cb(expr* e, unsigned idx, lbool phase) override;
|
||||
|
||||
void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits);
|
||||
void decide(bool_var& var, bool& is_pos);
|
||||
bool get_case_split(bool_var& var, bool& is_pos);
|
||||
|
||||
theory * mk_fresh(context * new_ctx) override;
|
||||
bool internalize_atom(app* atom, bool gate_ctx) override;
|
||||
|
@ -154,5 +160,5 @@ namespace smt {
|
|||
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