mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
seq + API
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
68a532d066
commit
c1ebf6b4fc
9 changed files with 484 additions and 77 deletions
|
@ -23,6 +23,7 @@ Notes:
|
|||
#include"ast_util.h"
|
||||
#include"uint_set.h"
|
||||
#include"automaton.h"
|
||||
#include"well_sorted.h"
|
||||
|
||||
|
||||
struct display_expr1 {
|
||||
|
@ -843,37 +844,33 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
|||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
expr* a, *b;
|
||||
zstring s;
|
||||
bool change = false;
|
||||
m_lhs.reset();
|
||||
m_rhs.reset();
|
||||
m_util.str.get_concat(l, m_lhs);
|
||||
m_util.str.get_concat(r, m_rhs);
|
||||
|
||||
// solve from back
|
||||
while (true) {
|
||||
while (!m_rhs.empty() && m_util.str.is_empty(m_rhs.back())) {
|
||||
m_rhs.pop_back();
|
||||
while (!rs.empty() && m_util.str.is_empty(rs.back())) {
|
||||
rs.pop_back();
|
||||
change = true;
|
||||
}
|
||||
while (!m_lhs.empty() && m_util.str.is_empty(m_lhs.back())) {
|
||||
m_lhs.pop_back();
|
||||
while (!ls.empty() && m_util.str.is_empty(ls.back())) {
|
||||
ls.pop_back();
|
||||
change = true;
|
||||
}
|
||||
if (m_lhs.empty() || m_rhs.empty()) {
|
||||
if (ls.empty() || rs.empty()) {
|
||||
break;
|
||||
}
|
||||
expr* l = m_lhs.back();
|
||||
expr* r = m_rhs.back();
|
||||
expr* l = ls.back();
|
||||
expr* r = rs.back();
|
||||
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||
std::swap(l, r);
|
||||
m_lhs.swap(m_rhs);
|
||||
ls.swap(rs);
|
||||
}
|
||||
if (l == r) {
|
||||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
ls.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else if(m_util.str.is_unit(l, a) &&
|
||||
m_util.str.is_unit(r, b)) {
|
||||
|
@ -882,8 +879,8 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
}
|
||||
lhs.push_back(a);
|
||||
rhs.push_back(b);
|
||||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
ls.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else if (m_util.str.is_unit(l, a) && m_util.str.is_string(r, s)) {
|
||||
SASSERT(s.length() > 0);
|
||||
|
@ -892,13 +889,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
SASSERT(m().get_sort(ch) == m().get_sort(a));
|
||||
lhs.push_back(ch);
|
||||
rhs.push_back(a);
|
||||
m_lhs.pop_back();
|
||||
ls.pop_back();
|
||||
if (s.length() == 1) {
|
||||
m_rhs.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else {
|
||||
expr_ref s2(m_util.str.mk_string(s.extract(0, s.length()-2)), m());
|
||||
m_rhs[m_rhs.size()-1] = s2;
|
||||
rs[rs.size()-1] = s2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -910,22 +907,22 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
// solve from front
|
||||
unsigned head1 = 0, head2 = 0;
|
||||
while (true) {
|
||||
while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1].get())) {
|
||||
while (head1 < ls.size() && m_util.str.is_empty(ls[head1].get())) {
|
||||
++head1;
|
||||
}
|
||||
while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2].get())) {
|
||||
while (head2 < rs.size() && m_util.str.is_empty(rs[head2].get())) {
|
||||
++head2;
|
||||
}
|
||||
if (head1 == m_lhs.size() || head2 == m_rhs.size()) {
|
||||
if (head1 == ls.size() || head2 == rs.size()) {
|
||||
break;
|
||||
}
|
||||
SASSERT(head1 < m_lhs.size() && head2 < m_rhs.size());
|
||||
SASSERT(head1 < ls.size() && head2 < rs.size());
|
||||
|
||||
expr* l = m_lhs[head1].get();
|
||||
expr* r = m_rhs[head2].get();
|
||||
expr* l = ls[head1].get();
|
||||
expr* r = rs[head2].get();
|
||||
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||
std::swap(l, r);
|
||||
m_lhs.swap(m_rhs);
|
||||
ls.swap(rs);
|
||||
}
|
||||
if (l == r) {
|
||||
++head1;
|
||||
|
@ -947,13 +944,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
SASSERT(m().get_sort(ch) == m().get_sort(a));
|
||||
lhs.push_back(ch);
|
||||
rhs.push_back(a);
|
||||
m_lhs.pop_back();
|
||||
ls.pop_back();
|
||||
if (s.length() == 1) {
|
||||
m_rhs.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else {
|
||||
expr_ref s2(m_util.str.mk_string(s.extract(1, s.length()-1)), m());
|
||||
m_rhs[m_rhs.size()-1] = s2;
|
||||
rs[rs.size()-1] = s2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -963,10 +960,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
}
|
||||
// reduce strings
|
||||
zstring s1, s2;
|
||||
while (head1 < m_lhs.size() &&
|
||||
head2 < m_rhs.size() &&
|
||||
m_util.str.is_string(m_lhs[head1].get(), s1) &&
|
||||
m_util.str.is_string(m_rhs[head2].get(), s2)) {
|
||||
while (head1 < ls.size() &&
|
||||
head2 < rs.size() &&
|
||||
m_util.str.is_string(ls[head1].get(), s1) &&
|
||||
m_util.str.is_string(rs[head2].get(), s2)) {
|
||||
unsigned l = std::min(s1.length(), s2.length());
|
||||
for (unsigned i = 0; i < l; ++i) {
|
||||
if (s1[i] != s2[i]) {
|
||||
|
@ -977,64 +974,105 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
++head1;
|
||||
}
|
||||
else {
|
||||
m_lhs[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
|
||||
ls[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
|
||||
}
|
||||
if (l == s2.length()) {
|
||||
++head2;
|
||||
}
|
||||
else {
|
||||
m_rhs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
|
||||
rs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
|
||||
}
|
||||
change = true;
|
||||
}
|
||||
while (head1 < m_lhs.size() &&
|
||||
head2 < m_rhs.size() &&
|
||||
m_util.str.is_string(m_lhs.back(), s1) &&
|
||||
m_util.str.is_string(m_rhs.back(), s2)) {
|
||||
while (head1 < ls.size() &&
|
||||
head2 < rs.size() &&
|
||||
m_util.str.is_string(ls.back(), s1) &&
|
||||
m_util.str.is_string(rs.back(), s2)) {
|
||||
unsigned l = std::min(s1.length(), s2.length());
|
||||
for (unsigned i = 0; i < l; ++i) {
|
||||
if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
ls.pop_back();
|
||||
rs.pop_back();
|
||||
if (l < s1.length()) {
|
||||
m_lhs.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
|
||||
ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
|
||||
}
|
||||
if (l < s2.length()) {
|
||||
m_rhs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
|
||||
rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
|
||||
}
|
||||
change = true;
|
||||
}
|
||||
|
||||
bool is_sat;
|
||||
unsigned szl = m_lhs.size() - head1, szr = m_rhs.size() - head2;
|
||||
expr* const* ls = m_lhs.c_ptr() + head1, * const*rs = m_rhs.c_ptr() + head2;
|
||||
if (length_constrained(szl, ls, szr, rs, lhs, rhs, is_sat)) {
|
||||
unsigned szl = ls.size() - head1, szr = rs.size() - head2;
|
||||
expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2;
|
||||
if (length_constrained(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
|
||||
ls.reset(); rs.reset();
|
||||
return is_sat;
|
||||
}
|
||||
if (is_subsequence(szl, ls, szr, rs, lhs, rhs, is_sat)) {
|
||||
if (is_subsequence(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
|
||||
ls.reset(); rs.reset();
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
if (szl == 0 && szr == 0) {
|
||||
return true;
|
||||
}
|
||||
if (szl == 0 && szr == 0) {
|
||||
ls.reset(); rs.reset();
|
||||
return true;
|
||||
}
|
||||
else if (!change) {
|
||||
lhs.push_back(l);
|
||||
rhs.push_back(r);
|
||||
// skip
|
||||
}
|
||||
else {
|
||||
// could solve if either side is fixed size.
|
||||
SASSERT(szl > 0 && szr > 0);
|
||||
|
||||
lhs.push_back(m_util.str.mk_concat(szl, ls));
|
||||
rhs.push_back(m_util.str.mk_concat(szr, rs));
|
||||
if (head1 > 0) {
|
||||
for (unsigned i = 0; i < szl; ++i) {
|
||||
ls[i] = ls[i + head1];
|
||||
}
|
||||
}
|
||||
ls.shrink(szl);
|
||||
if (head2 > 0) {
|
||||
for (unsigned i = 0; i < szr; ++i) {
|
||||
rs[i] = rs[i + head2];
|
||||
}
|
||||
}
|
||||
rs.shrink(szr);
|
||||
lhs.push_back(m_util.str.mk_concat(ls.size(), ls.c_ptr()));
|
||||
rhs.push_back(m_util.str.mk_concat(rs.size(), rs.c_ptr()));
|
||||
ls.reset();
|
||||
rs.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
m_lhs.reset();
|
||||
m_rhs.reset();
|
||||
m_util.str.get_concat(l, m_lhs);
|
||||
m_util.str.get_concat(r, m_rhs);
|
||||
if (reduce_eq(m_lhs, m_rhs, lhs, rhs)) {
|
||||
SASSERT(lhs.size() == rhs.size());
|
||||
if (!m_lhs.empty()) {
|
||||
SASSERT(!m_rhs.empty());
|
||||
lhs.push_back(m_util.str.mk_concat(m_lhs.size(), m_lhs.c_ptr()));
|
||||
rhs.push_back(m_util.str.mk_concat(m_rhs.size(), m_rhs.c_ptr()));
|
||||
}
|
||||
for (unsigned i = 0; i < lhs.size(); ++i) {
|
||||
SASSERT(is_well_sorted(m(), lhs[i].get()));
|
||||
SASSERT(is_well_sorted(m(), rhs[i].get()));
|
||||
SASSERT(m().get_sort(lhs[i].get()) == m().get_sort(rhs[i].get()));
|
||||
TRACE("seq", tout << mk_pp(lhs[i].get(), m()) << " = " << mk_pp(rhs[i].get(), m()) << "\n";);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TRACE("seq", tout << mk_pp(l, m()) << " != " << mk_pp(r, m()) << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
|
||||
SASSERT(n > 0);
|
||||
ptr_vector<expr> bs;
|
||||
|
|
|
@ -92,6 +92,8 @@ public:
|
|||
|
||||
bool reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
|
||||
bool reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue