mirror of
https://github.com/Z3Prover/z3
synced 2025-04-06 09:34:08 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
224cc8f8dd
commit
71d68b8fe0
|
@ -1005,6 +1005,11 @@ br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
|
|||
|
||||
m_lhs.reset();
|
||||
m_util.str.get_concat_units(a, m_lhs);
|
||||
|
||||
if (m_lhs.empty()) {
|
||||
result = m_util.str.mk_empty(m().get_sort(a));
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < m_lhs.size(); ++i) {
|
||||
|
|
|
@ -279,8 +279,9 @@ public:
|
|||
app* mk_lex_le(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_STRING_LE, 2, es); }
|
||||
|
||||
|
||||
bool is_nth_i(func_decl* f) const { return is_decl_of(f, m_fid, OP_SEQ_NTH_I); }
|
||||
bool is_nth_u(func_decl* f) const { return is_decl_of(f, m_fid, OP_SEQ_NTH_U); }
|
||||
bool is_nth_i(func_decl const* f) const { return is_decl_of(f, m_fid, OP_SEQ_NTH_I); }
|
||||
bool is_nth_u(func_decl const* f) const { return is_decl_of(f, m_fid, OP_SEQ_NTH_U); }
|
||||
bool is_skolem(func_decl const* f) const { return is_decl_of(f, m_fid, _OP_SEQ_SKOLEM); }
|
||||
|
||||
bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); }
|
||||
bool is_string(expr const* n, symbol& s) const {
|
||||
|
|
|
@ -1912,6 +1912,19 @@ void cmd_context::validate_model() {
|
|||
}
|
||||
|
||||
void cmd_context::analyze_failure(model_evaluator& ev, expr* a, bool expected_value) {
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (m().is_not(a, e)) {
|
||||
analyze_failure(ev, e, !expected_value);
|
||||
return;
|
||||
}
|
||||
if (!expected_value && m().is_or(a)) {
|
||||
for (expr* arg : *to_app(a)) {
|
||||
if (ev.is_true(arg)) {
|
||||
analyze_failure(ev, arg, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expected_value && m().is_and(a)) {
|
||||
for (expr* arg : *to_app(a)) {
|
||||
if (ev.is_false(arg)) {
|
||||
|
@ -1920,36 +1933,27 @@ void cmd_context::analyze_failure(model_evaluator& ev, expr* a, bool expected_va
|
|||
}
|
||||
}
|
||||
}
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (expected_value && m().is_ite(a, c, t, e)) {
|
||||
if (ev.is_true(c) && ev.is_false(t)) {
|
||||
analyze_failure(ev, t, true);
|
||||
if (!m().is_true(c)) analyze_failure(ev, c, false);
|
||||
if (!m().is_false(t)) analyze_failure(ev, t, true);
|
||||
return;
|
||||
}
|
||||
if (ev.is_false(c) && ev.is_false(e)) {
|
||||
analyze_failure(ev, e, true);
|
||||
if (!m().is_false(c)) analyze_failure(ev, c, true);
|
||||
if (!m().is_false(e)) analyze_failure(ev, e, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m().is_not(a, e)) {
|
||||
analyze_failure(ev, e, !expected_value);
|
||||
return;
|
||||
}
|
||||
if (!expected_value && m().is_or(a)) {
|
||||
for (expr* arg : *to_app(a)) {
|
||||
if (ev.is_false(arg)) {
|
||||
analyze_failure(ev, arg, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!expected_value && m().is_ite(a, c, t, e)) {
|
||||
if (ev.is_true(c) && ev.is_true(t)) {
|
||||
analyze_failure(ev, t, false);
|
||||
if (!m().is_true(c)) analyze_failure(ev, c, false);
|
||||
if (!m().is_true(t)) analyze_failure(ev, t, false);
|
||||
return;
|
||||
}
|
||||
if (ev.is_false(c) && ev.is_true(e)) {
|
||||
analyze_failure(ev, e, false);
|
||||
if (!m().is_false(c)) analyze_failure(ev, c, true);
|
||||
if (!m().is_true(e)) analyze_failure(ev, e, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ Copyright (c) 2015 Microsoft Corporation
|
|||
|
||||
Module Name:
|
||||
|
||||
theory_seq.h
|
||||
theory_seq.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
|
@ -269,7 +269,6 @@ theory_seq::theory_seq(ast_manager& m, theory_seq_params const & params):
|
|||
m(m),
|
||||
m_params(params),
|
||||
m_rep(m, m_dm),
|
||||
m_reset_cache(false),
|
||||
m_lts_checked(false),
|
||||
m_eq_id(0),
|
||||
m_find(*this),
|
||||
|
@ -310,7 +309,6 @@ theory_seq::theory_seq(ast_manager& m, theory_seq_params const & params):
|
|||
m_post = "seq.post"; // (seq.post s l): suffix of string s of length l
|
||||
m_eq = "seq.eq";
|
||||
m_seq_align = "seq.align";
|
||||
|
||||
}
|
||||
|
||||
theory_seq::~theory_seq() {
|
||||
|
@ -334,11 +332,6 @@ struct scoped_enable_trace {
|
|||
};
|
||||
|
||||
final_check_status theory_seq::final_check_eh() {
|
||||
if (m_reset_cache) {
|
||||
m_rep.reset_cache();
|
||||
m_reset_cache = false;
|
||||
}
|
||||
|
||||
m_new_propagation = false;
|
||||
TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n"););
|
||||
TRACE("seq_verbose", get_context().display(tout););
|
||||
|
@ -2106,9 +2099,12 @@ bool theory_seq::check_extensionality() {
|
|||
}
|
||||
if (!seqs.empty() && ctx.is_relevant(n1) && m_util.is_seq(o1) && ctx.is_shared(n1)) {
|
||||
dependency* dep = nullptr;
|
||||
expr_ref e1 = canonize(o1, dep);
|
||||
for (unsigned i = 0; i < seqs.size(); ++i) {
|
||||
enode* n2 = get_enode(seqs[i]);
|
||||
expr_ref e1(m);
|
||||
if (!canonize(o1, dep, e1)) {
|
||||
return false;
|
||||
}
|
||||
for (theory_var v : seqs) {
|
||||
enode* n2 = get_enode(v);
|
||||
expr* o2 = n2->get_owner();
|
||||
if (m.get_sort(o1) != m.get_sort(o2)) {
|
||||
continue;
|
||||
|
@ -2116,7 +2112,10 @@ bool theory_seq::check_extensionality() {
|
|||
if (ctx.is_diseq(n1, n2) || m_exclude.contains(o1, o2)) {
|
||||
continue;
|
||||
}
|
||||
expr_ref e2 = canonize(n2->get_owner(), dep);
|
||||
expr_ref e2(m);
|
||||
if (!canonize(n2->get_owner(), dep, e2)) {
|
||||
return false;
|
||||
}
|
||||
m_lhs.reset(); m_rhs.reset();
|
||||
bool change = false;
|
||||
if (!m_seq_rewrite.reduce_eq(e1, e2, m_lhs, m_rhs, change)) {
|
||||
|
@ -2251,7 +2250,7 @@ bool theory_seq::is_solved() {
|
|||
SASSERT(len1 == len2);
|
||||
}
|
||||
else {
|
||||
std::cout << r << "does not have a length\n";
|
||||
IF_VERBOSE(0, verbose_stream() << r << "does not have a length\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2399,7 +2398,6 @@ bool theory_seq::propagate_eq(dependency* dep, literal lit, expr* e1, expr* e2,
|
|||
void theory_seq::enforce_length_coherence(enode* n1, enode* n2) {
|
||||
expr* o1 = n1->get_owner();
|
||||
expr* o2 = n2->get_owner();
|
||||
// std::cout << mk_pp(o1, m) << " " << mk_pp(o2, m) << " " << has_length(o1) << " " << has_length(o2) << "\n";
|
||||
if (m_util.str.is_concat(o1) && m_util.str.is_concat(o2)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2446,17 +2444,28 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc
|
|||
context& ctx = get_context();
|
||||
expr_ref_vector lhs(m), rhs(m);
|
||||
bool changed = false;
|
||||
TRACE("seq_verbose", tout << ls << " = " << rs << "\n";);
|
||||
TRACE("seq",
|
||||
for (expr* l : ls) tout << "s#" << l->get_id() << " " << mk_bounded_pp(l, m, 2) << "\n";
|
||||
tout << " = \n";
|
||||
for (expr* r : rs) tout << "s#" << r->get_id() << " " << mk_bounded_pp(r, m, 2) << "\n";);
|
||||
|
||||
if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, changed)) {
|
||||
// equality is inconsistent.
|
||||
TRACE("seq_verbose", tout << ls << " != " << rs << "\n";);
|
||||
set_conflict(deps);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
SASSERT(lhs.empty() && rhs.empty());
|
||||
return false;
|
||||
}
|
||||
TRACE("seq",
|
||||
tout << "reduced to\n";
|
||||
for (expr* l : lhs) tout << mk_bounded_pp(l, m, 2) << "\n";
|
||||
tout << " = \n";
|
||||
for (expr* r : rhs) tout << mk_bounded_pp(r, m, 2) << "\n";
|
||||
);
|
||||
SASSERT(lhs.size() == rhs.size());
|
||||
m_seq_rewrite.add_seqs(ls, rs, lhs, rhs);
|
||||
if (lhs.empty()) {
|
||||
|
@ -2640,6 +2649,7 @@ bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) {
|
|||
enode* n1 = ensure_enode(l);
|
||||
enode* n2 = ensure_enode(r);
|
||||
TRACE("seq", tout << mk_bounded_pp(l, m, 2) << " ==> " << mk_bounded_pp(r, m, 2) << "\n"; display_deps(tout, deps);
|
||||
tout << "#" << n1->get_owner_id() << " ==> #" << n2->get_owner_id() << "\n";
|
||||
tout << (n1->get_root() == n2->get_root()) << "\n";);
|
||||
propagate_eq(deps, n1, n2);
|
||||
return true;
|
||||
|
@ -2671,8 +2681,9 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de
|
|||
expr_ref_vector& rs = m_rs;
|
||||
rs.reset(); ls.reset();
|
||||
dependency* dep2 = nullptr;
|
||||
bool change = canonize(l, ls, dep2);
|
||||
change = canonize(r, rs, dep2) || change;
|
||||
bool change = false;
|
||||
if (!canonize(l, ls, dep2, change)) return false;
|
||||
if (!canonize(r, rs, dep2, change)) return false;
|
||||
deps = m_dm.mk_join(dep2, deps);
|
||||
TRACE("seq_verbose", tout << l << " = " << r << " ==> ";
|
||||
tout << ls << " = " << rs << "\n";
|
||||
|
@ -3217,8 +3228,8 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
ls.reset(); rs.reset(); lhs.reset(); rhs.reset();
|
||||
dependency* deps = nullptr;
|
||||
bool change = false;
|
||||
change = canonize(n.ls(i), ls, deps) || change;
|
||||
change = canonize(n.rs(i), rs, deps) || change;
|
||||
if (!canonize(n.ls(i), ls, deps, change)) return false;
|
||||
if (!canonize(n.rs(i), rs, deps, change)) return false;
|
||||
|
||||
if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, change)) {
|
||||
TRACE("seq", display_disequation(tout << "reduces to false: ", n);
|
||||
|
@ -3347,7 +3358,10 @@ bool theory_seq::solve_nc(unsigned idx) {
|
|||
dependency* deps = n.deps();
|
||||
literal len_gt = n.len_gt();
|
||||
context& ctx = get_context();
|
||||
expr_ref c = canonize(n.contains(), deps);
|
||||
expr_ref c(m);
|
||||
if (!canonize(n.contains(), deps, c)) {
|
||||
return false;
|
||||
}
|
||||
expr* a = nullptr, *b = nullptr;
|
||||
|
||||
CTRACE("seq", c != n.contains(), tout << n.contains() << " =>\n" << c << "\n";);
|
||||
|
@ -4026,7 +4040,8 @@ void theory_seq::init_model(expr_ref_vector const& es) {
|
|||
expr_ref new_s(m);
|
||||
for (auto e : es) {
|
||||
dependency* eqs = nullptr;
|
||||
expr_ref s = canonize(e, eqs);
|
||||
expr_ref s(m);
|
||||
if (!canonize(e, eqs, s)) s = e;
|
||||
if (is_var(s)) {
|
||||
new_s = m_factory->get_fresh_value(m.get_sort(s));
|
||||
m_rep.update(s, new_s, eqs);
|
||||
|
@ -4107,7 +4122,8 @@ public:
|
|||
}
|
||||
case string_source: {
|
||||
dependency* deps = nullptr;
|
||||
expr_ref tmp = th.canonize(m_strings[k], deps);
|
||||
expr_ref tmp(th.m);
|
||||
if (!th.canonize(m_strings[k], deps, tmp)) tmp = m_strings[k];
|
||||
zstring zs;
|
||||
if (th.m_util.str.is_string(tmp, zs)) {
|
||||
add_buffer(sbuffer, zs);
|
||||
|
@ -4247,14 +4263,14 @@ void theory_seq::validate_model(model& mdl) {
|
|||
expr_ref l(m_util.str.mk_concat(ls), m);
|
||||
expr_ref r(m_util.str.mk_concat(rs), m);
|
||||
if (!mdl.are_equal(l, r)) {
|
||||
IF_VERBOSE(0, verbose_stream() << l << " = " << r << " but " << mdl(l) << " != " << mdl(r) << "\n");
|
||||
IF_VERBOSE(0, verbose_stream() << "equality failed: " << l << " = " << r << "\nbut\n" << mdl(l) << " != " << mdl(r) << "\n");
|
||||
}
|
||||
}
|
||||
for (auto const& ne : m_nqs) {
|
||||
expr_ref l = ne.l();
|
||||
expr_ref r = ne.r();
|
||||
if (mdl.are_equal(l, r)) {
|
||||
IF_VERBOSE(0, verbose_stream() << l << " = " << r << " = " << mdl(l) << "\n");
|
||||
IF_VERBOSE(0, verbose_stream() << "disequality failed: " << l << " != " << r << "\n" << mdl(l) << "\n" << mdl(r) << "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4274,11 +4290,19 @@ void theory_seq::validate_model(model& mdl) {
|
|||
}
|
||||
|
||||
#if 0
|
||||
// to enable this check need to add m_util.str.is_skolem(f); to theory_seq::include_func_interp
|
||||
for (auto const& kv : m_rep) {
|
||||
expr_ref l(kv.m_key, m);
|
||||
expr_ref r(kv.m_value.first, m);
|
||||
|
||||
if (!mdl.are_equal(l, r)) {
|
||||
IF_VERBOSE(0, verbose_stream() << l << " = " << r << " but " << mdl(l) << " != " << mdl(r) << "\n");
|
||||
enode* ln = ensure_enode(l);
|
||||
enode* rn = ensure_enode(r);
|
||||
IF_VERBOSE(0, verbose_stream() << "bad representation: " << l << " ->\n" << r << "\nbut\n"
|
||||
<< mdl(l) << "\n->\n" << mdl(r) << "\n"
|
||||
<< "nodes: #" << ln->get_owner_id() << " #" << rn->get_owner_id() << "\n"
|
||||
<< "roots: #" << ln->get_root()->get_owner_id() << " #" << rn->get_root()->get_owner_id() << "\n";
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -4317,56 +4341,68 @@ bool theory_seq::can_propagate() {
|
|||
return m_axioms_head < m_axioms.size() || !m_replay.empty() || m_new_solution;
|
||||
}
|
||||
|
||||
expr_ref theory_seq::canonize(expr* e, dependency*& eqs) {
|
||||
expr_ref result = expand(e, eqs);
|
||||
bool theory_seq::canonize(expr* e, dependency*& eqs, expr_ref& result) {
|
||||
if (!expand(e, eqs, result)) {
|
||||
return false;
|
||||
}
|
||||
TRACE("seq", tout << mk_bounded_pp(e, m, 2) << " expands to\n" << mk_bounded_pp(result, m, 2) << "\n";);
|
||||
m_rewrite(result);
|
||||
TRACE("seq", tout << mk_bounded_pp(e, m, 2) << " rewrites to\n" << mk_bounded_pp(result, m, 2) << "\n";);
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool theory_seq::canonize(expr* e, expr_ref_vector& es, dependency*& eqs) {
|
||||
bool theory_seq::canonize(expr* e, expr_ref_vector& es, dependency*& eqs, bool& change) {
|
||||
expr* e1, *e2;
|
||||
expr_ref e3(e, m);
|
||||
bool change = false;
|
||||
while (true) {
|
||||
if (m_util.str.is_concat(e3, e1, e2)) {
|
||||
canonize(e1, es, eqs);
|
||||
if (!canonize(e1, es, eqs, change)) {
|
||||
return false;
|
||||
}
|
||||
e3 = e2;
|
||||
change = true;
|
||||
}
|
||||
else if (m_util.str.is_empty(e3)) {
|
||||
return true;
|
||||
change = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
expr_ref e4 = expand(e3, eqs);
|
||||
expr_ref e4(m);
|
||||
if (!expand(e3, eqs, e4)) {
|
||||
return false;
|
||||
}
|
||||
change |= e4 != e3;
|
||||
m_util.str.get_concat(e4, es);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return change;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool theory_seq::canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs) {
|
||||
bool change = false;
|
||||
bool theory_seq::canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs, bool& change) {
|
||||
for (expr* e : es) {
|
||||
change = canonize(e, result, eqs) || change;
|
||||
if (!canonize(e, result, eqs, change))
|
||||
return false;
|
||||
SASSERT(!m_util.str.is_concat(e) || change);
|
||||
}
|
||||
return change;
|
||||
return true;
|
||||
}
|
||||
|
||||
expr_ref theory_seq::expand(expr* e, dependency*& eqs) {
|
||||
bool theory_seq::expand(expr* e, dependency*& eqs, expr_ref& result) {
|
||||
unsigned sz = m_expand_todo.size();
|
||||
m_expand_todo.push_back(e);
|
||||
expr_ref result(m);
|
||||
while (m_expand_todo.size() != sz) {
|
||||
expr* e = m_expand_todo.back();
|
||||
result = expand1(e, eqs);
|
||||
if (result.get()) m_expand_todo.pop_back();
|
||||
bool r = expand1(e, eqs, result);
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
if (result) {
|
||||
SASSERT(m_expand_todo.back() == e);
|
||||
m_expand_todo.pop_back();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
expr_ref theory_seq::try_expand(expr* e, dependency*& eqs){
|
||||
|
@ -4383,10 +4419,9 @@ expr_ref theory_seq::try_expand(expr* e, dependency*& eqs){
|
|||
}
|
||||
return result;
|
||||
}
|
||||
expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) {
|
||||
expr_ref result(m);
|
||||
bool theory_seq::expand1(expr* e0, dependency*& eqs, expr_ref& result) {
|
||||
result = try_expand(e0, eqs);
|
||||
if (result) return result;
|
||||
if (result) return true;
|
||||
dependency* deps = nullptr;
|
||||
expr* e = m_rep.find(e0, deps);
|
||||
expr* e1, *e2, *e3;
|
||||
|
@ -4395,7 +4430,7 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) {
|
|||
if (m_util.str.is_concat(e, e1, e2)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = mk_concat(arg1, arg2);
|
||||
}
|
||||
else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) {
|
||||
|
@ -4404,78 +4439,63 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) {
|
|||
else if (m_util.str.is_prefix(e, e1, e2)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = m_util.str.mk_prefix(arg1, arg2);
|
||||
}
|
||||
else if (m_util.str.is_suffix(e, e1, e2)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = m_util.str.mk_suffix(arg1, arg2);
|
||||
}
|
||||
else if (m_util.str.is_contains(e, e1, e2)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = m_util.str.mk_contains(arg1, arg2);
|
||||
}
|
||||
else if (m_util.str.is_unit(e, e1)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
if (!arg1) return result;
|
||||
if (!arg1) return true;
|
||||
result = m_util.str.mk_unit(arg1);
|
||||
}
|
||||
else if (m_util.str.is_index(e, e1, e2)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = m_util.str.mk_index(arg1, arg2, m_autil.mk_int(0));
|
||||
}
|
||||
else if (m_util.str.is_index(e, e1, e2, e3)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = m_util.str.mk_index(arg1, arg2, e3);
|
||||
}
|
||||
else if (m_util.str.is_last_index(e, e1, e2)) {
|
||||
arg1 = try_expand(e1, deps);
|
||||
arg2 = try_expand(e2, deps);
|
||||
if (!arg1 || !arg2) return result;
|
||||
if (!arg1 || !arg2) return true;
|
||||
result = m_util.str.mk_last_index(arg1, arg2);
|
||||
}
|
||||
else if (m.is_ite(e, e1, e2, e3)) {
|
||||
enode* r = get_root(e);
|
||||
enode* r2 = get_root(e2);
|
||||
enode* r3 = get_root(e3);
|
||||
if (ctx.e_internalized(e) && ctx.e_internalized(e2) && r == r2 && r != r3) {
|
||||
literal lit(mk_literal(e1));
|
||||
switch (ctx.get_assignment(lit)) {
|
||||
case l_true:
|
||||
deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit)));
|
||||
result = try_expand(e2, deps);
|
||||
if (!result) return result;
|
||||
add_dependency(deps, ctx.get_enode(e), ctx.get_enode(e2));
|
||||
}
|
||||
else if (ctx.e_internalized(e) && ctx.e_internalized(e2) && r == r3 && r != r2) {
|
||||
if (!result) return true;
|
||||
break;
|
||||
case l_false:
|
||||
deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(~lit)));
|
||||
result = try_expand(e3, deps);
|
||||
if (!result) return result;
|
||||
add_dependency(deps, ctx.get_enode(e), ctx.get_enode(e3));
|
||||
}
|
||||
else {
|
||||
literal lit(mk_literal(e1));
|
||||
switch (ctx.get_assignment(lit)) {
|
||||
case l_true:
|
||||
deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit)));
|
||||
result = try_expand(e2, deps);
|
||||
if (!result) return result;
|
||||
break;
|
||||
case l_false:
|
||||
deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(~lit)));
|
||||
result = try_expand(e3, deps);
|
||||
if (!result) return result;
|
||||
break;
|
||||
case l_undef:
|
||||
result = e;
|
||||
m_reset_cache = true;
|
||||
TRACE("seq", tout << "undef: " << mk_bounded_pp(result, m, 2) << "\n";
|
||||
tout << lit << "@ level: " << ctx.get_scope_level() << "\n";);
|
||||
break;
|
||||
}
|
||||
if (!result) return true;
|
||||
break;
|
||||
case l_undef:
|
||||
ctx.mark_as_relevant(lit);
|
||||
m_new_propagation = true;
|
||||
TRACE("seq", tout << "undef: " << mk_bounded_pp(e, m, 2) << "\n";
|
||||
tout << lit << "@ level: " << ctx.get_scope_level() << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_itos(e, e1)) {
|
||||
|
@ -4531,7 +4551,7 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) {
|
|||
eqs = m_dm.mk_join(eqs, deps);
|
||||
TRACE("seq_verbose", tout << mk_pp(e0, m) << " |--> " << result << "\n";
|
||||
if (eqs) display_deps(tout, eqs););
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
void theory_seq::add_dependency(dependency*& dep, enode* a, enode* b) {
|
||||
|
@ -5229,14 +5249,17 @@ void theory_seq::add_extract_axiom(expr* e) {
|
|||
}
|
||||
|
||||
void theory_seq::add_tail_axiom(expr* e, expr* s) {
|
||||
|
||||
expr_ref head(m), tail(m);
|
||||
mk_decompose(s, head, tail);
|
||||
TRACE("seq", tout << "tail " << mk_bounded_pp(e, m, 2) << " " << mk_bounded_pp(s, m, 2) << "\n";);
|
||||
literal emp = mk_eq_empty(s);
|
||||
add_axiom(emp, mk_seq_eq(s, mk_concat(head, e)));
|
||||
add_axiom(~emp, mk_eq_empty(e));
|
||||
}
|
||||
|
||||
void theory_seq::add_drop_last_axiom(expr* e, expr* s) {
|
||||
TRACE("seq", tout << "drop last " << mk_bounded_pp(e, m, 2) << " " << mk_bounded_pp(s, m, 2) << "\n";);
|
||||
literal emp = mk_eq_empty(s);
|
||||
add_axiom(emp, mk_seq_eq(s, mk_concat(e, m_util.str.mk_unit(mk_last(s)))));
|
||||
add_axiom(~emp, mk_eq_empty(e));
|
||||
|
@ -5283,7 +5306,7 @@ bool theory_seq::is_extract_suffix(expr* s, expr* i, expr* l) {
|
|||
l < 0 => e = empty
|
||||
*/
|
||||
void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) {
|
||||
TRACE("seq", tout << mk_bounded_pp(e, m, 2) << " " << mk_bounded_pp(s, m, 2) << " " << mk_bounded_pp(l, m, 2) << "\n";);
|
||||
TRACE("seq", tout << "prefix " << mk_bounded_pp(e, m, 2) << " " << mk_bounded_pp(s, m, 2) << " " << mk_bounded_pp(l, m, 2) << "\n";);
|
||||
expr_ref le = mk_len(e);
|
||||
expr_ref ls = mk_len(s);
|
||||
expr_ref ls_minus_l(mk_sub(ls, l), m);
|
||||
|
@ -5305,6 +5328,7 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) {
|
|||
i > len(s) => e = empty
|
||||
*/
|
||||
void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) {
|
||||
TRACE("seq", tout << "suffix " << mk_bounded_pp(e, m, 2) << " " << mk_bounded_pp(s, m, 2) << "\n";);
|
||||
expr_ref x(mk_skolem(m_pre, s, i), m);
|
||||
expr_ref lx = mk_len(x);
|
||||
expr_ref ls = mk_len(s);
|
||||
|
@ -5612,6 +5636,7 @@ bool theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, exp
|
|||
literal_vector lits(_lits);
|
||||
enode_pair_vector eqs;
|
||||
if (!linearize(deps, eqs, lits)) {
|
||||
IF_VERBOSE(10, verbose_stream() << "not linearized " << mk_bounded_pp(e1, m, 2) << " " << mk_bounded_pp(e2, m, 2) << "\n");
|
||||
return false;
|
||||
}
|
||||
if (add_to_eqs) {
|
||||
|
@ -5619,12 +5644,14 @@ bool theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, exp
|
|||
new_eq_eh(deps, n1, n2);
|
||||
}
|
||||
TRACE("seq_verbose",
|
||||
tout << "assert: " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << " <- \n";
|
||||
tout << "assert: #" << e1->get_id() << " " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << " <- \n";
|
||||
if (!lits.empty()) { ctx.display_literals_verbose(tout, lits) << "\n"; });
|
||||
|
||||
TRACE("seq",
|
||||
tout << "assert: " << mk_bounded_pp(e1, m, 2) << " = " << mk_bounded_pp(e2, m, 2) << " <- \n";
|
||||
tout << lits << "\n";);
|
||||
tout << "assert:" << mk_bounded_pp(e1, m, 2) << " = " << mk_bounded_pp(e2, m, 2) << " <- \n";
|
||||
tout << lits << "\n";
|
||||
tout << "#" << e1->get_id() << "\n";
|
||||
);
|
||||
|
||||
justification* js =
|
||||
ctx.mk_justification(
|
||||
|
@ -6120,8 +6147,8 @@ void theory_seq::propagate_not_prefix(expr* e) {
|
|||
literal lit = ctx.get_literal(e);
|
||||
SASSERT(ctx.get_assignment(lit) == l_false);
|
||||
dependency * deps = nullptr;
|
||||
expr_ref cont = canonize(e, deps);
|
||||
if (m.is_true(cont)) {
|
||||
expr_ref cont(m);
|
||||
if (canonize(e, deps, cont) && m.is_true(cont)) {
|
||||
propagate_lit(deps, 0, nullptr, lit);
|
||||
return;
|
||||
}
|
||||
|
@ -6153,8 +6180,8 @@ void theory_seq::propagate_not_suffix(expr* e) {
|
|||
SASSERT(ctx.get_assignment(lit) == l_false);
|
||||
|
||||
dependency * deps = nullptr;
|
||||
expr_ref cont = canonize(e, deps);
|
||||
if (m.is_true(cont)) {
|
||||
expr_ref cont(m);
|
||||
if (canonize(e, deps, cont) && m.is_true(cont)) {
|
||||
propagate_lit(deps, 0, nullptr, lit);
|
||||
return;
|
||||
}
|
||||
|
@ -6242,7 +6269,8 @@ void theory_seq::add_le_axiom(expr* n) {
|
|||
bool theory_seq::canonizes(bool sign, expr* e) {
|
||||
context& ctx = get_context();
|
||||
dependency* deps = nullptr;
|
||||
expr_ref cont = canonize(e, deps);
|
||||
expr_ref cont(m);
|
||||
if (!canonize(e, deps, cont)) cont = e;
|
||||
TRACE("seq", tout << mk_bounded_pp(e, m, 2) << " -> " << mk_bounded_pp(cont, m, 2) << "\n";
|
||||
if (deps) display_deps(tout, deps););
|
||||
if ((m.is_true(cont) && !sign) ||
|
||||
|
|
|
@ -346,7 +346,6 @@ namespace smt {
|
|||
theory_seq_params const& m_params;
|
||||
dependency_manager m_dm;
|
||||
solution_map m_rep; // unification representative.
|
||||
bool m_reset_cache; // invalidate cache.
|
||||
scoped_vector<eq> m_eqs; // set of current equations.
|
||||
scoped_vector<ne> m_nqs; // set of current disequalities.
|
||||
scoped_vector<nc> m_ncs; // set of non-contains constraints.
|
||||
|
@ -561,12 +560,12 @@ namespace smt {
|
|||
expr_ref mk_nth(expr* s, expr* idx);
|
||||
expr_ref mk_last(expr* e);
|
||||
expr_ref mk_first(expr* e);
|
||||
expr_ref canonize(expr* e, dependency*& eqs);
|
||||
bool canonize(expr* e, expr_ref_vector& es, dependency*& eqs);
|
||||
bool canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs);
|
||||
bool canonize(expr* e, dependency*& eqs, expr_ref& result);
|
||||
bool canonize(expr* e, expr_ref_vector& es, dependency*& eqs, bool& change);
|
||||
bool canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs, bool& change);
|
||||
ptr_vector<expr> m_expand_todo;
|
||||
expr_ref expand(expr* e, dependency*& eqs);
|
||||
expr_ref expand1(expr* e, dependency*& eqs);
|
||||
bool expand(expr* e, dependency*& eqs, expr_ref& result);
|
||||
bool expand1(expr* e, dependency*& eqs, expr_ref& result);
|
||||
expr_ref try_expand(expr* e, dependency*& eqs);
|
||||
void add_dependency(dependency*& dep, enode* a, enode* b);
|
||||
|
||||
|
|
Loading…
Reference in a new issue