3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00

more rewrite rules

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2021-02-18 22:14:53 -08:00
parent b2eb248bad
commit 27584d68db
3 changed files with 96 additions and 25 deletions

View file

@ -909,6 +909,18 @@ bool seq_rewriter::is_suffix(expr* s, expr* offset, expr* len) {
lens.contains(s));
}
bool seq_rewriter::is_prefix(expr* s, expr* offset, expr* len) {
expr_ref_vector lens(m());
rational a, b;
return
get_lengths(len, lens, a) &&
a < 0 &&
m_autil.is_numeral(offset, b) &&
b == 0 &&
lens.size() == 1 &&
lens.contains(s);
}
bool seq_rewriter::sign_is_determined(expr* e, sign& s) {
s = sign_zero;
if (m_autil.is_add(e)) {
@ -965,6 +977,27 @@ expr_ref seq_rewriter::mk_len(rational const& p, expr_ref_vector const& xs) {
return r;
}
bool seq_rewriter::extract_pop_suffix(expr_ref_vector const& as, expr* b, expr* c, expr_ref& result) {
unsigned len_a1 = 0, len_a2 = 0;
min_length(as, len_a1);
rational pos, len;
if (!as.empty() && m_autil.is_numeral(b, pos) &&
m_autil.is_numeral(c, len) && len_a1 >= pos + len && pos >= 0 && len >= 0) {
unsigned i = 0;
len_a1 = 0;
for ( ; i < as.size() && len_a1 < pos + len; ++i) {
min_length(as.get(i), len_a2);
len_a1 += len_a2;
}
if (i < as.size()) {
expr* a = str().mk_concat(i, as.c_ptr(), as[0]->get_sort());
result = str().mk_substr(a, b, c);
return true;
}
}
return false;
}
bool seq_rewriter::extract_push_offset(expr_ref_vector const& as, expr* b, expr* c, expr_ref& result) {
expr_ref_vector lens(m());
@ -1049,7 +1082,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
return BR_DONE;
}
// case 1: pos<0 or len<=0
// case 1: pos < 0 or len <= 0
// rewrite to ""
if ( (constantPos && pos.is_neg()) || (constantLen && !len.is_pos()) ) {
result = str().mk_empty(a_sort);
@ -1057,42 +1090,41 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
}
// case 1.1: pos >= length(base)
// rewrite to ""
if (constantPos && constantBase && pos >= rational(s.length())) {
if (constantPos && constantBase && pos >= s.length()) {
result = str().mk_empty(a_sort);
return BR_DONE;
}
rational len_a;
if (constantPos && max_length(a, len_a) && rational(len_a) <= pos) {
if (constantPos && max_length(a, len_a) && len_a <= pos) {
result = str().mk_empty(a_sort);
return BR_DONE;
}
constantPos &= pos.is_unsigned();
constantLen &= len.is_unsigned();
if (constantPos && constantLen && constantBase) {
unsigned _pos = pos.get_unsigned();
unsigned _len = len.get_unsigned();
if (_pos + _len >= s.length()) {
// case 2: pos+len goes past the end of the string
unsigned _len = s.length() - _pos + 1;
if (pos + len >= s.length())
result = str().mk_string(s.extract(_pos, s.length()));
else
result = str().mk_string(s.extract(_pos, _len));
} else {
// case 3: pos+len still within string
result = str().mk_string(s.extract(_pos, _len));
}
return BR_DONE;
}
expr_ref_vector as(m()), bs(m());
expr_ref_vector as(m());
str().get_concat_units(a, as);
if (as.empty()) {
result = str().mk_empty(a->get_sort());
return BR_DONE;
}
if (extract_pop_suffix(as, b, c, result))
return BR_REWRITE1;
// extract(a + b + c, len(a + b), s) -> extract(c, 0, s)
// extract(a + b + c, len(a) + len(b), s) -> extract(c, 0, s)
if (extract_push_offset(as, b, c, result))
@ -1109,6 +1141,12 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
return BR_REWRITE3;
}
if (str().is_extract(a, a1, b1, c1) &&
is_prefix(a1, b1, c1) && is_prefix(a, b, c)) {
result = str().mk_substr(a1, b, m_autil.mk_sub(c1, m_autil.mk_sub(str().mk_length(a), c)));
return BR_REWRITE3;
}
if (!constantPos)
return BR_FAILED;
@ -4522,23 +4560,42 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa
maximal length (the sequence is bounded).
*/
bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) {
bool seq_rewriter::min_length(expr* e, unsigned& len) {
zstring s;
len = 0;
if (str().is_unit(e)) {
len = 1;
return true;
}
else if (str().is_empty(e)) {
len = 0;
return true;
}
else if (str().is_string(e, s)) {
len = s.length();
return true;
}
else if (str().is_concat(e)) {
unsigned min_l = 0;
bool bounded = true;
for (expr* arg : *to_app(e)) {
if (!min_length(arg, min_l))
bounded = false;
len += min_l;
}
return bounded;
}
return false;
}
bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) {
unsigned min_l = 0;
bool bounded = true;
len = 0;
for (expr* e : es) {
if (str().is_unit(e)) {
++len;
}
else if (str().is_empty(e)) {
continue;
}
else if (str().is_string(e, s)) {
len += s.length();
}
else {
for (expr* arg : es) {
if (!min_length(arg, min_l))
bounded = false;
}
len += min_l;
}
return bounded;
}

View file

@ -210,6 +210,7 @@ class seq_rewriter {
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
br_status mk_seq_length(expr* a, expr_ref& result);
expr_ref mk_len(rational const& offset, expr_ref_vector const& xs);
bool extract_pop_suffix(expr_ref_vector const& as, expr* b, expr* c, expr_ref& result);
bool extract_push_offset(expr_ref_vector const& as, expr* b, expr* c, expr_ref& result);
bool extract_push_length(expr_ref_vector& as, expr* b, expr* c, expr_ref& result);
br_status mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result);
@ -276,6 +277,7 @@ class seq_rewriter {
expr_ref minus_one() { return expr_ref(m_autil.mk_int(-1), m()); }
bool is_suffix(expr* s, expr* offset, expr* len);
bool is_prefix(expr* s, expr* offset, expr* len);
bool sign_is_determined(expr* len, sign& s);
bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs);
@ -285,6 +287,7 @@ class seq_rewriter {
bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs);
bool reduce_eq_empty(expr* l, expr* r, expr_ref& result);
bool min_length(expr_ref_vector const& es, unsigned& len);
bool min_length(expr* e, unsigned& len);
bool max_length(expr* e, rational& len);
expr* concat_non_empty(expr_ref_vector& es);

View file

@ -69,6 +69,17 @@ literal seq_axioms::mk_literal(expr* _e) {
}
void seq_axioms::add_clause(expr_ref_vector const& clause) {
expr* a = nullptr, *b = nullptr;
if (clause.size() == 1 && m.is_eq(clause[0], a, b)) {
enode* n1 = th.ensure_enode(a);
enode* n2 = th.ensure_enode(b);
justification* js =
ctx().mk_justification(
ext_theory_eq_propagation_justification(
th.get_id(), ctx().get_region(), 0, nullptr, 0, nullptr, n1, n2));
ctx().assign_eq(n1, n2, eq_justification(js));
return;
}
literal lits[5] = { null_literal, null_literal, null_literal, null_literal, null_literal };
unsigned idx = 0;
for (expr* e : clause) {