3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-20 21:03:39 +00:00

more seq overhaul

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-04-18 17:32:28 -07:00
parent 76735476d4
commit a9c4984a16
13 changed files with 1888 additions and 1860 deletions

View file

@ -2566,31 +2566,34 @@ bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs, bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) { expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
expr* n = nullptr;
expr* l, *r;
is_sat = true; is_sat = true;
if (szl == 1 && m_util.str.is_itos(ls[0], l)) { if (szl == 1 && m_util.str.is_itos(ls[0], n) &&
if (szr == 1 && m_util.str.is_itos(rs[0], r)) { solve_itos(n, szr, rs, lhs, rhs)) {
lhs.push_back(l); return true;
rhs.push_back(r); }
if (szr == 1 && m_util.str.is_itos(rs[0], n) &&
solve_itos(n, szl, ls, rhs, lhs)) {
return true;
}
return false;
}
/**
* itos(n) = <numeric string> -> n = numeric
*/
bool seq_rewriter::solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_vector& lhs, expr_ref_vector& rhs) {
zstring s;
if (is_string(sz, es, s)) {
std::string s1 = s.encode();
rational r(s1.c_str());
if (s1 == r.to_string()) {
lhs.push_back(n);
rhs.push_back(m_autil.mk_numeral(r, true));
return true; return true;
} }
zstring s;
if (is_string(szr, rs, s)) {
std::string s1 = s.encode();
rational r(s1.c_str());
if (s1 == r.to_string()) {
lhs.push_back(l);
rhs.push_back(m_autil.mk_numeral(r, true));
return true;
}
}
} }
if (szr == 1 && szl >= 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) {
return solve_itos(szr, rs, szl, ls, rhs, lhs, is_sat);
}
return false; return false;
} }

View file

@ -153,6 +153,7 @@ class seq_rewriter {
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat); expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool solve_itos(unsigned n, expr* const* l, unsigned m, expr* const* r, bool solve_itos(unsigned n, expr* const* l, unsigned m, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat); expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_vector& lhs, expr_ref_vector& rhs);
bool min_length(unsigned n, expr* const* es, unsigned& len); bool min_length(unsigned n, expr* const* es, unsigned& len);
expr* concat_non_empty(unsigned n, expr* const* es); expr* concat_non_empty(unsigned n, expr* const* es);

View file

