mirror of
https://github.com/Z3Prover/z3
synced 2025-04-13 12:28:44 +00:00
Merge remote-tracking branch 'upstream/master' into lackr
This commit is contained in:
commit
c6df8b3128
|
@ -126,14 +126,27 @@ eautomaton* re2automaton::re2aut(expr* e) {
|
|||
}
|
||||
return b.detach();
|
||||
}
|
||||
#if 0
|
||||
else if (u.re.is_loop(e, e1, lo) && (a = re2aut(e1))) {
|
||||
b = eautomaton::clone(*a);
|
||||
b->add_final_to_init_moves();
|
||||
b->add_init_to_final_states();
|
||||
while (lo > 0) {
|
||||
b = eautomaton::mk_concat(*a, *b);
|
||||
--lo;
|
||||
}
|
||||
return b.detach();
|
||||
}
|
||||
else if (u.re.is_empty(e)) {
|
||||
return alloc(eautomaton, m);
|
||||
return alloc(eautomaton, sm);
|
||||
}
|
||||
else if (u.re.is_full(e)) {
|
||||
expr_ref tt(m.mk_true(), m);
|
||||
sym_expr* _true = sym_expr::mk_pred(tt);
|
||||
return eautomaton::mk_loop(sm, _true);
|
||||
}
|
||||
#if 0
|
||||
else if (u.re.is_intersect(e, e1, e2)) {
|
||||
|
||||
// maybe later
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -197,7 +210,7 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
case OP_RE_INTERSECT:
|
||||
return BR_FAILED;
|
||||
case OP_RE_LOOP:
|
||||
return BR_FAILED;
|
||||
return mk_re_loop(num_args, args, result);
|
||||
case OP_RE_EMPTY_SET:
|
||||
return BR_FAILED;
|
||||
case OP_RE_FULL_SET:
|
||||
|
@ -687,14 +700,14 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
|
|||
return BR_FAILED;
|
||||
}
|
||||
|
||||
void seq_rewriter::add_next(u_map<expr*>& next, unsigned idx, expr* cond) {
|
||||
void seq_rewriter::add_next(u_map<expr*>& next, expr_ref_vector& trail, unsigned idx, expr* cond) {
|
||||
expr* acc;
|
||||
if (m().is_true(cond) || !next.find(idx, acc)) {
|
||||
next.insert(idx, cond);
|
||||
}
|
||||
else {
|
||||
next.insert(idx, m().mk_or(cond, acc));
|
||||
if (!m().is_true(cond) && next.find(idx, acc)) {
|
||||
cond = m().mk_or(cond, acc);
|
||||
}
|
||||
trail.push_back(cond);
|
||||
next.insert(idx, cond);
|
||||
|
||||
}
|
||||
|
||||
bool seq_rewriter::is_sequence(eautomaton& aut, expr_ref_vector& seq) {
|
||||
|
@ -804,9 +817,10 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
aut->get_moves_from(state, mvs, false);
|
||||
for (unsigned j = 0; j < mvs.size(); ++j) {
|
||||
eautomaton::move const& mv = mvs[j];
|
||||
SASSERT(mv.t());
|
||||
if (mv.t()->is_char() && m().is_value(mv.t()->get_char()) && m().is_value(ch)) {
|
||||
if (mv.t()->get_char() == ch) {
|
||||
add_next(next, mv.dst(), acc);
|
||||
add_next(next, trail, mv.dst(), acc);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
|
@ -815,7 +829,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
else {
|
||||
cond = mv.t()->accept(ch);
|
||||
if (!m().is_true(acc)) cond = m().mk_and(acc, cond);
|
||||
add_next(next, mv.dst(), cond);
|
||||
add_next(next, trail, mv.dst(), cond);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -835,12 +849,25 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
}
|
||||
result = mk_or(ors);
|
||||
TRACE("seq", tout << result << "\n";);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) {
|
||||
if (m_util.re.is_full(a) && m_util.re.is_full(b)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_empty(a)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_empty(b)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_epsilon(a)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
|
@ -861,6 +888,22 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
|
|||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_empty(a)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_empty(b)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_full(a)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_full(b)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_star(a) && is_epsilon(b)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
|
@ -871,6 +914,32 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
||||
br_status seq_rewriter::mk_re_loop(unsigned num_args, expr* const* args, expr_ref& result) {
|
||||
rational n1, n2;
|
||||
switch (num_args) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
if (m_autil.is_numeral(args[1], n1) && n1.is_unsigned()) {
|
||||
result = m_util.re.mk_loop(args[0], n1.get_unsigned());
|
||||
return BR_DONE;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (m_autil.is_numeral(args[1], n1) && n1.is_unsigned() &&
|
||||
m_autil.is_numeral(args[2], n2) && n2.is_unsigned()) {
|
||||
result = m_util.re.mk_loop(args[0], n1.get_unsigned(), n2.get_unsigned());
|
||||
return BR_DONE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
a** = a*
|
||||
(a* + b)* = (a + b)*
|
||||
|
@ -879,7 +948,7 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
|
|||
*/
|
||||
br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
|
||||
expr* b, *c, *b1, *c1;
|
||||
if (m_util.re.is_star(a)) {
|
||||
if (m_util.re.is_star(a) || m_util.re.is_empty(a) || m_util.re.is_full(a)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -1127,7 +1196,6 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
|
|||
if (set_empty(szr, _rs, true, lhs, rhs)) {
|
||||
lchange |= szr > 1;
|
||||
change |= szr > 1;
|
||||
TRACE("seq", tout << lchange << " " << szr << "\n";);
|
||||
if (szr == 1 && !lchange) {
|
||||
lhs.reset();
|
||||
rhs.reset();
|
||||
|
@ -1322,23 +1390,20 @@ bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, ex
|
|||
for (unsigned i = 0; i < szl; ++i) {
|
||||
bool found = false;
|
||||
unsigned j = 0;
|
||||
bool is_unit = m_util.str.is_unit(l[i]);
|
||||
for (; !found && j < szr; ++j) {
|
||||
found = !rpos.contains(j) && l[i] == r[j];
|
||||
found = !rpos.contains(j) && (l[i] == r[j] || (is_unit && m_util.str.is_unit(r[j])));
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
#if 0
|
||||
std::cout << mk_pp(l[i], m()) << " not found in ";
|
||||
for (unsigned j = 0; j < szr; ++j) {
|
||||
std::cout << mk_pp(r[j], m()) << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
SASSERT(0 < j && j <= szr);
|
||||
rpos.insert(j-1);
|
||||
}
|
||||
// if we reach here, then every element of l is contained in r in some position.
|
||||
// or each non-unit in l is matched by a non-unit in r, and otherwise, the non-units match up.
|
||||
bool change = false;
|
||||
ptr_vector<expr> rs;
|
||||
for (unsigned j = 0; j < szr; ++j) {
|
||||
if (rpos.contains(j)) {
|
||||
|
@ -1348,6 +1413,12 @@ bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, ex
|
|||
is_sat = false;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if (!change) {
|
||||
return false;
|
||||
}
|
||||
SASSERT(szl == rs.size());
|
||||
if (szl > 0) {
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, false, t); }
|
||||
static sym_expr* mk_char(ast_manager& m, expr* t) { expr_ref tr(t, m); return alloc(sym_expr, false, tr); }
|
||||
static sym_expr* mk_pred(expr_ref& t) { return alloc(sym_expr, true, t); }
|
||||
void inc_ref() { ++m_ref; }
|
||||
void inc_ref() { ++m_ref; }
|
||||
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
bool is_char() const { return !m_is_pred; }
|
||||
|
@ -91,6 +91,7 @@ class seq_rewriter {
|
|||
br_status mk_re_star(expr* a, expr_ref& result);
|
||||
br_status mk_re_plus(expr* a, expr_ref& result);
|
||||
br_status mk_re_opt(expr* a, expr_ref& result);
|
||||
br_status mk_re_loop(unsigned num_args, expr* const* args, expr_ref& result);
|
||||
|
||||
bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
bool is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
||||
|
@ -100,7 +101,7 @@ class seq_rewriter {
|
|||
bool min_length(unsigned n, expr* const* es, unsigned& len);
|
||||
expr* concat_non_empty(unsigned n, expr* const* es);
|
||||
|
||||
void add_next(u_map<expr*>& next, unsigned idx, expr* cond);
|
||||
void add_next(u_map<expr*>& next, expr_ref_vector& trail, unsigned idx, expr* cond);
|
||||
bool is_sequence(expr* e, expr_ref_vector& seq);
|
||||
bool is_sequence(eautomaton& aut, expr_ref_vector& seq);
|
||||
bool is_epsilon(expr* e) const;
|
||||
|
|
|
@ -36,18 +36,55 @@ static bool is_hex_digit(char ch, unsigned& d) {
|
|||
|
||||
static bool is_escape_char(char const *& s, unsigned& result) {
|
||||
unsigned d1, d2;
|
||||
if (*s == '\\' && *(s + 1) == 'x' &&
|
||||
if (*s != '\\' || *(s + 1) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (*(s + 1) == 'x' &&
|
||||
is_hex_digit(*(s + 2), d1) && is_hex_digit(*(s + 3), d2)) {
|
||||
result = d1*16 + d2;
|
||||
s += 4;
|
||||
return true;
|
||||
}
|
||||
if (*s == '\\' && *(s + 1) == '\\') {
|
||||
result = '\\';
|
||||
switch (*(s + 1)) {
|
||||
case 'a':
|
||||
result = '\a';
|
||||
s += 2;
|
||||
return true;
|
||||
case 'b':
|
||||
result = '\b';
|
||||
s += 2;
|
||||
return true;
|
||||
#if 0
|
||||
case 'e':
|
||||
result = '\e';
|
||||
s += 2;
|
||||
return true;
|
||||
#endif
|
||||
case 'f':
|
||||
result = '\f';
|
||||
s += 2;
|
||||
return true;
|
||||
case 'n':
|
||||
result = '\n';
|
||||
s += 2;
|
||||
return true;
|
||||
case 'r':
|
||||
result = '\r';
|
||||
s += 2;
|
||||
return true;
|
||||
case 't':
|
||||
result = '\t';
|
||||
s += 2;
|
||||
return true;
|
||||
case 'v':
|
||||
result = '\v';
|
||||
s += 2;
|
||||
return true;
|
||||
default:
|
||||
result = *(s + 1);
|
||||
s += 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
zstring::zstring(encoding enc): m_encoding(enc) {}
|
||||
|
@ -126,9 +163,6 @@ std::string zstring::encode() const {
|
|||
unsigned char ch = m_buffer[i];
|
||||
if (0 <= ch && ch < 32) {
|
||||
strm << esc_table[ch];
|
||||
}
|
||||
else if (ch == 127) {
|
||||
strm << "^?";
|
||||
}
|
||||
else {
|
||||
strm << (char)(ch);
|
||||
|
@ -211,13 +245,15 @@ seq_decl_plugin::seq_decl_plugin(): m_init(false),
|
|||
m_stringc_sym("String"),
|
||||
m_charc_sym("Char"),
|
||||
m_string(0),
|
||||
m_char(0) {}
|
||||
m_char(0),
|
||||
m_re(0) {}
|
||||
|
||||
void seq_decl_plugin::finalize() {
|
||||
for (unsigned i = 0; i < m_sigs.size(); ++i)
|
||||
dealloc(m_sigs[i]);
|
||||
m_manager->dec_ref(m_string);
|
||||
m_manager->dec_ref(m_char);
|
||||
m_manager->dec_ref(m_re);
|
||||
}
|
||||
|
||||
bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) {
|
||||
|
@ -411,9 +447,9 @@ void seq_decl_plugin::init() {
|
|||
m_sigs[OP_RE_UNION] = alloc(psig, m, "re.union", 1, 2, reAreA, reA);
|
||||
m_sigs[OP_RE_INTERSECT] = alloc(psig, m, "re.inter", 1, 2, reAreA, reA);
|
||||
m_sigs[OP_RE_LOOP] = alloc(psig, m, "re.loop", 1, 1, &reA, reA);
|
||||
m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re-empty-set", 1, 0, 0, reA);
|
||||
m_sigs[OP_RE_FULL_SET] = alloc(psig, m, "re-full-set", 1, 0, 0, reA);
|
||||
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re-of-pred", 1, 1, &predA, reA);
|
||||
m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re.empty", 1, 0, 0, reA);
|
||||
m_sigs[OP_RE_FULL_SET] = alloc(psig, m, "re.all", 1, 0, 0, reA);
|
||||
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re.of.pred", 1, 1, &predA, reA);
|
||||
m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA);
|
||||
m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT);
|
||||
m_sigs[OP_STRING_CONST] = 0;
|
||||
|
@ -429,6 +465,8 @@ void seq_decl_plugin::init() {
|
|||
m_sigs[_OP_STRING_SUFFIX] = alloc(psig, m, "str.suffixof", 0, 2, str2T, boolT);
|
||||
m_sigs[_OP_STRING_IN_REGEXP] = alloc(psig, m, "str.in.re", 0, 2, strTreT, boolT);
|
||||
m_sigs[_OP_STRING_TO_REGEXP] = alloc(psig, m, "str.to.re", 0, 1, &strT, reT);
|
||||
m_sigs[_OP_REGEXP_EMPTY] = alloc(psig, m, "re.nostr", 0, 0, 0, reT);
|
||||
m_sigs[_OP_REGEXP_FULL] = alloc(psig, m, "re.allchar", 0, 0, 0, reT);
|
||||
m_sigs[_OP_STRING_SUBSTR] = alloc(psig, m, "str.substr", 0, 3, strTint2T, strT);
|
||||
}
|
||||
|
||||
|
@ -440,6 +478,9 @@ void seq_decl_plugin::set_manager(ast_manager* m, family_id id) {
|
|||
parameter param(m_char);
|
||||
m_string = m->mk_sort(symbol("String"), sort_info(m_family_id, SEQ_SORT, 1, ¶m));
|
||||
m->inc_ref(m_string);
|
||||
parameter paramS(m_string);
|
||||
m_re = m->mk_sort(m_family_id, RE_SORT, 1, ¶mS);
|
||||
m->inc_ref(m_re);
|
||||
}
|
||||
|
||||
sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
|
||||
|
@ -527,14 +568,41 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
|
||||
|
||||
case OP_RE_LOOP:
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
if (num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_int()) {
|
||||
m.raise_exception("Expecting two numeral parameters to function re-loop");
|
||||
case _OP_REGEXP_FULL:
|
||||
if (!range) {
|
||||
range = m_re;
|
||||
}
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
|
||||
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_FULL_SET));
|
||||
case _OP_REGEXP_EMPTY:
|
||||
if (!range) {
|
||||
range = m_re;
|
||||
}
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
return m.mk_func_decl(symbol("re.nostr"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_EMPTY_SET));
|
||||
|
||||
case OP_RE_LOOP:
|
||||
switch (arity) {
|
||||
case 1:
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
if (num_parameters == 0 || num_parameters > 2 || !parameters[0].is_int() || (num_parameters == 2 && !parameters[1].is_int())) {
|
||||
m.raise_exception("Expecting two numeral parameters to function re-loop");
|
||||
}
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
case 2:
|
||||
if (m_re != domain[0] || !arith_util(m).is_int(domain[1])) {
|
||||
m.raise_exception("Incorrect type of arguments passed to re.loop. Expecting regular expression and two integer parameters");
|
||||
}
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, domain[0], func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
case 3:
|
||||
if (m_re != domain[0] || !arith_util(m).is_int(domain[1]) || !arith_util(m).is_int(domain[2])) {
|
||||
m.raise_exception("Incorrect type of arguments passed to re.loop. Expecting regular expression and two integer parameters");
|
||||
}
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, domain[0], func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
default:
|
||||
m.raise_exception("Incorrect number of arguments passed to loop. Expected 1 regular expression and two integer parameters");
|
||||
}
|
||||
|
||||
|
||||
case OP_STRING_CONST:
|
||||
if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) {
|
||||
|
@ -722,17 +790,37 @@ void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const {
|
|||
}
|
||||
}
|
||||
|
||||
app* seq_util::re::mk_loop(expr* r, unsigned lo) {
|
||||
parameter param(lo);
|
||||
return m.mk_app(m_fid, OP_RE_LOOP, 1, ¶m, 1, &r);
|
||||
}
|
||||
|
||||
app* seq_util::re::mk_loop(expr* r, unsigned lo, unsigned hi) {
|
||||
parameter params[2] = { parameter(lo), parameter(hi) };
|
||||
return m.mk_app(m_fid, OP_RE_LOOP, 2, params, 1, &r);
|
||||
}
|
||||
|
||||
bool seq_util::re::is_loop(expr const* n, expr*& body, unsigned& lo, unsigned& hi) {
|
||||
if (is_loop(n)) {
|
||||
app const* a = to_app(n);
|
||||
SASSERT(a->get_num_args() == 1);
|
||||
SASSERT(a->get_decl()->get_num_parameters() == 2);
|
||||
body = a->get_arg(0);
|
||||
lo = a->get_decl()->get_parameter(0).get_int();
|
||||
hi = a->get_decl()->get_parameter(1).get_int();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
if (a->get_num_args() == 1 && a->get_decl()->get_num_parameters() == 2) {
|
||||
body = a->get_arg(0);
|
||||
lo = a->get_decl()->get_parameter(0).get_int();
|
||||
hi = a->get_decl()->get_parameter(1).get_int();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool seq_util::re::is_loop(expr const* n, expr*& body, unsigned& lo) {
|
||||
if (is_loop(n)) {
|
||||
app const* a = to_app(n);
|
||||
if (a->get_num_args() == 1 && a->get_decl()->get_num_parameters() == 1) {
|
||||
body = a->get_arg(0);
|
||||
lo = a->get_decl()->get_parameter(0).get_int();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,9 @@ enum seq_op_kind {
|
|||
_OP_STRING_TO_REGEXP,
|
||||
_OP_STRING_CHARAT,
|
||||
_OP_STRING_SUBSTR,
|
||||
_OP_STRING_STRIDOF,
|
||||
_OP_STRING_STRIDOF,
|
||||
_OP_REGEXP_EMPTY,
|
||||
_OP_REGEXP_FULL,
|
||||
_OP_SEQ_SKOLEM,
|
||||
LAST_SEQ_OP
|
||||
};
|
||||
|
@ -134,6 +136,7 @@ class seq_decl_plugin : public decl_plugin {
|
|||
symbol m_charc_sym;
|
||||
sort* m_string;
|
||||
sort* m_char;
|
||||
sort* m_re;
|
||||
|
||||
void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
|
||||
|
||||
|
@ -295,6 +298,8 @@ public:
|
|||
app* mk_star(expr* r) { return m.mk_app(m_fid, OP_RE_STAR, r); }
|
||||
app* mk_plus(expr* r) { return m.mk_app(m_fid, OP_RE_PLUS, r); }
|
||||
app* mk_opt(expr* r) { return m.mk_app(m_fid, OP_RE_OPTION, r); }
|
||||
app* mk_loop(expr* r, unsigned lo);
|
||||
app* mk_loop(expr* r, unsigned lo, unsigned hi);
|
||||
|
||||
bool is_to_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_TO_RE); }
|
||||
bool is_concat(expr const* n) const { return is_app_of(n, m_fid, OP_RE_CONCAT); }
|
||||
|
@ -316,7 +321,7 @@ public:
|
|||
MATCH_UNARY(is_plus);
|
||||
MATCH_UNARY(is_opt);
|
||||
bool is_loop(expr const* n, expr*& body, unsigned& lo, unsigned& hi);
|
||||
|
||||
bool is_loop(expr const* n, expr*& body, unsigned& lo);
|
||||
};
|
||||
str str;
|
||||
re re;
|
||||
|
|
|
@ -127,11 +127,11 @@ bool simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void simplifier::reduce_core(expr * n) {
|
||||
if (!is_cached(n)) {
|
||||
void simplifier::reduce_core(expr * n1) {
|
||||
if (!is_cached(n1)) {
|
||||
// We do not assume m_todo is empty... So, we store the current size of the todo-stack.
|
||||
unsigned sz = m_todo.size();
|
||||
m_todo.push_back(n);
|
||||
m_todo.push_back(n1);
|
||||
while (m_todo.size() != sz) {
|
||||
expr * n = m_todo.back();
|
||||
if (is_cached(n))
|
||||
|
@ -142,6 +142,10 @@ void simplifier::reduce_core(expr * n) {
|
|||
m_todo.pop_back();
|
||||
reduce1(n);
|
||||
}
|
||||
if (m.canceled()) {
|
||||
cache_result(n1, n1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -543,8 +543,16 @@ private:
|
|||
|
||||
|
||||
void add(move const& mv) {
|
||||
m_delta[mv.src()].push_back(mv);
|
||||
m_delta_inv[mv.dst()].push_back(mv);
|
||||
if (!is_duplicate_cheap(mv)) {
|
||||
m_delta[mv.src()].push_back(mv);
|
||||
m_delta_inv[mv.dst()].push_back(mv);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_duplicate_cheap(move const& mv) const {
|
||||
if (m_delta[mv.src()].empty()) return false;
|
||||
move const& mv0 = m_delta[mv.src()].back();
|
||||
return mv0.src() == mv.src() && mv0.dst() == mv.dst() && mv0.t() == mv.t();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ expr* theory_seq::solution_map::find(expr* e) {
|
|||
}
|
||||
|
||||
void theory_seq::solution_map::pop_scope(unsigned num_scopes) {
|
||||
if (num_scopes == 0) return;
|
||||
if (num_scopes == 0) return;
|
||||
m_cache.reset();
|
||||
unsigned start = m_limit[m_limit.size() - num_scopes];
|
||||
for (unsigned i = m_updates.size(); i > start; ) {
|
||||
|
@ -151,7 +151,7 @@ void theory_seq::exclusion_table::display(std::ostream& out) const {
|
|||
|
||||
|
||||
theory_seq::theory_seq(ast_manager& m):
|
||||
theory(m.mk_family_id("seq")),
|
||||
theory(m.mk_family_id("seq")),
|
||||
m(m),
|
||||
m_rep(m, m_dm),
|
||||
m_eq_id(0),
|
||||
|
@ -170,7 +170,7 @@ theory_seq::theory_seq(ast_manager& m):
|
|||
m_atoms_qhead(0),
|
||||
m_new_solution(false),
|
||||
m_new_propagation(false),
|
||||
m_mk_aut(m) {
|
||||
m_mk_aut(m) {
|
||||
m_prefix = "seq.prefix.suffix";
|
||||
m_suffix = "seq.suffix.prefix";
|
||||
m_contains_left = "seq.contains.left";
|
||||
|
@ -194,7 +194,7 @@ theory_seq::~theory_seq() {
|
|||
}
|
||||
|
||||
|
||||
final_check_status theory_seq::final_check_eh() {
|
||||
final_check_status theory_seq::final_check_eh() {
|
||||
TRACE("seq", display(tout););
|
||||
if (simplify_and_solve_eqs()) {
|
||||
++m_stats.m_solve_eqs;
|
||||
|
@ -313,10 +313,10 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re
|
|||
++start;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool all_units = true;
|
||||
for (unsigned j = 0; all_units && j < rs.size(); ++j) {
|
||||
for (unsigned j = 0; all_units && j < rs.size(); ++j) {
|
||||
all_units &= m_util.str.is_unit(rs[j]);
|
||||
}
|
||||
if (all_units) {
|
||||
|
@ -372,7 +372,7 @@ lbool theory_seq::assume_equality(expr* l, expr* r) {
|
|||
if (m.is_false(eq)) {
|
||||
return l_false;
|
||||
}
|
||||
|
||||
|
||||
TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << "\n";);
|
||||
enode* n1 = ensure_enode(l);
|
||||
enode* n2 = ensure_enode(r);
|
||||
|
@ -380,7 +380,7 @@ lbool theory_seq::assume_equality(expr* l, expr* r) {
|
|||
return l_true;
|
||||
}
|
||||
ctx.mark_as_relevant(n1);
|
||||
ctx.mark_as_relevant(n2);
|
||||
ctx.mark_as_relevant(n2);
|
||||
ctx.assume_eq(n1, n2);
|
||||
return l_undef;
|
||||
}
|
||||
|
@ -414,15 +414,15 @@ bool theory_seq::propagate_length_coherence(expr* e) {
|
|||
tail = mk_concat(elems.size(), elems.c_ptr());
|
||||
// len(e) >= low => e = tail;
|
||||
literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true))));
|
||||
add_axiom(~low, mk_eq(e, tail, false));
|
||||
add_axiom(~low, mk_eq(e, tail, false));
|
||||
if (upper_bound(e, hi)) {
|
||||
// len(e) <= hi => len(tail) <= hi - lo
|
||||
expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m);
|
||||
expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m);
|
||||
if (hi == lo) {
|
||||
add_axiom(~mk_literal(high1), mk_eq(seq, emp, false));
|
||||
}
|
||||
else {
|
||||
expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m);
|
||||
expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m);
|
||||
add_axiom(~mk_literal(high1), mk_literal(high2));
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +444,9 @@ bool theory_seq::check_length_coherence(expr* e) {
|
|||
propagate_is_conc(e, conc);
|
||||
assume_equality(tail, emp);
|
||||
}
|
||||
m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e)));
|
||||
if (!get_context().at_base_level()) {
|
||||
m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -459,14 +461,14 @@ bool theory_seq::check_length_coherence() {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
lit => s != ""
|
||||
*/
|
||||
void theory_seq::propagate_non_empty(literal lit, expr* s) {
|
||||
SASSERT(get_context().get_assignment(lit) == l_true);
|
||||
propagate_lit(0, 1, &lit, ~mk_eq_empty(s));
|
||||
propagate_lit(0, 1, &lit, ~mk_eq_empty(s));
|
||||
}
|
||||
|
||||
void theory_seq::propagate_is_conc(expr* e, expr* conc) {
|
||||
|
@ -485,9 +487,9 @@ bool theory_seq::is_nth(expr* e) const {
|
|||
|
||||
bool theory_seq::is_tail(expr* e, expr*& s, unsigned& idx) const {
|
||||
rational r;
|
||||
return
|
||||
is_skolem(m_tail, e) &&
|
||||
m_autil.is_numeral(to_app(e)->get_arg(1), r) &&
|
||||
return
|
||||
is_skolem(m_tail, e) &&
|
||||
m_autil.is_numeral(to_app(e)->get_arg(1), r) &&
|
||||
(idx = r.get_unsigned(), s = to_app(e)->get_arg(0), true);
|
||||
}
|
||||
|
||||
|
@ -536,7 +538,7 @@ void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) {
|
|||
else {
|
||||
head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0)));
|
||||
tail = mk_skolem(m_tail, e, m_autil.mk_int(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -556,7 +558,7 @@ bool theory_seq::is_solved() {
|
|||
IF_VERBOSE(10, verbose_stream() << "(seq.giveup regular expression did not compile to automaton)\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -582,9 +584,9 @@ void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits
|
|||
literal_vector lits(n, _lits);
|
||||
enode_pair_vector eqs;
|
||||
linearize(dep, eqs, lits);
|
||||
TRACE("seq", ctx.display_detailed_literal(tout, lit);
|
||||
tout << " <- "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep););
|
||||
justification* js =
|
||||
TRACE("seq", ctx.display_detailed_literal(tout, lit);
|
||||
tout << " <- "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); if (!lits.empty()) tout << "\n"; display_deps(tout, dep););
|
||||
justification* js =
|
||||
ctx.mk_justification(
|
||||
ext_theory_propagation_justification(
|
||||
get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit));
|
||||
|
@ -598,7 +600,7 @@ void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) {
|
|||
enode_pair_vector eqs;
|
||||
literal_vector lits(_lits);
|
||||
linearize(dep, eqs, lits);
|
||||
TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep); ;);
|
||||
TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); if (!lits.empty()) tout << "\n"; display_deps(tout, dep); ;);
|
||||
m_new_propagation = true;
|
||||
ctx.set_conflict(
|
||||
ctx.mk_justification(
|
||||
|
@ -615,10 +617,10 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) {
|
|||
enode_pair_vector eqs;
|
||||
linearize(dep, eqs, lits);
|
||||
TRACE("seq",
|
||||
tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- ";
|
||||
tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- \n";
|
||||
display_deps(tout, dep);
|
||||
);
|
||||
|
||||
);
|
||||
|
||||
justification* js = ctx.mk_justification(
|
||||
ext_theory_eq_propagation_justification(
|
||||
get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), n1, n2));
|
||||
|
@ -652,16 +654,16 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc
|
|||
expr_ref_vector lhs(m), rhs(m);
|
||||
bool changed = false;
|
||||
if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, changed)) {
|
||||
// equality is inconsistent.x2
|
||||
// equality is inconsistent.
|
||||
TRACE("seq", tout << ls << " != " << rs << "\n";);
|
||||
set_conflict(deps);
|
||||
return true;
|
||||
}
|
||||
if (!changed) {
|
||||
if (!changed) {
|
||||
SASSERT(lhs.empty() && rhs.empty());
|
||||
return false;
|
||||
}
|
||||
SASSERT(lhs.size() == rhs.size());
|
||||
SASSERT(lhs.size() == rhs.size());
|
||||
m_seq_rewrite.add_seqs(ls, rs, lhs, rhs);
|
||||
if (lhs.empty()) {
|
||||
return true;
|
||||
|
@ -678,7 +680,7 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc
|
|||
else {
|
||||
propagate_eq(deps, ensure_enode(li), ensure_enode(ri));
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("seq",
|
||||
tout << ls << " = " << rs << " => \n";
|
||||
for (unsigned i = 0; i < lhs.size(); ++i) {
|
||||
|
@ -704,7 +706,7 @@ bool theory_seq::solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const&
|
|||
bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) {
|
||||
if (l == r) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (is_var(l) && !occurs(l, r) && add_solution(l, r, deps)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -724,7 +726,7 @@ bool theory_seq::occurs(expr* a, expr_ref_vector const& b) {
|
|||
}
|
||||
|
||||
bool theory_seq::occurs(expr* a, expr* b) {
|
||||
// true if a occurs under an interpreted function or under left/right selector.
|
||||
// true if a occurs under an interpreted function or under left/right selector.
|
||||
SASSERT(is_var(a));
|
||||
SASSERT(m_todo.empty());
|
||||
expr* e1, *e2;
|
||||
|
@ -739,18 +741,18 @@ bool theory_seq::occurs(expr* a, expr* b) {
|
|||
if (m_util.str.is_concat(b, e1, e2)) {
|
||||
m_todo.push_back(e1);
|
||||
m_todo.push_back(e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool theory_seq::is_var(expr* a) {
|
||||
return
|
||||
return
|
||||
m_util.is_seq(a) &&
|
||||
!m_util.str.is_concat(a) &&
|
||||
!m_util.str.is_empty(a) &&
|
||||
!m_util.str.is_string(a) &&
|
||||
!m_util.str.is_concat(a) &&
|
||||
!m_util.str.is_empty(a) &&
|
||||
!m_util.str.is_string(a) &&
|
||||
!m_util.str.is_unit(a);
|
||||
}
|
||||
|
||||
|
@ -787,7 +789,7 @@ bool theory_seq::solve_eqs(unsigned i) {
|
|||
m_eqs.pop_back();
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("seq", tout << "solve_eqs\n";);
|
||||
return change || ctx.inconsistent();
|
||||
}
|
||||
|
@ -809,7 +811,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de
|
|||
TRACE("seq", tout << ls << " = " << rs << "\n";);
|
||||
if (ls.empty() && rs.empty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!ctx.inconsistent() && solve_unit_eq(ls, rs, deps)) {
|
||||
TRACE("seq", tout << "unit\n";);
|
||||
return true;
|
||||
|
@ -840,7 +842,7 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, ptr_vector<expr>& xs, ptr_vector<expr>& ys, expr*& y) {
|
||||
bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, ptr_vector<expr>& xs, ptr_vector<expr>& ys, expr*& y) {
|
||||
if (ls.size() > 1 && is_var(ls[0]) &&
|
||||
rs.size() > 1 && is_var(rs.back())) {
|
||||
xs.reset();
|
||||
|
@ -883,7 +885,7 @@ bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector cons
|
|||
}
|
||||
if (xs.empty()) {
|
||||
// this should have been solved already
|
||||
UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
unsigned sz = xs.size();
|
||||
|
@ -958,7 +960,7 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
case l_false:
|
||||
return true;
|
||||
case l_true:
|
||||
break;
|
||||
break;
|
||||
case l_undef:
|
||||
++num_undef_lits;
|
||||
break;
|
||||
|
@ -979,12 +981,16 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
bool change = false;
|
||||
change = canonize(n.ls(i), ls, deps) || change;
|
||||
change = canonize(n.rs(i), rs, deps) || change;
|
||||
|
||||
|
||||
if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, change)) {
|
||||
return true;
|
||||
}
|
||||
else if (!change) {
|
||||
TRACE("seq", tout << "no change " << n.ls(i) << " " << n.rs(i) << "\n";);
|
||||
if (updated) {
|
||||
new_ls.push_back(n.ls(i));
|
||||
new_rs.push_back(n.rs(i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
|
@ -994,13 +1000,13 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
new_ls.push_back(n.ls(j));
|
||||
new_rs.push_back(n.rs(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
updated = true;
|
||||
if (!ls.empty() || !rs.empty()) {
|
||||
new_ls.push_back(ls);
|
||||
new_rs.push_back(rs);
|
||||
}
|
||||
TRACE("seq",
|
||||
TRACE("seq",
|
||||
for (unsigned j = 0; j < lhs.size(); ++j) {
|
||||
tout << mk_pp(lhs[j].get(), m) << " ";
|
||||
}
|
||||
|
@ -1012,7 +1018,7 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
expr* nr = rhs[j].get();
|
||||
if (m_util.is_seq(nl) || m_util.is_re(nl)) {
|
||||
ls.reset();
|
||||
rs.reset();
|
||||
rs.reset();
|
||||
SASSERT(!m_util.str.is_concat(nl));
|
||||
SASSERT(!m_util.str.is_concat(nr));
|
||||
ls.push_back(nl); rs.push_back(nr);
|
||||
|
@ -1034,7 +1040,7 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new_deps = m_dm.mk_join(deps, new_deps);
|
||||
}
|
||||
}
|
||||
|
@ -1046,7 +1052,7 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
new_ls.push_back(n.ls(j));
|
||||
new_rs.push_back(n.rs(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_undef_lits == 1 && new_ls.empty()) {
|
||||
literal_vector lits;
|
||||
|
@ -1065,10 +1071,10 @@ bool theory_seq::solve_ne(unsigned idx) {
|
|||
undef_lit = lit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("seq", tout << "propagate: " << undef_lit << "\n";);
|
||||
SASSERT(undef_lit != null_literal);
|
||||
propagate_lit(new_deps, lits.size(), lits.c_ptr(), ~undef_lit);
|
||||
propagate_lit(new_deps, lits.size(), lits.c_ptr(), ~undef_lit);
|
||||
return true;
|
||||
}
|
||||
if (updated) {
|
||||
|
@ -1097,14 +1103,14 @@ bool theory_seq::simplify_and_solve_eqs() {
|
|||
}
|
||||
|
||||
|
||||
bool theory_seq::internalize_term(app* term) {
|
||||
bool theory_seq::internalize_term(app* term) {
|
||||
context & ctx = get_context();
|
||||
if (ctx.e_internalized(term)) {
|
||||
enode* e = ctx.get_enode(term);
|
||||
mk_var(e);
|
||||
return true;
|
||||
}
|
||||
TRACE("seq", tout << mk_pp(term, m) << "\n";);
|
||||
TRACE("seq", tout << mk_pp(term, m) << "\n";);
|
||||
unsigned num_args = term->get_num_args();
|
||||
expr* arg;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
|
@ -1123,9 +1129,9 @@ bool theory_seq::internalize_term(app* term) {
|
|||
}
|
||||
else {
|
||||
e = ctx.mk_enode(term, false, m.is_bool(term), true);
|
||||
}
|
||||
}
|
||||
mk_var(e);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1153,13 +1159,13 @@ void theory_seq::enforce_length(enode* n) {
|
|||
}
|
||||
|
||||
void theory_seq::apply_sort_cnstr(enode* n, sort* s) {
|
||||
mk_var(n);
|
||||
mk_var(n);
|
||||
}
|
||||
|
||||
void theory_seq::display(std::ostream & out) const {
|
||||
if (m_eqs.size() == 0 &&
|
||||
m_nqs.size() == 0 &&
|
||||
m_rep.empty() &&
|
||||
m_nqs.size() == 0 &&
|
||||
m_rep.empty() &&
|
||||
m_exclude.empty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1195,9 +1201,9 @@ void theory_seq::display(std::ostream & out) const {
|
|||
void theory_seq::display_equations(std::ostream& out) const {
|
||||
for (unsigned i = 0; i < m_eqs.size(); ++i) {
|
||||
eq const& e = m_eqs[i];
|
||||
out << e.ls() << " = " << e.rs() << " <- ";
|
||||
out << e.ls() << " = " << e.rs() << " <- \n";
|
||||
display_deps(out, e.dep());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void theory_seq::display_disequations(std::ostream& out) const {
|
||||
|
@ -1220,7 +1226,7 @@ void theory_seq::display_disequation(std::ostream& out, ne const& e) const {
|
|||
out << e.ls(j) << " != " << e.rs(j) << "\n";
|
||||
}
|
||||
if (e.dep()) {
|
||||
display_deps(out, e.dep());
|
||||
display_deps(out, e.dep());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1229,13 +1235,13 @@ void theory_seq::display_deps(std::ostream& out, dependency* dep) const {
|
|||
enode_pair_vector eqs;
|
||||
linearize(dep, eqs, lits);
|
||||
for (unsigned i = 0; i < eqs.size(); ++i) {
|
||||
out << "\n " << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m);
|
||||
out << " " << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m) << "\n";
|
||||
}
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
literal lit = lits[i];
|
||||
get_context().display_literals_verbose(out << "\n ", 1, &lit);
|
||||
get_context().display_literals_verbose(out << " ", 1, &lit);
|
||||
out << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
void theory_seq::collect_statistics(::statistics & st) const {
|
||||
|
@ -1292,7 +1298,7 @@ public:
|
|||
return th.mk_value(n);
|
||||
}
|
||||
return th.mk_value(mg.get_manager().mk_app(n->get_decl(), values.size(), values.c_ptr()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1310,7 +1316,7 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
|||
e = concats[0];
|
||||
SASSERT(!m_util.str.is_concat(e));
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
e = m_rep.find(n->get_owner());
|
||||
SASSERT(m_util.str.is_concat(e));
|
||||
break;
|
||||
|
@ -1322,7 +1328,7 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
|||
}
|
||||
tout << "\n";
|
||||
);
|
||||
|
||||
|
||||
if (concats.size() > 1) {
|
||||
for (unsigned i = 0; i < concats.size(); ++i) {
|
||||
expr* e = concats[i];
|
||||
|
@ -1333,7 +1339,7 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
|
|||
}
|
||||
else if (m_util.str.is_unit(e, e1)) {
|
||||
sv->add_dependency(ctx.get_enode(e1));
|
||||
}
|
||||
}
|
||||
return sv;
|
||||
}
|
||||
|
||||
|
@ -1349,7 +1355,7 @@ void theory_seq::get_concat(expr* e, ptr_vector<expr>& concats) {
|
|||
if (!m_util.str.is_empty(e)) {
|
||||
concats.push_back(e);
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1366,7 +1372,7 @@ app* theory_seq::mk_value(app* e) {
|
|||
unsigned v = val.get_unsigned();
|
||||
if (false && ((v < 7) || (14 <= v && v < 32) || v == 127)) {
|
||||
// disabled: use escape characters.
|
||||
result = m_util.str.mk_unit(result);
|
||||
result = m_util.str.mk_unit(result);
|
||||
}
|
||||
else {
|
||||
svector<bool> val_as_bits;
|
||||
|
@ -1453,7 +1459,7 @@ bool theory_seq::canonize(expr* e, expr_ref_vector& es, dependency*& eqs) {
|
|||
canonize(e1, es, eqs);
|
||||
e3 = e2;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_empty(e3)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1461,7 +1467,7 @@ bool theory_seq::canonize(expr* e, expr_ref_vector& es, dependency*& eqs) {
|
|||
expr_ref e4 = expand(e3, eqs);
|
||||
change |= e4 != e3;
|
||||
m_util.str.get_concat(e4, es);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return change;
|
||||
|
@ -1490,7 +1496,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) {
|
|||
expr* e1, *e2;
|
||||
if (m_util.str.is_concat(e, e1, e2)) {
|
||||
result = mk_concat(expand(e1, deps), expand(e2, deps));
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) {
|
||||
result = e;
|
||||
}
|
||||
|
@ -1534,7 +1540,7 @@ void theory_seq::propagate() {
|
|||
}
|
||||
while (!m_replay.empty() && !ctx.inconsistent()) {
|
||||
(*m_replay[m_replay.size()-1])(*this);
|
||||
TRACE("seq", tout << "replay: " << ctx.get_scope_level() << "\n";);
|
||||
TRACE("seq", tout << "replay at level: " << ctx.get_scope_level() << "\n";);
|
||||
m_replay.pop_back();
|
||||
}
|
||||
if (m_new_solution) {
|
||||
|
@ -1554,7 +1560,7 @@ void theory_seq::enque_axiom(expr* e) {
|
|||
}
|
||||
|
||||
void theory_seq::deque_axiom(expr* n) {
|
||||
if (m_util.str.is_length(n)) {
|
||||
if (m_util.str.is_length(n)) {
|
||||
add_length_axiom(n);
|
||||
}
|
||||
else if (m_util.str.is_empty(n) && !has_length(n) && !m_length.empty()) {
|
||||
|
@ -1581,7 +1587,7 @@ void theory_seq::deque_axiom(expr* n) {
|
|||
/*
|
||||
encode that s is not a proper prefix of xs1
|
||||
where s1 is all of s, except the last element.
|
||||
|
||||
|
||||
lit or s = "" or s = s1*(unit c)
|
||||
lit or s = "" or !prefix(s, x*s1)
|
||||
*/
|
||||
|
@ -1598,7 +1604,7 @@ void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) {
|
|||
// index of s in t starting at offset.
|
||||
|
||||
let i = Index(t, s, offset):
|
||||
|
||||
|
||||
offset >= len(t) => i = -1
|
||||
|
||||
offset fixed to 0:
|
||||
|
@ -1609,17 +1615,17 @@ void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) {
|
|||
|
||||
offset not fixed:
|
||||
|
||||
0 <= offset < len(t) => xy = t &
|
||||
len(x) = offset &
|
||||
(-1 = indexof(y, s, 0) => -1 = i) &
|
||||
0 <= offset < len(t) => xy = t &
|
||||
len(x) = offset &
|
||||
(-1 = indexof(y, s, 0) => -1 = i) &
|
||||
(indexof(y, s, 0) >= 0 => indexof(t, s, 0) + offset = i)
|
||||
|
||||
if offset < 0
|
||||
|
||||
if offset < 0
|
||||
under specified
|
||||
|
||||
optional lemmas:
|
||||
(len(s) > len(t) -> i = -1)
|
||||
(len(s) <= len(t) -> i <= len(t)-len(s))
|
||||
(len(s) > len(t) -> i = -1)
|
||||
(len(s) <= len(t) -> i <= len(t)-len(s))
|
||||
*/
|
||||
void theory_seq::add_indexof_axiom(expr* i) {
|
||||
expr* s, *t, *offset;
|
||||
|
@ -1636,7 +1642,7 @@ void theory_seq::add_indexof_axiom(expr* i) {
|
|||
|
||||
if (m_autil.is_numeral(offset, r) && r.is_zero()) {
|
||||
expr_ref x = mk_skolem(m_contains_left, t, s);
|
||||
expr_ref y = mk_skolem(m_contains_right, t, s);
|
||||
expr_ref y = mk_skolem(m_contains_right, t, s);
|
||||
xsy = mk_concat(x,s,y);
|
||||
literal cnt = mk_literal(m_util.str.mk_contains(t, s));
|
||||
literal eq_empty = mk_eq_empty(s);
|
||||
|
@ -1651,36 +1657,36 @@ void theory_seq::add_indexof_axiom(expr* i) {
|
|||
expr_ref indexof0(m_util.str.mk_index(y, s, zero), m);
|
||||
expr_ref offset_p_indexof0(m_autil.mk_add(offset, indexof0), m);
|
||||
literal offset_ge_0 = mk_literal(m_autil.mk_ge(offset, zero));
|
||||
|
||||
// 0 <= offset & offset < len(t) => t = xy
|
||||
|
||||
// 0 <= offset & offset < len(t) => t = xy
|
||||
// 0 <= offset & offset < len(t) => len(x) = offset
|
||||
// 0 <= offset & offset < len(t) & -1 = indexof(y,s,0) = -1 => -1 = i
|
||||
// 0 <= offset & offset < len(t) & indexof(y,s,0) >= 0 = -1 =>
|
||||
// 0 <= offset & offset < len(t) & indexof(y,s,0) >= 0 = -1 =>
|
||||
// -1 = indexof(y,s,0) + offset = indexof(t, s, offset)
|
||||
|
||||
|
||||
add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, mk_concat(x, y), false));
|
||||
add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false));
|
||||
add_axiom(~offset_ge_0, offset_ge_len,
|
||||
add_axiom(~offset_ge_0, offset_ge_len,
|
||||
~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false));
|
||||
add_axiom(~offset_ge_0, offset_ge_len,
|
||||
~mk_literal(m_autil.mk_ge(indexof0, zero)),
|
||||
add_axiom(~offset_ge_0, offset_ge_len,
|
||||
~mk_literal(m_autil.mk_ge(indexof0, zero)),
|
||||
mk_eq(offset_p_indexof0, i, false));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
let r = replace(a, s, t)
|
||||
|
||||
|
||||
(contains(a, s) -> tightest_prefix(s,xs))
|
||||
(contains(a, s) -> r = xty & a = xsy) &
|
||||
(contains(a, s) -> r = xty & a = xsy) &
|
||||
(!contains(a, s) -> r = a)
|
||||
|
||||
|
||||
*/
|
||||
void theory_seq::add_replace_axiom(expr* r) {
|
||||
expr* a, *s, *t;
|
||||
VERIFY(m_util.str.is_replace(r, a, s, t));
|
||||
expr_ref x = mk_skolem(m_contains_left, a, s);
|
||||
expr_ref y = mk_skolem(m_contains_right, a, s);
|
||||
expr_ref y = mk_skolem(m_contains_right, a, s);
|
||||
expr_ref xty = mk_concat(x, t, y);
|
||||
expr_ref xsy = mk_concat(x, s, y);
|
||||
literal cnt = mk_literal(m_util.str.mk_contains(a ,s));
|
||||
|
@ -1716,6 +1722,7 @@ void theory_seq::add_elim_string_axiom(expr* n) {
|
|||
- len(x) >= 0 otherwise
|
||||
*/
|
||||
void theory_seq::add_length_axiom(expr* n) {
|
||||
context& ctx = get_context();
|
||||
expr* x;
|
||||
VERIFY(m_util.str.is_length(n, x));
|
||||
if (m_util.str.is_concat(x) ||
|
||||
|
@ -1726,12 +1733,15 @@ void theory_seq::add_length_axiom(expr* n) {
|
|||
m_rewrite(len);
|
||||
SASSERT(n != len);
|
||||
add_axiom(mk_eq(len, n, false));
|
||||
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, n)));
|
||||
if (!ctx.at_base_level()) {
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, n)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, n)));
|
||||
add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
|
||||
if (!ctx.at_base_level()) {
|
||||
m_trail_stack.push(push_replay(alloc(replay_axiom, m, n)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1915,7 +1925,7 @@ void theory_seq::add_extract_axiom(expr* e) {
|
|||
expr_ref ls_minus_i(mk_sub(ls, i), m);
|
||||
expr_ref xe = mk_concat(x, e);
|
||||
expr_ref zero(m_autil.mk_int(0), m);
|
||||
|
||||
|
||||
literal i_ge_0 = mk_literal(m_autil.mk_ge(i, zero));
|
||||
literal i_ge_ls = mk_literal(m_autil.mk_ge(mk_sub(i, ls), zero));
|
||||
literal l_ge_ls = mk_literal(m_autil.mk_ge(mk_sub(l, ls), zero));
|
||||
|
@ -1924,14 +1934,14 @@ void theory_seq::add_extract_axiom(expr* e) {
|
|||
add_axiom(~i_ge_0, i_ge_ls, mk_literal(m_util.str.mk_prefix(xe, s)));
|
||||
add_axiom(~i_ge_0, i_ge_ls, mk_eq(lx, i, false));
|
||||
add_axiom(~i_ge_0, i_ge_ls, ~l_ge_ls, mk_eq(le, ls_minus_i, false));
|
||||
add_axiom(~i_ge_0, i_ge_ls, l_ge_zero, mk_eq(le, zero, false));
|
||||
add_axiom(~i_ge_0, i_ge_ls, l_ge_zero, mk_eq(le, zero, false));
|
||||
}
|
||||
|
||||
/*
|
||||
let e = at(s, i)
|
||||
|
||||
|
||||
0 <= i < len(s) -> s = xey & len(x) = i & len(e) = 1
|
||||
|
||||
|
||||
*/
|
||||
void theory_seq::add_at_axiom(expr* e) {
|
||||
expr* s, *i;
|
||||
|
@ -1985,7 +1995,7 @@ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) {
|
|||
unsigned _idx = r.get_unsigned();
|
||||
expr_ref head(m), tail(m), conc(m), len1(m), len2(m);
|
||||
expr_ref_vector elems(m);
|
||||
|
||||
|
||||
expr* s2 = s;
|
||||
for (unsigned j = 0; j <= _idx; ++j) {
|
||||
mk_decompose(s2, head, tail);
|
||||
|
@ -2035,7 +2045,7 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) {
|
|||
}
|
||||
|
||||
|
||||
expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1,
|
||||
expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1,
|
||||
expr* e2, expr* e3, sort* range) {
|
||||
expr* es[3] = { e1, e2, e3 };
|
||||
unsigned len = e3?3:(e2?2:1);
|
||||
|
@ -2064,12 +2074,12 @@ void theory_seq::propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs)
|
|||
SASSERT(l_true == ctx.get_assignment(lit));
|
||||
dependency* deps = m_dm.mk_leaf(assumption(lit));
|
||||
new_eq_eh(deps, n1, n2);
|
||||
|
||||
|
||||
}
|
||||
TRACE("seq",
|
||||
tout << mk_pp(ctx.bool_var2expr(lit.var()), m) << " => "
|
||||
<< mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";);
|
||||
justification* js =
|
||||
TRACE("seq",
|
||||
tout << mk_pp(ctx.bool_var2expr(lit.var()), m) << " => "
|
||||
<< mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";);
|
||||
justification* js =
|
||||
ctx.mk_justification(
|
||||
ext_theory_eq_propagation_justification(
|
||||
get_id(), ctx.get_region(), 1, &lit, 0, 0, n1, n2));
|
||||
|
@ -2171,7 +2181,7 @@ void theory_seq::add_atom(expr* e) {
|
|||
m_atoms.push_back(e);
|
||||
}
|
||||
|
||||
void theory_seq::new_eq_eh(theory_var v1, theory_var v2) {
|
||||
void theory_seq::new_eq_eh(theory_var v1, theory_var v2) {
|
||||
enode* n1 = get_enode(v1);
|
||||
enode* n2 = get_enode(v2);
|
||||
dependency* deps = m_dm.mk_leaf(assumption(n1, n2));
|
||||
|
@ -2183,7 +2193,7 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
|
|||
expr_ref o1(n1->get_owner(), m);
|
||||
expr_ref o2(n2->get_owner(), m);
|
||||
TRACE("seq", tout << o1 << " = " << o2 << "\n";);
|
||||
m_eqs.push_back(mk_eqdep(o1, o2, deps));
|
||||
m_eqs.push_back(mk_eqdep(o1, o2, deps));
|
||||
solve_eqs(m_eqs.size()-1);
|
||||
enforce_length_coherence(n1, n2);
|
||||
}
|
||||
|
@ -2198,6 +2208,7 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
|
|||
expr_ref eq(m.mk_eq(e1, e2), m);
|
||||
m_rewrite(eq);
|
||||
if (!m.is_false(eq)) {
|
||||
TRACE("seq", tout << "new disequality: " << eq << "\n";);
|
||||
literal lit = ~mk_eq(e1, e2, false);
|
||||
//SASSERT(get_context().get_assignment(lit) == l_true);
|
||||
dependency* dep = m_dm.mk_leaf(assumption(lit));
|
||||
|
@ -2221,8 +2232,8 @@ void theory_seq::push_scope_eh() {
|
|||
|
||||
void theory_seq::pop_scope_eh(unsigned num_scopes) {
|
||||
m_trail_stack.pop_scope(num_scopes);
|
||||
theory::pop_scope_eh(num_scopes);
|
||||
m_dm.pop_scope(num_scopes);
|
||||
theory::pop_scope_eh(num_scopes);
|
||||
m_dm.pop_scope(num_scopes);
|
||||
m_rep.pop_scope(num_scopes);
|
||||
m_exclude.pop_scope(num_scopes);
|
||||
m_eqs.pop_scope(num_scopes);
|
||||
|
@ -2234,7 +2245,7 @@ void theory_seq::pop_scope_eh(unsigned num_scopes) {
|
|||
void theory_seq::restart_eh() {
|
||||
}
|
||||
|
||||
void theory_seq::relevant_eh(app* n) {
|
||||
void theory_seq::relevant_eh(app* n) {
|
||||
if (m_util.str.is_index(n) ||
|
||||
m_util.str.is_replace(n) ||
|
||||
m_util.str.is_extract(n) ||
|
||||
|
@ -2263,7 +2274,7 @@ eautomaton* theory_seq::get_automaton(expr* re) {
|
|||
}
|
||||
m_automata.push_back(result);
|
||||
m_trail_stack.push(push_back_vector<theory_seq, scoped_ptr_vector<eautomaton> >(m_automata));
|
||||
|
||||
|
||||
m_re2aut.insert(re, result);
|
||||
m_trail_stack.push(insert_obj_map<theory_seq, expr, eautomaton*>(m_re2aut, re));
|
||||
return result;
|
||||
|
@ -2290,7 +2301,7 @@ bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, exp
|
|||
VERIFY(m_autil.is_numeral(to_app(e)->get_arg(3), r));
|
||||
SASSERT(r.is_unsigned());
|
||||
i = r.get_unsigned();
|
||||
aut = get_automaton(re);
|
||||
aut = get_automaton(re);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -2317,7 +2328,7 @@ bool theory_seq::is_step(expr* e, expr*& s, expr*& idx, expr*& re, expr*& i, exp
|
|||
}
|
||||
}
|
||||
|
||||
expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, expr* acc) {
|
||||
expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, expr* acc) {
|
||||
SASSERT(m.is_bool(acc));
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(s).push_back(idx).push_back(re);
|
||||
|
@ -2352,7 +2363,7 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) {
|
|||
propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx)));
|
||||
}
|
||||
else {
|
||||
propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx)));
|
||||
propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2362,7 +2373,7 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) {
|
|||
*/
|
||||
bool theory_seq::add_accept2step(expr* acc) {
|
||||
context& ctx = get_context();
|
||||
|
||||
|
||||
TRACE("seq", tout << mk_pp(acc, m) << "\n";);
|
||||
SASSERT(ctx.get_assignment(acc) == l_true);
|
||||
expr *e, * idx, *re;
|
||||
|
@ -2376,7 +2387,7 @@ bool theory_seq::add_accept2step(expr* acc) {
|
|||
SASSERT(m_autil.is_numeral(idx));
|
||||
eautomaton::moves mvs;
|
||||
aut->get_moves_from(src, mvs);
|
||||
|
||||
|
||||
expr_ref len(m_util.str.mk_length(e), m);
|
||||
literal_vector lits;
|
||||
lits.push_back(~ctx.get_literal(acc));
|
||||
|
@ -2386,7 +2397,7 @@ bool theory_seq::add_accept2step(expr* acc) {
|
|||
case l_true:
|
||||
return false;
|
||||
case l_undef:
|
||||
ctx.force_phase(lits.back());
|
||||
ctx.force_phase(lits.back());
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
|
@ -2424,9 +2435,9 @@ bool theory_seq::add_accept2step(expr* acc) {
|
|||
}
|
||||
if (has_undef) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";);
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
SASSERT(ctx.get_assignment(lits[i]) == l_false);
|
||||
lits[i].neg();
|
||||
}
|
||||
|
@ -2452,7 +2463,7 @@ bool theory_seq::add_step2accept(expr* step) {
|
|||
return true;
|
||||
case l_true: {
|
||||
rational r;
|
||||
VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned());
|
||||
VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned());
|
||||
expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m);
|
||||
literal acc2 = mk_accept(s, idx1, re, j);
|
||||
literal_vector lits;
|
||||
|
@ -2478,14 +2489,14 @@ bool theory_seq::add_step2accept(expr* step) {
|
|||
|
||||
/*
|
||||
rej(s, idx, re, i) & nth(s, idx) = t & idx < len(s) => rej(s, idx + 1, re, j)
|
||||
|
||||
|
||||
len(s) > idx -> s = (nth 0 s) ++ .. ++ (nth idx s) ++ (tail idx s)
|
||||
|
||||
Recall we also have:
|
||||
rej(s, idx, re, i) -> len(s) >= idx if i is non-final
|
||||
rej(s, idx, re, i) -> len(s) > idx if i is final
|
||||
|
||||
*/
|
||||
*/
|
||||
bool theory_seq::add_reject2reject(expr* rej) {
|
||||
context& ctx = get_context();
|
||||
SASSERT(ctx.get_assignment(rej) == l_true);
|
||||
|
@ -2503,7 +2514,7 @@ bool theory_seq::add_reject2reject(expr* rej) {
|
|||
expr_ref len(m_util.str.mk_length(s), m);
|
||||
literal len_le_idx = mk_literal(m_autil.mk_le(len, idx));
|
||||
switch (ctx.get_assignment(len_le_idx)) {
|
||||
case l_true:
|
||||
case l_true:
|
||||
return false;
|
||||
case l_undef:
|
||||
ctx.force_phase(len_le_idx);
|
||||
|
@ -2511,13 +2522,13 @@ bool theory_seq::add_reject2reject(expr* rej) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
expr_ref nth = mk_nth(s, idx);
|
||||
expr_ref nth = mk_nth(s, idx);
|
||||
ensure_nth(~len_le_idx, s, idx);
|
||||
literal_vector eqs;
|
||||
bool has_undef = false;
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
eautomaton::move const& mv = mvs[i];
|
||||
literal eq = mk_literal(mv.t()->accept(nth));
|
||||
eautomaton::move const& mv = mvs[i];
|
||||
literal eq = mk_literal(mv.t()->accept(nth));
|
||||
switch (ctx.get_assignment(eq)) {
|
||||
case l_false:
|
||||
case l_true:
|
||||
|
@ -2533,18 +2544,18 @@ bool theory_seq::add_reject2reject(expr* rej) {
|
|||
return true;
|
||||
}
|
||||
for (unsigned i = 0; i < mvs.size(); ++i) {
|
||||
eautomaton::move const& mv = mvs[i];
|
||||
eautomaton::move const& mv = mvs[i];
|
||||
literal eq = eqs[i];
|
||||
if (ctx.get_assignment(eq) == l_true) {
|
||||
literal rej2 = mk_reject(s, idx1, re, m_autil.mk_int(mv.dst()));
|
||||
add_axiom(~rej1, ~eq, len_le_idx, rej2);
|
||||
}
|
||||
add_axiom(~rej1, ~eq, len_le_idx, rej2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
!prefix -> e2 = emp \/ nth(e1,0) != nth(e2,0) \/ !prefix(tail(e1),tail(e2))
|
||||
!prefix -> e2 = emp \/ nth(e1,0) != nth(e2,0) \/ !prefix(tail(e1),tail(e2))
|
||||
*/
|
||||
bool theory_seq::add_prefix2prefix(expr* e) {
|
||||
context& ctx = get_context();
|
||||
|
@ -2566,7 +2577,7 @@ bool theory_seq::add_prefix2prefix(expr* e) {
|
|||
expr_ref head1(m), tail1(m), head2(m), tail2(m);
|
||||
mk_decompose(e1, head1, tail1);
|
||||
mk_decompose(e2, head2, tail2);
|
||||
|
||||
|
||||
literal lit = mk_eq(head1, head2, false);
|
||||
switch (ctx.get_assignment(lit)) {
|
||||
case l_true: {
|
||||
|
@ -2615,7 +2626,7 @@ bool theory_seq::add_suffix2suffix(expr* e) {
|
|||
expr_ref last1 = mk_last(e1);
|
||||
expr_ref conc = mk_concat(first2, m_util.str.mk_unit(last2));
|
||||
propagate_eq(~mk_eq(e2, emp, false), e2, conc);
|
||||
|
||||
|
||||
literal last_eq = mk_eq(last1, last2, false);
|
||||
switch (ctx.get_assignment(last_eq)) {
|
||||
case l_false:
|
||||
|
@ -2632,7 +2643,7 @@ bool theory_seq::add_suffix2suffix(expr* e) {
|
|||
lits.push_back(~mk_eq(e2, emp, false));
|
||||
lits.push_back(last_eq);
|
||||
propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_suffix(first1, first2)));
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool theory_seq::canonizes(bool sign, expr* e) {
|
||||
|
@ -2666,7 +2677,7 @@ bool theory_seq::add_contains2contains(expr* e) {
|
|||
return false;
|
||||
}
|
||||
expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m);
|
||||
|
||||
|
||||
switch (assume_equality(e1, emp)) {
|
||||
case l_true:
|
||||
return false; // done
|
||||
|
@ -2714,7 +2725,7 @@ bool theory_seq::propagate_automata() {
|
|||
if (reQ) {
|
||||
re_add.push_back(e);
|
||||
}
|
||||
++m_atoms_qhead;
|
||||
++m_atoms_qhead;
|
||||
}
|
||||
m_atoms.append(re_add);
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue