Skip to content

Commit 0528c86

Browse files
fix #7745
axioms for len(substr(...)) escaped due to nested rewriting
1 parent 95be0cf commit 0528c86

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

src/ast/rewriter/seq_axioms.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,16 +1224,39 @@ namespace seq {
12241224
let n = len(x)
12251225
- len(a ++ b) = len(a) + len(b) if x = a ++ b
12261226
- len(unit(u)) = 1 if x = unit(u)
1227+
- len(extract(x, o, l)) = l if len(x) >= o + l etc
12271228
- len(str) = str.length() if x = str
12281229
- len(empty) = 0 if x = empty
12291230
- len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|))
12301231
- len(x) >= 0 otherwise
12311232
*/
12321233
void axioms::length_axiom(expr* n) {
1233-
expr* x = nullptr;
1234+
expr* x = nullptr, * y = nullptr, * offs = nullptr, * l = nullptr;
12341235
VERIFY(seq.str.is_length(n, x));
1235-
if (seq.str.is_concat(x) ||
1236-
seq.str.is_unit(x) ||
1236+
if (seq.str.is_concat(x) && to_app(x)->get_num_args() != 0) {
1237+
ptr_vector<expr> args;
1238+
for (auto arg : *to_app(x))
1239+
args.push_back(seq.str.mk_length(arg));
1240+
expr_ref len(a.mk_add(args), m);
1241+
add_clause(mk_eq(len, n));
1242+
}
1243+
else if (seq.str.is_extract(x, y, offs, l)) {
1244+
// len(extract(y, o, l)) = l if len(y) >= o + l, o >= 0, l >= 0
1245+
// len(extract(y, o, l)) = 0 if o < 0 or l <= 0 or len(y) < o
1246+
// len(extract(y, o, l)) = o + l - len(y) if o <= len(y) < o + l
1247+
expr_ref len_y(mk_len(y), m);
1248+
expr_ref z(a.mk_int(0), m);
1249+
expr_ref y_ge_l(a.mk_ge(len_y, a.mk_add(offs, l)), m);
1250+
expr_ref y_ge_o(a.mk_ge(len_y, offs), m);
1251+
expr_ref offs_ge_0(a.mk_ge(offs, z), m);
1252+
expr_ref l_ge_0(a.mk_ge(l, z), m);
1253+
add_clause(~offs_ge_0, ~l_ge_0, ~y_ge_l, mk_eq(n, l));
1254+
add_clause(offs_ge_0, mk_eq(n, z));
1255+
add_clause(l_ge_0, mk_eq(n, z));
1256+
add_clause(y_ge_o, mk_eq(n, z));
1257+
add_clause(~y_ge_o, y_ge_l, mk_eq(n, a.mk_sub(a.mk_add(offs, l), len_y)));
1258+
}
1259+
else if (seq.str.is_unit(x) ||
12371260
seq.str.is_empty(x) ||
12381261
seq.str.is_string(x)) {
12391262
expr_ref len(n, m);

src/smt/theory_seq.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,6 @@ final_check_status theory_seq::final_check_eh() {
439439
}
440440

441441

442-
443442
bool theory_seq::set_empty(expr* x) {
444443
add_axiom(~mk_eq(m_autil.mk_int(0), mk_len(x), false), mk_eq_empty(x));
445444
return true;
@@ -475,9 +474,8 @@ bool theory_seq::check_fixed_length(bool is_zero, bool check_long_strings) {
475474
bool found = false;
476475
for (unsigned i = 0; i < m_length.size(); ++i) {
477476
expr* e = m_length.get(i);
478-
if (fixed_length(e, is_zero, check_long_strings)) {
479-
found = true;
480-
}
477+
if (fixed_length(e, is_zero, check_long_strings))
478+
found = true;
481479
}
482480
return found;
483481
}

0 commit comments

Comments
 (0)