@ -209,7 +209,7 @@ public:
} }
template <enum with_deps_t wd> template <enum with_deps_t wd>
void power(const interval& a, unsigned n, interval& b) { void power(const interval& a, unsigned n, interval& b) {
if (with_deps == wd) { if (with_deps == wd) {
interval_deps_combine_rule combine_rule; interval_deps_combine_rule combine_rule;
m_imanager.power(a, n, b, combine_rule); m_imanager.power(a, n, b, combine_rule);

View file

@ -14,6 +14,7 @@ z3_add_component(smt
qi_queue.cpp qi_queue.cpp
seq_axioms.cpp seq_axioms.cpp
seq_skolem.cpp seq_skolem.cpp
seq_eq_solver.cpp
smt_almost_cg_table.cpp smt_almost_cg_table.cpp
smt_arith_value.cpp smt_arith_value.cpp
smt_case_split_queue.cpp smt_case_split_queue.cpp

View file

@ -120,13 +120,13 @@ void seq_axioms::add_extract_axiom(expr* e) {
expr_ref xey = mk_concat(x, e, y); expr_ref xey = mk_concat(x, e, y);
expr_ref zero(a.mk_int(0), m); expr_ref zero(a.mk_int(0), m);
literal i_ge_0 = mk_literal(a.mk_ge(i, zero)); literal i_ge_0 = mk_ge(i, zero);
literal i_le_ls = mk_literal(a.mk_le(mk_sub(i, ls), zero)); literal i_le_ls = mk_le(mk_sub(i, ls), zero);
literal ls_le_i = mk_literal(a.mk_le(mk_sub(ls, i), zero)); literal ls_le_i = mk_le(mk_sub(ls, i), zero);
literal ls_ge_li = mk_literal(a.mk_ge(ls_minus_i_l, zero)); literal ls_ge_li = mk_ge(ls_minus_i_l, zero);
literal l_ge_0 = mk_literal(a.mk_ge(l, zero)); literal l_ge_0 = mk_ge(l, zero);
literal l_le_0 = mk_literal(a.mk_le(l, zero)); literal l_le_0 = mk_le(l, zero);
literal ls_le_0 = mk_literal(a.mk_le(ls, zero)); literal ls_le_0 = mk_le(ls, zero);
literal le_is_0 = mk_eq(le, zero); literal le_is_0 = mk_eq(le, zero);
@ -214,8 +214,8 @@ void seq_axioms::add_extract_prefix_axiom(expr* e, expr* s, expr* l) {
expr_ref zero(a.mk_int(0), m); expr_ref zero(a.mk_int(0), m);
expr_ref y = m_sk.mk_post(s, l); expr_ref y = m_sk.mk_post(s, l);
expr_ref ey = mk_concat(e, y); expr_ref ey = mk_concat(e, y);
literal l_ge_0 = mk_literal(a.mk_ge(l, zero)); literal l_ge_0 = mk_ge(l, zero);
literal l_le_s = mk_literal(a.mk_le(mk_sub(l, ls), zero)); literal l_le_s = mk_le(mk_sub(l, ls), zero);
add_axiom(~l_ge_0, ~l_le_s, mk_seq_eq(s, ey)); add_axiom(~l_ge_0, ~l_le_s, mk_seq_eq(s, ey));
add_axiom(~l_ge_0, ~l_le_s, mk_eq(l, le)); add_axiom(~l_ge_0, ~l_le_s, mk_eq(l, le));
add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, mk_len(y))); add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, mk_len(y)));
@ -236,8 +236,8 @@ void seq_axioms::add_extract_suffix_axiom(expr* e, expr* s, expr* i) {
expr_ref zero(a.mk_int(0), m); expr_ref zero(a.mk_int(0), m);
expr_ref xe = mk_concat(x, e); expr_ref xe = mk_concat(x, e);
literal le_is_0 = mk_eq_empty(e); literal le_is_0 = mk_eq_empty(e);
literal i_ge_0 = mk_literal(a.mk_ge(i, zero)); literal i_ge_0 = mk_ge(i, zero);
literal i_le_s = mk_literal(a.mk_le(mk_sub(i, ls), zero)); literal i_le_s = mk_le(mk_sub(i, ls), zero);
add_axiom(~i_ge_0, ~i_le_s, mk_seq_eq(s, xe)); add_axiom(~i_ge_0, ~i_le_s, mk_seq_eq(s, xe));
add_axiom(~i_ge_0, ~i_le_s, mk_eq(i, lx)); add_axiom(~i_ge_0, ~i_le_s, mk_eq(i, lx));
add_axiom(i_ge_0, le_is_0); add_axiom(i_ge_0, le_is_0);
@ -328,7 +328,7 @@ void seq_axioms::add_indexof_axiom(expr* i) {
add_axiom(~s_eq_empty, i_eq_0); add_axiom(~s_eq_empty, i_eq_0);
add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy)); add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy));
add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx)); add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx));
add_axiom(~cnt, mk_literal(a.mk_ge(i, zero))); add_axiom(~cnt, mk_ge(i, zero));
tightest_prefix(s, x); tightest_prefix(s, x);
} }
else { else {
@ -336,8 +336,8 @@ void seq_axioms::add_indexof_axiom(expr* i) {
// offset > len(t) => indexof(t, s, offset) = -1 // offset > len(t) => indexof(t, s, offset) = -1
// offset = len(t) & |s| = 0 => indexof(t, s, offset) = offset // offset = len(t) & |s| = 0 => indexof(t, s, offset) = offset
expr_ref len_t = mk_len(t); expr_ref len_t = mk_len(t);
literal offset_ge_len = mk_literal(a.mk_ge(mk_sub(offset, len_t), zero)); literal offset_ge_len = mk_ge(mk_sub(offset, len_t), zero);
literal offset_le_len = mk_literal(a.mk_le(mk_sub(offset, len_t), zero)); literal offset_le_len = mk_le(mk_sub(offset, len_t), zero);
literal i_eq_offset = mk_eq(i, offset); literal i_eq_offset = mk_eq(i, offset);
add_axiom(~offset_ge_len, s_eq_empty, i_eq_m1); add_axiom(~offset_ge_len, s_eq_empty, i_eq_m1);
add_axiom(offset_le_len, i_eq_m1); add_axiom(offset_le_len, i_eq_m1);
@ -347,7 +347,7 @@ void seq_axioms::add_indexof_axiom(expr* i) {
expr_ref y = m_sk.mk_indexof_right(t, s, offset); expr_ref y = m_sk.mk_indexof_right(t, s, offset);
expr_ref indexof0(seq.str.mk_index(y, s, zero), m); expr_ref indexof0(seq.str.mk_index(y, s, zero), m);
expr_ref offset_p_indexof0(a.mk_add(offset, indexof0), m); expr_ref offset_p_indexof0(a.mk_add(offset, indexof0), m);
literal offset_ge_0 = mk_literal(a.mk_ge(offset, zero)); literal offset_ge_0 = 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) => len(x) = offset
@ -360,7 +360,7 @@ void seq_axioms::add_indexof_axiom(expr* i) {
add_axiom(~offset_ge_0, offset_ge_len, add_axiom(~offset_ge_0, offset_ge_len,
~mk_eq(indexof0, minus_one), i_eq_m1); ~mk_eq(indexof0, minus_one), i_eq_m1);
add_axiom(~offset_ge_0, offset_ge_len, add_axiom(~offset_ge_0, offset_ge_len,
~mk_literal(a.mk_ge(indexof0, zero)), ~mk_ge(indexof0, zero),
mk_eq(offset_p_indexof0, i)); mk_eq(offset_p_indexof0, i));
// offset < 0 => -1 = i // offset < 0 => -1 = i
@ -451,8 +451,8 @@ void seq_axioms::add_at_axiom(expr* e) {
expr_ref one(a.mk_int(1), m); expr_ref one(a.mk_int(1), m);
expr_ref emp(seq.str.mk_empty(m.get_sort(e)), m); expr_ref emp(seq.str.mk_empty(m.get_sort(e)), m);
expr_ref len_s = mk_len(s); expr_ref len_s = mk_len(s);
literal i_ge_0 = mk_literal(a.mk_ge(i, zero)); literal i_ge_0 = mk_ge(i, zero);
literal i_ge_len_s = mk_literal(a.mk_ge(mk_sub(i, mk_len(s)), zero)); literal i_ge_len_s = mk_ge(mk_sub(i, mk_len(s)), zero);
expr_ref len_e = mk_len(e); expr_ref len_e = mk_len(e);
rational iv; rational iv;
@ -480,7 +480,7 @@ void seq_axioms::add_at_axiom(expr* e) {
add_axiom(i_ge_0, mk_eq(e, emp)); add_axiom(i_ge_0, mk_eq(e, emp));
add_axiom(~i_ge_len_s, mk_eq(e, emp)); add_axiom(~i_ge_len_s, mk_eq(e, emp));
add_axiom(~i_ge_0, i_ge_len_s, mk_eq(one, len_e)); add_axiom(~i_ge_0, i_ge_len_s, mk_eq(one, len_e));
add_axiom(mk_literal(a.mk_le(len_e, one))); add_axiom(mk_le(len_e, one));
} }
/** /**
@ -500,8 +500,8 @@ void seq_axioms::add_nth_axiom(expr* e) {
} }
else { else {
expr_ref zero(a.mk_int(0), m); expr_ref zero(a.mk_int(0), m);
literal i_ge_0 = mk_literal(a.mk_ge(i, zero)); literal i_ge_0 = mk_ge(i, zero);
literal i_ge_len_s = mk_literal(a.mk_ge(mk_sub(i, mk_len(s)), zero)); literal i_ge_len_s = mk_ge(mk_sub(i, mk_len(s)), zero);
// at(s,i) = [nth(s,i)] // at(s,i) = [nth(s,i)]
expr_ref rhs(s, m); expr_ref rhs(s, m);
expr_ref lhs(seq.str.mk_unit(e), m); expr_ref lhs(seq.str.mk_unit(e), m);
@ -520,12 +520,12 @@ void seq_axioms::add_itos_axiom(expr* e) {
// itos(n) = "" <=> n < 0 // itos(n) = "" <=> n < 0
expr_ref zero(a.mk_int(0), m); expr_ref zero(a.mk_int(0), m);
literal eq1 = mk_literal(seq.str.mk_is_empty(e)); literal eq1 = mk_literal(seq.str.mk_is_empty(e));
literal ge0 = mk_literal(a.mk_ge(n, zero)); literal ge0 = mk_ge(n, zero);
// n >= 0 => itos(n) != "" // n >= 0 => itos(n) != ""
// itos(n) = "" or n >= 0 // itos(n) = "" or n >= 0
add_axiom(~eq1, ~ge0); add_axiom(~eq1, ~ge0);
add_axiom(eq1, ge0); add_axiom(eq1, ge0);
add_axiom(mk_literal(a.mk_ge(mk_len(e), zero))); add_axiom(mk_ge(mk_len(e), 0));
// n >= 0 => stoi(itos(n)) = n // n >= 0 => stoi(itos(n)) = n
app_ref stoi(seq.str.mk_stoi(e), m); app_ref stoi(seq.str.mk_stoi(e), m);
@ -550,37 +550,74 @@ void seq_axioms::add_stoi_axiom(expr* e) {
TRACE("seq", tout << mk_pp(e, m) << "\n";); TRACE("seq", tout << mk_pp(e, m) << "\n";);
expr* s = nullptr; expr* s = nullptr;
VERIFY (seq.str.is_stoi(e, s)); VERIFY (seq.str.is_stoi(e, s));
add_axiom(mk_literal(a.mk_ge(e, a.mk_int(-1)))); add_axiom(mk_ge(e, -1));
add_axiom(~mk_literal(seq.str.mk_is_empty(s)), mk_eq(seq.str.mk_stoi(s), a.mk_int(-1))); add_axiom(~mk_literal(seq.str.mk_is_empty(s)), mk_eq(seq.str.mk_stoi(s), a.mk_int(-1)));
} }
/** /**
stoi(s) >= 0 =>
s != empty stoi(s) >= 0, len(s) <= k => stoi(s) = stoi(s, k)
s = unit(head) + tail len(s) > 0 => stoi(s, 0) = digit(nth_i(s, 0))
stoi(s) = 10*digit(head) + stoi(tail) or tail = empty 0 < i, len(s) <= i => stoi(s, i) = stoi(s, i - 1)
stoi(s) = digit(head) or tail != empty 0 < i, len(s) > i => stoi(s, i) = 10*stoi(s, i - 1) + digit(nth_i(s, i - 1))
is_digit(head)
(tail = empty or stoi(tail) >= 0) Define auxiliary function with the property:
for 0 <= i < len(s)
stoi(s, i) := stoi(extract(s, 0, i+1))
for 0 < i < len(s):
len(s) > i => stoi(s, i) := stoi(extract(s, 0, i))*10 + stoi(extract(s, i, 1))
len(s) <= i => stoi(s, i) := stoi(extract(s, 0, i-1), i-1)
*/ */
void seq_axioms::add_stoi_non_empty_axiom(expr* e) { void seq_axioms::add_stoi_axiom(expr* e, unsigned k) {
SASSERT(k > 0);
expr* s = nullptr; expr* s = nullptr;
VERIFY (seq.str.is_stoi(e, s)); VERIFY (seq.str.is_stoi(e, s));
expr_ref head(m), tail(m); auto stoi2 = [&](unsigned j) { return m_sk.mk("seq.stoi", s, a.mk_int(j), a.mk_int()); };
m_sk.decompose(s, head, tail); auto digit = [&](unsigned j) { return m_sk.mk_digit2int(mk_nth(s, a.mk_int(j))); };
expr_ref first_char = mk_nth(s, a.mk_int(0)); expr_ref len = mk_len(s);
literal ge0 = mk_literal(a.mk_ge(e, a.mk_int(0))); literal ge0 = mk_ge(e, 0);
literal tail_empty = mk_eq_empty(tail); literal lek = mk_le(len, k);
expr_ref first_digit = m_sk.mk_digit2int(first_char); add_axiom(~ge0, ~mk_eq(len, a.mk_int(0)));
expr_ref stoi_tail(seq.str.mk_stoi(tail), m); add_axiom(~ge0, ~lek, mk_eq(e, stoi2(k-1)));
add_axiom(~ge0, ~mk_literal(seq.str.mk_is_empty(s))); add_axiom(mk_eq(len, a.mk_int(0)), mk_eq(stoi2(0), digit(0)));
add_axiom(~ge0, mk_seq_eq(s, mk_concat(head, tail))); for (unsigned i = 1; i < k; ++i) {
add_axiom(~ge0, tail_empty, mk_eq(a.mk_add(a.mk_mul(a.mk_int(10), first_digit), stoi_tail), e)); add_axiom(mk_le(len, i), mk_eq(stoi2(i), a.mk_add(a.mk_mul(a.mk_int(10), stoi2(i-1)), digit(i))));
add_axiom(~ge0, ~tail_empty, mk_eq(first_digit, e)); add_axiom(~mk_le(len, i), mk_eq(stoi2(i), stoi2(i-1)));
add_axiom(~ge0, is_digit(first_char)); }
add_axiom(~ge0, tail_empty, mk_literal(a.mk_ge(stoi_tail, a.mk_int(0))));
} }
/**
Let s := itos(e)
Relate values of e with len(s) where len(s) is bounded by k.
|s| = 0 => e < 0
|s| <= 1 => e < 10
|s| <= 2 => e < 100
|s| <= 3 => e < 1000
|s| >= 1 => e >= 0
|s| >= 2 => e >= 10
|s| >= 3 => e >= 100
*/
void seq_axioms::add_itos_axiom(expr* s, unsigned k) {
expr* e = nullptr;
VERIFY(seq.str.is_itos(s, e));
expr_ref len = mk_len(s);
add_axiom(mk_ge(e, 10), mk_le(len, 1));
add_axiom(mk_le(e, -1), mk_ge(len, 1));
rational lo(1);
for (unsigned i = 1; i <= k; ++i) {
lo *= rational(10);
add_axiom(mk_ge(e, lo), mk_le(len, i));
add_axiom(mk_le(e, lo - 1), mk_ge(len, i + 1));
}
}
/** /**
e1 < e2 => prefix(e1, e2) or e1 = xcy e1 < e2 => prefix(e1, e2) or e1 < e2 => prefix(e1, e2) or e1 = xcy e1 < e2 => prefix(e1, e2) or
@ -644,7 +681,7 @@ void seq_axioms::add_suffix_axiom(expr* e) {
expr* e1 = nullptr, *e2 = nullptr; expr* e1 = nullptr, *e2 = nullptr;
VERIFY(seq.str.is_suffix(e, e1, e2)); VERIFY(seq.str.is_suffix(e, e1, e2));
literal lit = mk_literal(e); literal lit = mk_literal(e);
literal e1_gt_e2 = mk_literal(a.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), a.mk_int(1))); literal e1_gt_e2 = mk_ge(mk_sub(mk_len(e1), mk_len(e2)), 1);
sort* char_sort = nullptr; sort* char_sort = nullptr;
VERIFY(seq.is_seq(m.get_sort(e1), char_sort)); VERIFY(seq.is_seq(m.get_sort(e1), char_sort));
expr_ref x = m_sk.mk(symbol("seq.suffix.x"), e1, e2); expr_ref x = m_sk.mk(symbol("seq.suffix.x"), e1, e2);
@ -661,7 +698,7 @@ void seq_axioms::add_prefix_axiom(expr* e) {
expr* e1 = nullptr, *e2 = nullptr; expr* e1 = nullptr, *e2 = nullptr;
VERIFY(seq.str.is_prefix(e, e1, e2)); VERIFY(seq.str.is_prefix(e, e1, e2));
literal lit = mk_literal(e); literal lit = mk_literal(e);
literal e1_gt_e2 = mk_literal(a.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), a.mk_int(1))); literal e1_gt_e2 = mk_ge(mk_sub(mk_len(e1), mk_len(e2)), 1);
sort* char_sort = nullptr; sort* char_sort = nullptr;
VERIFY(seq.is_seq(m.get_sort(e1), char_sort)); VERIFY(seq.is_seq(m.get_sort(e1), char_sort));
expr_ref x = m_sk.mk(symbol("seq.prefix.x"), e1, e2); expr_ref x = m_sk.mk(symbol("seq.prefix.x"), e1, e2);
@ -686,50 +723,6 @@ literal seq_axioms::is_digit(expr* ch) {
add_axiom(~isd, hi); add_axiom(~isd, hi);
return isd; return isd;
} }
// n >= 0 & len(e) >= i + 1 => is_digit(e_i) for i = 0..k-1
// n >= 0 & len(e) = k => n = sum 10^i*digit(e_i)
// n < 0 & len(e) = k => \/_i ~is_digit(e_i) for i = 0..k-1
// 10^k <= n < 10^{k+1}-1 => len(e) => k
void seq_axioms::add_si_axiom(expr* e, expr* n, unsigned k) {
zstring s;
expr_ref ith_char(m), num(m), coeff(m);
expr_ref_vector nums(m), chars(m);
expr_ref len = mk_len(e);
literal len_eq_k = th.mk_preferred_eq(len, a.mk_int(k));
literal ge0 = mk_literal(a.mk_ge(n, a.mk_int(0)));
literal_vector digits;
digits.push_back(~len_eq_k);
digits.push_back(ge0);
ensure_digit_axiom();
for (unsigned i = 0; i < k; ++i) {
ith_char = mk_nth(e, a.mk_int(i));
literal isd = is_digit(ith_char);
literal len_ge_i1 = mk_literal(a.mk_ge(len, a.mk_int(i+1)));
add_axiom(~len_ge_i1, ~ge0, isd);
digits.push_back(~isd);
chars.push_back(seq.str.mk_unit(ith_char));
nums.push_back(m_sk.mk_digit2int(ith_char));
}
ctx().mk_th_axiom(th.get_id(), digits.size(), digits.c_ptr());
rational c(1);
for (unsigned i = k; i-- > 0; c *= rational(10)) {
coeff = a.mk_int(c);
nums[i] = a.mk_mul(coeff, nums.get(i));
}
num = a.mk_add(nums.size(), nums.c_ptr());
m_rewrite(num);
add_axiom(~len_eq_k, ~ge0, th.mk_preferred_eq(n, num));
add_axiom(~len_eq_k, ~ge0, th.mk_preferred_eq(e, seq.str.mk_concat(chars)));
SASSERT(k > 0);
rational lb = power(rational(10), k - 1);
rational ub = power(rational(10), k) - 1;
literal lbl = mk_literal(a.mk_ge(n, a.mk_int(lb)));
literal ge_k = mk_literal(a.mk_ge(len, a.mk_int(k)));
// n >= lb => len(s) >= k
add_axiom(~lbl, ge_k);
}
void seq_axioms::ensure_digit_axiom() { void seq_axioms::ensure_digit_axiom() {
if (!m_digits_initialized) { if (!m_digits_initialized) {
@ -745,7 +738,10 @@ void seq_axioms::ensure_digit_axiom() {
expr_ref seq_axioms::add_length_limit(expr* s, unsigned k) { expr_ref seq_axioms::add_length_limit(expr* s, unsigned k) {
expr_ref bound_tracker = m_sk.mk_length_limit(s, k); expr_ref bound_tracker = m_sk.mk_length_limit(s, k);
literal bound_predicate = mk_literal(a.mk_le(mk_len(s), a.mk_int(k))); expr* s0 = nullptr;
if (seq.str.is_stoi(s, s0))
s = s0;
literal bound_predicate = mk_le(mk_len(s), k);
add_axiom(~mk_literal(bound_tracker), bound_predicate); add_axiom(~mk_literal(bound_tracker), bound_predicate);
return bound_tracker; return bound_tracker;
} }

View file

@ -47,6 +47,12 @@ namespace smt {
expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(seq.str.mk_concat(e1, e2, e3), m); } expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(seq.str.mk_concat(e1, e2, e3), m); }
expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(seq.str.mk_concat(e1, e2), m); } expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(seq.str.mk_concat(e1, e2), m); }
expr_ref mk_nth(expr* e, expr* i) { return expr_ref(seq.str.mk_nth_i(e, i), m); } expr_ref mk_nth(expr* e, expr* i) { return expr_ref(seq.str.mk_nth_i(e, i), m); }
literal mk_ge(expr* e, int k) { return mk_ge(e, a.mk_int(k)); }
literal mk_le(expr* e, int k) { return mk_le(e, a.mk_int(k)); }
literal mk_ge(expr* e, rational const& k) { return mk_ge(e, a.mk_int(k)); }
literal mk_le(expr* e, rational const& k) { return mk_le(e, a.mk_int(k)); }
literal mk_ge(expr* x, expr* y) { return mk_literal(a.mk_ge(x, y)); }
literal mk_le(expr* x, expr* y) { return mk_literal(a.mk_le(x, y)); }
void add_axiom(literal l1, literal l2 = null_literal, literal l3 = null_literal, void add_axiom(literal l1, literal l2 = null_literal, literal l3 = null_literal,
literal l4 = null_literal, literal l5 = null_literal) { add_axiom5(l1, l2, l3, l4, l5); } literal l4 = null_literal, literal l5 = null_literal) { add_axiom5(l1, l2, l3, l4, l5); }
@ -78,12 +84,12 @@ namespace smt {
void add_nth_axiom(expr* n); void add_nth_axiom(expr* n);
void add_itos_axiom(expr* n); void add_itos_axiom(expr* n);
void add_stoi_axiom(expr* n); void add_stoi_axiom(expr* n);
void add_stoi_non_empty_axiom(expr* e); void add_stoi_axiom(expr* e, unsigned k);
void add_itos_axiom(expr* s, unsigned k);
void add_lt_axiom(expr* n); void add_lt_axiom(expr* n);
void add_le_axiom(expr* n); void add_le_axiom(expr* n);
void add_unit_axiom(expr* n); void add_unit_axiom(expr* n);
literal is_digit(expr* ch); literal is_digit(expr* ch);
void add_si_axiom(expr* e, expr* n, unsigned k);
expr_ref add_length_limit(expr* s, unsigned k); expr_ref add_length_limit(expr* s, unsigned k);
}; };

1620
src/smt/seq_eq_solver.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -136,13 +136,18 @@ bool seq_skolem::is_step(expr* e, expr*& s, expr*& idx, expr*& re, expr*& i, exp
} }
} }
bool seq_skolem::is_tail(expr* e, expr*& s, unsigned& idx) const { bool seq_skolem::is_tail_u(expr* e, expr*& s, unsigned& idx) const {
expr* i = nullptr; expr* i = nullptr;
rational r; rational r;
return is_tail_match(e, s, i) && a.is_numeral(i, r) && r.is_unsigned() && (idx = r.get_unsigned(), true); return is_tail(e, s, i) && a.is_numeral(i, r) && r.is_unsigned() && (idx = r.get_unsigned(), true);
} }
bool seq_skolem::is_tail_match(expr* e, expr*& s, expr*& idx) const { bool seq_skolem::is_tail(expr* e, expr*& s) const {
expr* i = nullptr;
return is_tail(e, s, i);
}
bool seq_skolem::is_tail(expr* e, expr*& s, expr*& idx) const {
return is_tail(e) && (s = to_app(e)->get_arg(0), idx = to_app(e)->get_arg(1), true); return is_tail(e) && (s = to_app(e)->get_arg(0), idx = to_app(e)->get_arg(1), true);
} }

View file

@ -95,8 +95,9 @@ namespace smt {
bool is_post(expr* e, expr*& s, expr*& start); bool is_post(expr* e, expr*& s, expr*& start);
bool is_pre(expr* e, expr*& s, expr*& i); bool is_pre(expr* e, expr*& s, expr*& i);
bool is_eq(expr* e, expr*& a, expr*& b) const; bool is_eq(expr* e, expr*& a, expr*& b) const;
bool is_tail_match(expr* e, expr*& s, expr*& idx) const; bool is_tail(expr* e, expr*& s, expr*& idx) const;
bool is_tail(expr* e, expr*& s, unsigned& idx) const; bool is_tail_u(expr* e, expr*& s, unsigned& idx) const;
bool is_tail(expr* e, expr*& s) const;
bool is_digit(expr* e) const { return is_skolem(symbol("seq.is_digit"), e); } bool is_digit(expr* e) const { return is_skolem(symbol("seq.is_digit"), e); }
bool is_max_unfolding(expr* e) const { return is_skolem(m_max_unfolding, e); } bool is_max_unfolding(expr* e) const { return is_skolem(m_max_unfolding, e); }
bool is_length_limit(expr* e) const { return is_skolem(m_length_limit, e); } bool is_length_limit(expr* e) const { return is_skolem(m_length_limit, e); }

View file

@ -122,7 +122,7 @@ namespace smt {
return true_literal; return true_literal;
} }
context & ctx = get_context(); context & ctx = get_context();
app * eq = ctx.mk_eq_atom(a, b); app_ref eq(ctx.mk_eq_atom(a, b), get_manager());
TRACE("mk_var_bug", tout << "mk_eq: " << eq->get_id() << " " << a->get_id() << " " << b->get_id() << "\n"; TRACE("mk_var_bug", tout << "mk_eq: " << eq->get_id() << " " << a->get_id() << " " << b->get_id() << "\n";
tout << mk_ll_pp(a, get_manager()) << "\n" << mk_ll_pp(b, get_manager());); tout << mk_ll_pp(a, get_manager()) << "\n" << mk_ll_pp(b, get_manager()););
ctx.internalize(eq, gate_ctx); ctx.internalize(eq, gate_ctx);

File diff suppressed because it is too large Load diff

View file

@ -389,13 +389,12 @@ namespace smt {
obj_hashtable<expr> m_axiom_set; obj_hashtable<expr> m_axiom_set;
unsigned m_axioms_head; // index of first axiom to add. unsigned m_axioms_head; // index of first axiom to add.
bool m_incomplete; // is the solver (clearly) incomplete for the fragment. bool m_incomplete; // is the solver (clearly) incomplete for the fragment.
expr_ref_vector m_int_string; expr_ref_vector m_int_string;
obj_map<expr, unsigned> m_si_axioms; obj_hashtable<expr> m_has_length; // is length applied
obj_hashtable<expr> m_has_length; // is length applied expr_ref_vector m_length; // length applications themselves
expr_ref_vector m_length; // length applications themselves obj_map<expr, unsigned> m_length_limit_map; // sequences that have length limit predicates
obj_map<expr, unsigned> m_length_limit_map; // sequences that have length limit predicates expr_ref_vector m_length_limit; // length limit predicates
expr_ref_vector m_length_limit; // length limit predicates scoped_ptr_vector<apply> m_replay; // set of actions to replay
scoped_ptr_vector<apply> m_replay; // set of actions to replay
model_generator* m_mg; model_generator* m_mg;
th_rewriter m_rewrite; // rewriter that converts strings to character concats th_rewriter m_rewrite; // rewriter that converts strings to character concats
th_rewriter m_str_rewrite; // rewriter that coonverts character concats to strings th_rewriter m_str_rewrite; // rewriter that coonverts character concats to strings
@ -518,6 +517,7 @@ namespace smt {
bool solve_nth_eq1(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep); bool solve_nth_eq1(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep);
bool solve_nth_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep); bool solve_nth_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep);
bool solve_itos(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep); bool solve_itos(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep);
bool solve_itos(expr* n, expr_ref_vector const& rs, dependency* dep);
bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr_ref& x, ptr_vector<expr>& xunits, ptr_vector<expr>& yunits, expr_ref& y); bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr_ref& x, ptr_vector<expr>& xunits, ptr_vector<expr>& yunits, expr_ref& y);
bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2); bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2);
bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1);
@ -541,7 +541,7 @@ namespace smt {
bool solve_ne(unsigned i); bool solve_ne(unsigned i);
bool solve_nc(unsigned i); bool solve_nc(unsigned i);
bool branch_nqs(); bool branch_nqs();
void branch_nq(ne const& n); lbool branch_nq(ne const& n);
struct cell { struct cell {
cell* m_parent; cell* m_parent;
@ -622,10 +622,6 @@ namespace smt {
expr_ref add_elim_string_axiom(expr* n); expr_ref add_elim_string_axiom(expr* n);
void add_in_re_axiom(expr* n); void add_in_re_axiom(expr* n);
bool add_itos_val_axiom(expr* n);
bool add_stoi_val_axiom(expr* n);
bool add_si_axiom(expr* e, expr* n);
void add_itos_length_axiom(expr* n);
literal mk_literal(expr* n); literal mk_literal(expr* n);
literal mk_simplified_literal(expr* n); literal mk_simplified_literal(expr* n);
literal mk_eq_empty(expr* n, bool phase = true); literal mk_eq_empty(expr* n, bool phase = true);
@ -650,6 +646,9 @@ namespace smt {
void mk_decompose(expr* e, expr_ref& head, expr_ref& tail); void mk_decompose(expr* e, expr_ref& head, expr_ref& tail);
// unfold definitions based on length limits
void propagate_length_limit(expr* n);
void set_incomplete(app* term); void set_incomplete(app* term);
// automata utilities // automata utilities

View file

@ -19,9 +19,10 @@ Revision History:
#ifndef THEORY_SEQ_EMPTY_H_ #ifndef THEORY_SEQ_EMPTY_H_
#define THEORY_SEQ_EMPTY_H_ #define THEORY_SEQ_EMPTY_H_
#include "smt/smt_theory.h"
#include "ast/seq_decl_plugin.h" #include "ast/seq_decl_plugin.h"
#include "model/seq_factory.h" #include "model/seq_factory.h"
#include "smt/smt_theory.h"
#include "smt/smt_model_generator.h"
namespace smt { namespace smt {