mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
parent
8c5993d9a6
commit
9c3f0190f4
|
@ -1013,9 +1013,9 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned lenA = 0, lenB = 0;
|
unsigned lenA = 0, lenB = 0;
|
||||||
bool lA = min_length(as.size(), as.c_ptr(), lenA);
|
bool lA = min_length(as, lenA);
|
||||||
if (lA) {
|
if (lA) {
|
||||||
min_length(bs.size(), bs.c_ptr(), lenB);
|
min_length(bs, lenB);
|
||||||
if (lenB > lenA) {
|
if (lenB > lenA) {
|
||||||
result = m().mk_false();
|
result = m().mk_false();
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
|
@ -1387,7 +1387,7 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu
|
||||||
if (m_lhs.empty()) {
|
if (m_lhs.empty()) {
|
||||||
unsigned len = 0;
|
unsigned len = 0;
|
||||||
m_util.str.get_concat(b, m_lhs);
|
m_util.str.get_concat(b, m_lhs);
|
||||||
min_length(m_lhs.size(), m_lhs.c_ptr(), len);
|
min_length(m_lhs, len);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
result = a;
|
result = a;
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
|
@ -2191,13 +2191,12 @@ br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
||||||
TRACE("seq", tout << mk_bounded_pp(l, m(), 2) << " = " << mk_bounded_pp(r, m(), 2) << "\n";);
|
|
||||||
expr_ref_vector res(m());
|
expr_ref_vector res(m());
|
||||||
expr_ref_pair_vector new_eqs(m());
|
expr_ref_pair_vector new_eqs(m());
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (!reduce_eq(l, r, new_eqs, changed)) {
|
if (!reduce_eq(l, r, new_eqs, changed)) {
|
||||||
result = m().mk_false();
|
result = m().mk_false();
|
||||||
TRACE("seq", tout << result << "\n";);
|
TRACE("seq_verbose", tout << result << "\n";);
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
}
|
}
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
|
@ -2207,24 +2206,33 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
||||||
res.push_back(m().mk_eq(p.first, p.second));
|
res.push_back(m().mk_eq(p.first, p.second));
|
||||||
}
|
}
|
||||||
result = mk_and(res);
|
result = mk_and(res);
|
||||||
TRACE("seq", tout << result << "\n";);
|
TRACE("seq_verbose", tout << result << "\n";);
|
||||||
return BR_REWRITE3;
|
return BR_REWRITE3;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) {
|
void seq_rewriter::remove_empty(expr_ref_vector& es) {
|
||||||
|
unsigned j = 0;
|
||||||
|
for (expr* e : es) {
|
||||||
|
if (!m_util.str.is_empty(e))
|
||||||
|
es[j++] = e;
|
||||||
|
}
|
||||||
|
es.shrink(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void seq_rewriter::remove_leading(unsigned n, expr_ref_vector& es) {
|
||||||
|
SASSERT(n <= es.size());
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
for (unsigned i = n; i < es.size(); ++i) {
|
||||||
|
es[i-n] = es.get(i);
|
||||||
|
}
|
||||||
|
es.shrink(es.size() - n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool seq_rewriter::reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) {
|
||||||
expr* a, *b;
|
expr* a, *b;
|
||||||
zstring s;
|
zstring s, s1, s2;
|
||||||
bool lchange = false;
|
|
||||||
SASSERT(new_eqs.empty());
|
|
||||||
TRACE("seq_verbose", tout << ls << "\n"; tout << rs << "\n";);
|
|
||||||
// solve from back
|
|
||||||
while (true) {
|
while (true) {
|
||||||
while (!rs.empty() && m_util.str.is_empty(rs.back())) {
|
|
||||||
rs.pop_back();
|
|
||||||
}
|
|
||||||
while (!ls.empty() && m_util.str.is_empty(ls.back())) {
|
|
||||||
ls.pop_back();
|
|
||||||
}
|
|
||||||
if (ls.empty() || rs.empty()) {
|
if (ls.empty() || rs.empty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2262,29 +2270,42 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
|
||||||
rs[rs.size()-1] = s2;
|
rs[rs.size()-1] = s2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (m_util.str.is_string(l, s1) && m_util.str.is_string(r, s2)) {
|
||||||
|
unsigned min_l = std::min(s1.length(), s2.length());
|
||||||
|
for (unsigned i = 0; i < min_l; ++i) {
|
||||||
|
if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ls.pop_back();
|
||||||
|
rs.pop_back();
|
||||||
|
if (min_l < s1.length()) {
|
||||||
|
ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-min_l)));
|
||||||
|
}
|
||||||
|
if (min_l < s2.length()) {
|
||||||
|
rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-min_l)));
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
change = true;
|
change = true;
|
||||||
lchange = true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// solve from front
|
bool seq_rewriter::reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) {
|
||||||
|
expr* a, *b;
|
||||||
|
zstring s, s1, s2;
|
||||||
unsigned head1 = 0, head2 = 0;
|
unsigned head1 = 0, head2 = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
while (head1 < ls.size() && m_util.str.is_empty(ls[head1].get())) {
|
|
||||||
++head1;
|
|
||||||
}
|
|
||||||
while (head2 < rs.size() && m_util.str.is_empty(rs[head2].get())) {
|
|
||||||
++head2;
|
|
||||||
}
|
|
||||||
if (head1 == ls.size() || head2 == rs.size()) {
|
if (head1 == ls.size() || head2 == rs.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SASSERT(head1 < ls.size() && head2 < rs.size());
|
SASSERT(head1 < ls.size() && head2 < rs.size());
|
||||||
|
|
||||||
expr* l = ls[head1].get();
|
expr* l = ls.get(head1);
|
||||||
expr* r = rs[head2].get();
|
expr* r = rs.get(head2);
|
||||||
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||||
std::swap(l, r);
|
std::swap(l, r);
|
||||||
ls.swap(rs);
|
ls.swap(rs);
|
||||||
|
@ -2317,144 +2338,57 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
|
||||||
rs[head2] = s2;
|
rs[head2] = s2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (m_util.str.is_string(l, s1) &&
|
||||||
|
m_util.str.is_string(r, s2)) {
|
||||||
|
TRACE("seq", tout << s1 << " - " << s2 << " " << s1.length() << " " << s2.length() << "\n";);
|
||||||
|
unsigned min_l = std::min(s1.length(), s2.length());
|
||||||
|
for (unsigned i = 0; i < min_l; ++i) {
|
||||||
|
if (s1[i] != s2[i]) {
|
||||||
|
TRACE("seq", tout << "different at position " << i << " " << s1[i] << " " << s2[i] << "\n";);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min_l == s1.length()) {
|
||||||
|
++head1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ls[head1] = m_util.str.mk_string(s1.extract(min_l, s1.length()-min_l));
|
||||||
|
}
|
||||||
|
if (min_l == s2.length()) {
|
||||||
|
++head2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rs[head2] = m_util.str.mk_string(s2.extract(min_l, s2.length()-min_l));
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TRACE("seq_verbose", tout << ls << " == " << rs << "\n";);
|
|
||||||
|
|
||||||
change = true;
|
change = true;
|
||||||
lchange = true;
|
|
||||||
}
|
}
|
||||||
// reduce strings
|
remove_leading(head1, ls);
|
||||||
zstring s1, s2;
|
remove_leading(head2, rs);
|
||||||
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)) {
|
|
||||||
TRACE("seq", tout << s1 << " - " << s2 << " " << s1.length() << " " << s2.length() << "\n";);
|
|
||||||
unsigned l = std::min(s1.length(), s2.length());
|
|
||||||
for (unsigned i = 0; i < l; ++i) {
|
|
||||||
if (s1[i] != s2[i]) {
|
|
||||||
TRACE("seq", tout << "different at position " << i << " " << s1[i] << " " << s2[i] << "\n";);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (l == s1.length()) {
|
|
||||||
++head1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ls[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
|
|
||||||
}
|
|
||||||
if (l == s2.length()) {
|
|
||||||
++head2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
|
|
||||||
}
|
|
||||||
TRACE("seq", tout << "change string\n";);
|
|
||||||
change = true;
|
|
||||||
lchange = true;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ls.pop_back();
|
|
||||||
rs.pop_back();
|
|
||||||
if (l < s1.length()) {
|
|
||||||
ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
|
|
||||||
}
|
|
||||||
if (l < s2.length()) {
|
|
||||||
rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
|
|
||||||
}
|
|
||||||
TRACE("seq", tout << "change string back\n";);
|
|
||||||
change = true;
|
|
||||||
lchange = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_sat = true;
|
|
||||||
unsigned szl = ls.size() - head1, szr = rs.size() - head2;
|
|
||||||
expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2;
|
|
||||||
|
|
||||||
if (solve_itos(szl, _ls, szr, _rs, new_eqs, is_sat)) {
|
|
||||||
ls.reset(); rs.reset();
|
|
||||||
change = true;
|
|
||||||
return is_sat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length_constrained(szl, _ls, szr, _rs, new_eqs, is_sat)) {
|
|
||||||
ls.reset(); rs.reset();
|
|
||||||
change = true;
|
|
||||||
return is_sat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (szr == 0 && szl == 0) {
|
|
||||||
ls.reset();
|
|
||||||
rs.reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (szr == 0 && szl > 0) {
|
|
||||||
std::swap(szr, szl);
|
|
||||||
std::swap(_ls, _rs);
|
|
||||||
}
|
|
||||||
if (szl == 0 && szr > 0) {
|
|
||||||
if (set_empty(szr, _rs, true, new_eqs)) {
|
|
||||||
lchange |= szr > 1;
|
|
||||||
change |= szr > 1;
|
|
||||||
if (szr == 1 && !lchange) {
|
|
||||||
new_eqs.reset();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ls.reset();
|
|
||||||
rs.reset();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SASSERT(szl > 0 && szr > 0);
|
|
||||||
|
|
||||||
if (is_subsequence(szl, _ls, szr, _rs, new_eqs, is_sat)) {
|
|
||||||
ls.reset(); rs.reset();
|
|
||||||
change = true;
|
|
||||||
return is_sat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lchange) {
|
|
||||||
if (head1 > 0) {
|
|
||||||
for (unsigned i = 0; i < szl; ++i) {
|
|
||||||
ls[i] = ls[i + head1].get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ls.shrink(szl);
|
|
||||||
if (head2 > 0) {
|
|
||||||
for (unsigned i = 0; i < szr; ++i) {
|
|
||||||
rs[i] = rs[i + head2].get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rs.shrink(szr);
|
|
||||||
}
|
|
||||||
SASSERT(rs.empty() == ls.empty());
|
|
||||||
change |= lchange;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void seq_rewriter::add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_pair_vector& eqs) {
|
/**
|
||||||
if (!ls.empty() || !rs.empty()) {
|
\brief simplify equality ls = rs
|
||||||
sort * s = m().get_sort(ls.empty() ? rs[0] : ls[0]);
|
- New equalities are inserted into eqs.
|
||||||
eqs.push_back(m_util.str.mk_concat(ls, s), m_util.str.mk_concat(rs, s));
|
- Last remaining equalities that cannot be simplified further are kept in ls, rs
|
||||||
}
|
- returns false if equality is unsatisfiable
|
||||||
|
*/
|
||||||
|
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change) {
|
||||||
|
TRACE("seq_verbose", tout << ls << "\n"; tout << rs << "\n";);
|
||||||
|
remove_empty(ls);
|
||||||
|
remove_empty(rs);
|
||||||
|
return
|
||||||
|
reduce_back(ls, rs, eqs, change) &&
|
||||||
|
reduce_front(ls, rs, eqs, change) &&
|
||||||
|
reduce_itos(ls, rs, eqs, change) &&
|
||||||
|
reduce_by_length(ls, rs, eqs, change) &&
|
||||||
|
reduce_subsequence(ls, rs, eqs, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bool& changed) {
|
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bool& changed) {
|
||||||
m_lhs.reset();
|
m_lhs.reset();
|
||||||
m_rhs.reset();
|
m_rhs.reset();
|
||||||
|
@ -2463,7 +2397,7 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bo
|
||||||
bool change = false;
|
bool change = false;
|
||||||
if (reduce_eq(m_lhs, m_rhs, new_eqs, change)) {
|
if (reduce_eq(m_lhs, m_rhs, new_eqs, change)) {
|
||||||
if (!change) {
|
if (!change) {
|
||||||
new_eqs.push_back(std::make_pair(l, r));
|
new_eqs.push_back(l, r);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
add_seqs(m_lhs, m_rhs, new_eqs);
|
add_seqs(m_lhs, m_rhs, new_eqs);
|
||||||
|
@ -2477,6 +2411,14 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void seq_rewriter::add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_pair_vector& eqs) {
|
||||||
|
if (!ls.empty() || !rs.empty()) {
|
||||||
|
sort * s = m().get_sort(ls.empty() ? rs[0] : ls[0]);
|
||||||
|
eqs.push_back(m_util.str.mk_concat(ls, s), m_util.str.mk_concat(rs, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) {
|
bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) {
|
||||||
m_lhs.reset();
|
m_lhs.reset();
|
||||||
m_util.str.get_concat(a, m_lhs);
|
m_util.str.get_concat(a, m_lhs);
|
||||||
|
@ -2524,18 +2466,22 @@ bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
|
expr* seq_rewriter::concat_non_empty(expr_ref_vector& es) {
|
||||||
SASSERT(n > 0);
|
sort* s = m().get_sort(es.get(0));
|
||||||
ptr_vector<expr> bs;
|
unsigned j = 0;
|
||||||
for (unsigned i = 0; i < n; ++i) {
|
for (expr* e : es) {
|
||||||
if (m_util.str.is_unit(as[i]) ||
|
if (m_util.str.is_unit(e) || m_util.str.is_string(e))
|
||||||
m_util.str.is_string(as[i])) {
|
es[j++] = e;
|
||||||
bs.push_back(as[i]);
|
}
|
||||||
}
|
es.shrink(j);
|
||||||
}
|
return m_util.str.mk_concat(es, s);
|
||||||
return m_util.str.mk_concat(bs.size(), bs.c_ptr(), m().get_sort(as[0]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief assign the non-unit and non-string elements to the empty sequence.
|
||||||
|
If all is true, then return false if there is a unit or non-empty substring.
|
||||||
|
*/
|
||||||
|
|
||||||
bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs) {
|
bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs) {
|
||||||
zstring s;
|
zstring s;
|
||||||
expr* emp = nullptr;
|
expr* emp = nullptr;
|
||||||
|
@ -2547,8 +2493,9 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_string(es[i], s)) {
|
else if (m_util.str.is_string(es[i], s)) {
|
||||||
|
if (s.length() == 0)
|
||||||
|
continue;
|
||||||
if (all) {
|
if (all) {
|
||||||
SASSERT(s.length() > 0);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2560,18 +2507,24 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
|
/***
|
||||||
|
\brief extract the minimal length of the sequence.
|
||||||
|
Return true if the minimal length is equal to the
|
||||||
|
maximal length (the sequence is bounded).
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) {
|
||||||
zstring s;
|
zstring s;
|
||||||
bool bounded = true;
|
bool bounded = true;
|
||||||
len = 0;
|
len = 0;
|
||||||
for (unsigned i = 0; i < n; ++i) {
|
for (expr* e : es) {
|
||||||
if (m_util.str.is_unit(es[i])) {
|
if (m_util.str.is_unit(e)) {
|
||||||
++len;
|
++len;
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_empty(es[i])) {
|
else if (m_util.str.is_empty(e)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_string(es[i], s)) {
|
else if (m_util.str.is_string(e, s)) {
|
||||||
len += s.length();
|
len += s.length();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2599,28 +2552,29 @@ bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs,
|
bool seq_rewriter::reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs,
|
||||||
expr_ref_pair_vector& eqs, bool& is_sat) {
|
expr_ref_pair_vector& eqs, bool& change) {
|
||||||
expr* n = nullptr;
|
expr* n = nullptr;
|
||||||
is_sat = true;
|
if (ls.size() == 1 && m_util.str.is_itos(ls.get(0), n) &&
|
||||||
if (szl == 1 && m_util.str.is_itos(ls[0], n) &&
|
solve_itos(n, rs, eqs)) {
|
||||||
solve_itos(n, szr, rs, eqs)) {
|
ls.reset(); rs.reset();
|
||||||
return true;
|
change = true;
|
||||||
}
|
}
|
||||||
if (szr == 1 && m_util.str.is_itos(rs[0], n) &&
|
else if (rs.size() == 1 && m_util.str.is_itos(rs.get(0), n) &&
|
||||||
solve_itos(n, szl, ls, eqs)) {
|
solve_itos(n, ls, eqs)) {
|
||||||
return true;
|
ls.reset(); rs.reset();
|
||||||
|
change = true;
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* itos(n) = <numeric string> -> n = numeric
|
* itos(n) = <numeric string> -> n = numeric
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool seq_rewriter::solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_pair_vector& eqs) {
|
bool seq_rewriter::solve_itos(expr* n, expr_ref_vector const& es, expr_ref_pair_vector& eqs) {
|
||||||
zstring s;
|
zstring s;
|
||||||
if (is_string(sz, es, s)) {
|
if (is_string(es.size(), es.c_ptr(), s)) {
|
||||||
std::string s1 = s.encode();
|
std::string s1 = s.encode();
|
||||||
rational r(s1.c_str());
|
rational r(s1.c_str());
|
||||||
if (s1 == r.to_string()) {
|
if (s1 == r.to_string()) {
|
||||||
|
@ -2631,116 +2585,94 @@ bool seq_rewriter::solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_pa
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
|
bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs,
|
||||||
expr_ref_pair_vector& eqs, bool& is_sat) {
|
expr_ref_pair_vector& eqs, bool& change) {
|
||||||
is_sat = true;
|
|
||||||
|
if (ls.empty() && rs.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
unsigned len1 = 0, len2 = 0;
|
unsigned len1 = 0, len2 = 0;
|
||||||
bool bounded1 = min_length(szl, l, len1);
|
bool bounded1 = min_length(ls, len1);
|
||||||
bool bounded2 = min_length(szr, r, len2);
|
bool bounded2 = min_length(rs, len2);
|
||||||
if (bounded1 && len1 < len2) {
|
if (bounded1 && len1 < len2)
|
||||||
is_sat = false;
|
return false;
|
||||||
return true;
|
if (bounded2 && len2 < len1)
|
||||||
}
|
return false;
|
||||||
if (bounded2 && len2 < len1) {
|
|
||||||
is_sat = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (bounded1 && len1 == len2 && len1 > 0) {
|
if (bounded1 && len1 == len2 && len1 > 0) {
|
||||||
is_sat = set_empty(szr, r, false, eqs);
|
change = true;
|
||||||
if (is_sat) {
|
if (!set_empty(rs.size(), rs.c_ptr(), false, eqs))
|
||||||
eqs.push_back(concat_non_empty(szl, l), concat_non_empty(szr, r));
|
return false;
|
||||||
//split_units(eqs);
|
eqs.push_back(concat_non_empty(ls), concat_non_empty(rs));
|
||||||
}
|
ls.reset();
|
||||||
return true;
|
rs.reset();
|
||||||
}
|
}
|
||||||
if (bounded2 && len1 == len2 && len1 > 0) {
|
else if (bounded2 && len1 == len2 && len1 > 0) {
|
||||||
if (is_sat) {
|
change = true;
|
||||||
eqs.push_back(concat_non_empty(szl, l), concat_non_empty(szr, r));
|
if (!set_empty(ls.size(), ls.c_ptr(), false, eqs))
|
||||||
//split_units(eqs);
|
return false;
|
||||||
}
|
eqs.push_back(concat_non_empty(ls), concat_non_empty(rs));
|
||||||
return true;
|
ls.reset();
|
||||||
|
rs.reset();
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void seq_rewriter::split_units(expr_ref_pair_vector& eqs) {
|
|
||||||
expr* a, *b, *a1, *b1, *a2, *b2;
|
|
||||||
while (!eqs.empty()) {
|
|
||||||
auto const& p = eqs.back();
|
|
||||||
if (m_util.str.is_unit(p.first, a) &&
|
|
||||||
m_util.str.is_unit(p.second, b)) {
|
|
||||||
eqs[eqs.size()-1] = std::make_pair(a, b);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (m_util.str.is_concat(p.first, a, a2) &&
|
|
||||||
m_util.str.is_unit(a, a1) &&
|
|
||||||
m_util.str.is_concat(p.second, b, b2) &&
|
|
||||||
m_util.str.is_unit(b, b1)) {
|
|
||||||
expr_ref _pin_a(p.first, m()), _pin_b(p.second, m());
|
|
||||||
eqs[eqs.size()-1] = std::make_pair(a1, b1);
|
|
||||||
eqs.push_back(a2, b2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool seq_rewriter::is_epsilon(expr* e) const {
|
bool seq_rewriter::is_epsilon(expr* e) const {
|
||||||
expr* e1;
|
expr* e1;
|
||||||
return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1);
|
return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
|
bool seq_rewriter::reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change) {
|
||||||
expr_ref_pair_vector& eqs, bool& is_sat) {
|
|
||||||
is_sat = true;
|
if (ls.size() > rs.size())
|
||||||
if (szl == szr) return false;
|
ls.swap(rs);
|
||||||
if (szr < szl) {
|
|
||||||
std::swap(szl, szr);
|
|
||||||
std::swap(l, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (ls.size() == rs.size())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (ls.empty() && rs.size() == 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
uint_set rpos;
|
uint_set rpos;
|
||||||
for (unsigned i = 0; i < szl; ++i) {
|
for (expr* x : ls) {
|
||||||
bool found = false;
|
|
||||||
unsigned j = 0;
|
unsigned j = 0;
|
||||||
bool is_unit = m_util.str.is_unit(l[i]);
|
bool is_unit = m_util.str.is_unit(x);
|
||||||
for (; !found && j < szr; ++j) {
|
for (expr* y : rs) {
|
||||||
found = !rpos.contains(j) && (l[i] == r[j] || (is_unit && m_util.str.is_unit(r[j])));
|
if (!rpos.contains(j) && (x == y || (is_unit && m_util.str.is_unit(y)))) {
|
||||||
|
rpos.insert(j);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++j;
|
||||||
}
|
}
|
||||||
|
if (j == rs.size())
|
||||||
if (!found) {
|
return true;
|
||||||
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.
|
// 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.
|
// or each non-unit in l is matched by a non-unit in r, and otherwise, the non-units match up.
|
||||||
bool change = false;
|
unsigned i = 0, j = 0;
|
||||||
ptr_vector<expr> rs;
|
for (expr* y : rs) {
|
||||||
for (unsigned j = 0; j < szr; ++j) {
|
if (rpos.contains(i)) {
|
||||||
if (rpos.contains(j)) {
|
rs[j++] = y;
|
||||||
rs.push_back(r[j]);
|
|
||||||
}
|
}
|
||||||
else if (!set_empty(1, r + j, true, eqs)) {
|
else if (!set_empty(1, &y, true, eqs)) {
|
||||||
is_sat = false;
|
return false;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
change = true;
|
|
||||||
}
|
}
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
if (!change) {
|
if (j == rs.size()) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
SASSERT(szl == rs.size());
|
change = true;
|
||||||
if (szl > 0) {
|
rs.shrink(j);
|
||||||
sort* srt = m().get_sort(l[0]);
|
SASSERT(ls.size() == rs.size());
|
||||||
eqs.push_back(m_util.str.mk_concat(szl, l, srt),
|
if (!ls.empty()) {
|
||||||
m_util.str.mk_concat(szl, rs.c_ptr(), srt));
|
sort* srt = m().get_sort(ls.get(0));
|
||||||
|
eqs.push_back(m_util.str.mk_concat(ls, srt),
|
||||||
|
m_util.str.mk_concat(rs, srt));
|
||||||
|
ls.reset();
|
||||||
|
rs.reset();
|
||||||
|
TRACE("seq", tout << "subsequence " << eqs << "\n";);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
||||||
#define SEQ_REWRITER_H_
|
#define SEQ_REWRITER_H_
|
||||||
|
|
||||||
#include "ast/seq_decl_plugin.h"
|
#include "ast/seq_decl_plugin.h"
|
||||||
|
#include "ast/ast_pp.h"
|
||||||
#include "ast/arith_decl_plugin.h"
|
#include "ast/arith_decl_plugin.h"
|
||||||
#include "ast/rewriter/rewriter_types.h"
|
#include "ast/rewriter/rewriter_types.h"
|
||||||
#include "util/ref_pair_vector.h"
|
#include "util/ref_pair_vector.h"
|
||||||
|
@ -31,6 +32,13 @@ Notes:
|
||||||
|
|
||||||
typedef ref_pair_vector<expr, ast_manager> expr_ref_pair_vector;
|
typedef ref_pair_vector<expr, ast_manager> expr_ref_pair_vector;
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, expr_ref_pair_vector const& es) {
|
||||||
|
for (auto const& p : es) {
|
||||||
|
out << expr_ref(p.first, es.get_manager()) << "; " << expr_ref(p.second, es.get_manager()) << "\n";
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
class sym_expr {
|
class sym_expr {
|
||||||
enum ty {
|
enum ty {
|
||||||
t_char,
|
t_char,
|
||||||
|
@ -166,15 +174,12 @@ class seq_rewriter {
|
||||||
bool sign_is_determined(expr* len, sign& s);
|
bool sign_is_determined(expr* len, sign& s);
|
||||||
|
|
||||||
bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs);
|
bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs);
|
||||||
bool is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
bool reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change);
|
||||||
expr_ref_pair_vector& eqs, bool& is_sat);
|
bool reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change);
|
||||||
bool length_constrained(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change);
|
||||||
expr_ref_pair_vector& eqs, bool& is_sat);
|
bool solve_itos(expr* n, expr_ref_vector const& es, expr_ref_pair_vector& eqs);
|
||||||
bool solve_itos(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
bool min_length(expr_ref_vector const& es, unsigned& len);
|
||||||
expr_ref_pair_vector& eqs, bool& is_sat);
|
expr* concat_non_empty(expr_ref_vector& es);
|
||||||
bool solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_pair_vector& eqs);
|
|
||||||
bool min_length(unsigned n, expr* const* es, unsigned& len);
|
|
||||||
expr* concat_non_empty(unsigned n, expr* const* es);
|
|
||||||
|
|
||||||
bool is_string(unsigned n, expr* const* es, zstring& s) const;
|
bool is_string(unsigned n, expr* const* es, zstring& s) const;
|
||||||
|
|
||||||
|
@ -182,10 +187,11 @@ class seq_rewriter {
|
||||||
bool is_sequence(expr* e, expr_ref_vector& seq);
|
bool is_sequence(expr* e, expr_ref_vector& seq);
|
||||||
bool is_sequence(eautomaton& aut, expr_ref_vector& seq);
|
bool is_sequence(eautomaton& aut, expr_ref_vector& seq);
|
||||||
bool is_epsilon(expr* e) const;
|
bool is_epsilon(expr* e) const;
|
||||||
void split_units(expr_ref_pair_vector& eqs);
|
|
||||||
bool get_lengths(expr* e, expr_ref_vector& lens, rational& pos);
|
bool get_lengths(expr* e, expr_ref_vector& lens, rational& pos);
|
||||||
|
bool reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change);
|
||||||
|
bool reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change);
|
||||||
|
void remove_empty(expr_ref_vector& es);
|
||||||
|
void remove_leading(unsigned n, expr_ref_vector& es);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||||
|
|
|
@ -403,7 +403,6 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
|
||||||
if (is_sort_param(sP, idx)) {
|
if (is_sort_param(sP, idx)) {
|
||||||
if (binding.size() <= idx) binding.resize(idx+1);
|
if (binding.size() <= idx) binding.resize(idx+1);
|
||||||
if (binding[idx] && (binding[idx] != s)) return false;
|
if (binding[idx] && (binding[idx] != s)) return false;
|
||||||
TRACE("seq_verbose", tout << "setting binding @ " << idx << " to " << mk_pp(s, *m_manager) << "\n";);
|
|
||||||
binding[idx] = s;
|
binding[idx] = s;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -433,11 +432,6 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
|
||||||
void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
||||||
ptr_vector<sort> binding;
|
ptr_vector<sort> binding;
|
||||||
ast_manager& m = *m_manager;
|
ast_manager& m = *m_manager;
|
||||||
TRACE("seq_verbose",
|
|
||||||
tout << sig.m_name << ": ";
|
|
||||||
for (unsigned i = 0; i < dsz; ++i) tout << mk_pp(dom[i], m) << " ";
|
|
||||||
if (range) tout << " range: " << mk_pp(range, m);
|
|
||||||
tout << "\n";);
|
|
||||||
if (dsz == 0) {
|
if (dsz == 0) {
|
||||||
std::ostringstream strm;
|
std::ostringstream strm;
|
||||||
strm << "Unexpected number of arguments to '" << sig.m_name << "' ";
|
strm << "Unexpected number of arguments to '" << sig.m_name << "' ";
|
||||||
|
@ -466,7 +460,6 @@ void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* do
|
||||||
}
|
}
|
||||||
range_out = apply_binding(binding, sig.m_range);
|
range_out = apply_binding(binding, sig.m_range);
|
||||||
SASSERT(range_out);
|
SASSERT(range_out);
|
||||||
TRACE("seq_verbose", tout << mk_pp(range_out, m) << "\n";);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
||||||
|
|
|
@ -29,12 +29,7 @@ bool theory_seq::solve_nqs(unsigned i) {
|
||||||
context & ctx = get_context();
|
context & ctx = get_context();
|
||||||
for (; !ctx.inconsistent() && i < m_nqs.size(); ++i) {
|
for (; !ctx.inconsistent() && i < m_nqs.size(); ++i) {
|
||||||
if (solve_ne(i)) {
|
if (solve_ne(i)) {
|
||||||
if (i + 1 != m_nqs.size()) {
|
m_nqs.erase_and_swap(i--);
|
||||||
ne n = m_nqs[m_nqs.size()-1];
|
|
||||||
m_nqs.set(i, n);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
m_nqs.pop_back();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_new_propagation || ctx.inconsistent();
|
return m_new_propagation || ctx.inconsistent();
|
||||||
|
@ -100,6 +95,7 @@ bool theory_seq::propagate_ne2lit(unsigned idx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (undef_lit == null_literal) {
|
if (undef_lit == null_literal) {
|
||||||
|
display_disequation(verbose_stream() << "conflict:", n) << "\n";
|
||||||
dependency* dep = n.dep();
|
dependency* dep = n.dep();
|
||||||
dependency* dep1 = nullptr;
|
dependency* dep1 = nullptr;
|
||||||
if (explain_eq(n.l(), n.r(), dep1)) {
|
if (explain_eq(n.l(), n.r(), dep1)) {
|
||||||
|
@ -166,12 +162,15 @@ bool theory_seq::reduce_ne(unsigned idx) {
|
||||||
if (!canonize(p.first, ls, deps, change)) return false;
|
if (!canonize(p.first, ls, deps, change)) return false;
|
||||||
if (!canonize(p.second, rs, deps, change)) return false;
|
if (!canonize(p.second, rs, deps, change)) return false;
|
||||||
new_deps = m_dm.mk_join(deps, new_deps);
|
new_deps = m_dm.mk_join(deps, new_deps);
|
||||||
|
bool is_sat = m_seq_rewrite.reduce_eq(ls, rs, eqs, change);
|
||||||
|
|
||||||
if (!m_seq_rewrite.reduce_eq(ls, rs, eqs, change)) {
|
TRACE("seq", display_disequation(tout << "reduced\n", n);
|
||||||
TRACE("seq", display_disequation(tout << "reduces to false: ", n);
|
tout << p.first << " -> " << ls << "\n";
|
||||||
tout << p.first << " -> " << ls << "\n";
|
tout << p.second << " -> " << rs << "\n";
|
||||||
tout << p.second << " -> " << rs << "\n";);
|
tout << eqs << "\n";
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!is_sat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +192,9 @@ bool theory_seq::reduce_ne(unsigned idx) {
|
||||||
new_eqs.push_back(decomposed_eq(ls, rs));
|
new_eqs.push_back(decomposed_eq(ls, rs));
|
||||||
}
|
}
|
||||||
TRACE("seq",
|
TRACE("seq",
|
||||||
for (auto const& p : eqs) tout << mk_pp(p.first, m) << " != " << mk_pp(p.second, m) << "\n";
|
tout << "num eqs: " << eqs.size() << "\n";
|
||||||
|
tout << "num new eqs: " << new_eqs.size() << "\n";
|
||||||
|
tout << eqs << "\n";
|
||||||
for (auto const& p : new_eqs) tout << p.first << " != " << p.second << "\n";
|
for (auto const& p : new_eqs) tout << p.first << " != " << p.second << "\n";
|
||||||
tout << p.first << " != " << p.second << "\n";);
|
tout << p.first << " != " << p.second << "\n";);
|
||||||
|
|
||||||
|
@ -225,11 +226,15 @@ bool theory_seq::reduce_ne(unsigned idx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TRACE("seq", display_disequation(tout << "updated: " << updated << "\n", n););
|
TRACE("seq", display_disequation(tout << "updated: " << updated << "\n", n);
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
if (updated) {
|
if (updated) {
|
||||||
m_nqs.set(idx, ne(n.l(), n.r(), new_eqs, new_lits, new_deps));
|
auto new_n(ne(n.l(), n.r(), new_eqs, new_lits, new_deps));
|
||||||
TRACE("seq", display_disequation(tout << "updated: ", m_nqs[idx]););
|
m_nqs.set(idx, new_n);
|
||||||
|
TRACE("seq", display_disequation(tout << "updated:\n", m_nqs[idx]););
|
||||||
|
TRACE("seq", display_disequation(tout << "updated:\n", new_n););
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ expr_ref seq_skolem::mk_unit_inv(expr* n) {
|
||||||
expr* u = nullptr;
|
expr* u = nullptr;
|
||||||
VERIFY(seq.str.is_unit(n, u));
|
VERIFY(seq.str.is_unit(n, u));
|
||||||
sort* s = m.get_sort(u);
|
sort* s = m.get_sort(u);
|
||||||
return mk(symbol("seq.unit-inv"), n, nullptr, nullptr, nullptr, s);
|
return mk(symbol("seq.unit-inv"), n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,8 @@ namespace smt {
|
||||||
bool is_skolem(symbol const& s, expr* e) const;
|
bool is_skolem(symbol const& s, expr* e) const;
|
||||||
bool is_skolem(expr* e) const { return seq.is_skolem(e); }
|
bool is_skolem(expr* e) const { return seq.is_skolem(e); }
|
||||||
|
|
||||||
|
bool is_unit_inv(expr* e) const { return is_skolem(symbol("seq.unit-inv"), e); }
|
||||||
|
bool is_unit_inv(expr* e, expr*& u) const { return is_unit_inv(e) && (u = to_app(e)->get_arg(0), true); }
|
||||||
bool is_tail(expr* e) const { return is_skolem(m_tail, e); }
|
bool is_tail(expr* e) const { return is_skolem(m_tail, e); }
|
||||||
bool is_seq_first(expr* e) const { return is_skolem(m_seq_first, e); }
|
bool is_seq_first(expr* e) const { return is_skolem(m_seq_first, e); }
|
||||||
bool is_indexof_left(expr* e) const { return is_skolem(m_indexof_left, e); }
|
bool is_indexof_left(expr* e) const { return is_skolem(m_indexof_left, e); }
|
||||||
|
|
|
@ -1761,6 +1761,19 @@ std::ostream& theory_seq::display_deps(std::ostream& out, literal_vector const&
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& theory_seq::display_deps_smt2(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const {
|
||||||
|
params_ref p;
|
||||||
|
for (auto const& eq : eqs) {
|
||||||
|
out << " (= " << mk_pp(eq.first->get_owner(), m)
|
||||||
|
<< "\n " << mk_pp(eq.second->get_owner(), m)
|
||||||
|
<< ")\n";
|
||||||
|
}
|
||||||
|
for (literal l : lits) {
|
||||||
|
get_context().display_literal_smt2(out, l) << "\n";
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& theory_seq::display_lit(std::ostream& out, literal l) const {
|
std::ostream& theory_seq::display_lit(std::ostream& out, literal l) const {
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
if (l == true_literal) {
|
if (l == true_literal) {
|
||||||
|
@ -2181,6 +2194,12 @@ expr_ref theory_seq::elim_skolem(expr* e) {
|
||||||
todo.pop_back();
|
todo.pop_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (m_sk.is_unit_inv(a, x) && cache.contains(x) && m_util.str.is_unit(cache[x], y)) {
|
||||||
|
result = y;
|
||||||
|
cache.insert(a, result);
|
||||||
|
todo.pop_back();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
args.reset();
|
args.reset();
|
||||||
for (expr* arg : *to_app(a)) {
|
for (expr* arg : *to_app(a)) {
|
||||||
|
@ -2219,7 +2238,7 @@ void theory_seq::validate_axiom(literal_vector const& lits) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::validate_conflict(enode_pair_vector const& eqs, literal_vector const& lits) {
|
void theory_seq::validate_conflict(enode_pair_vector const& eqs, literal_vector const& lits) {
|
||||||
IF_VERBOSE(10, display_deps(verbose_stream() << "; conflict\n", lits, eqs));
|
IF_VERBOSE(10, display_deps_smt2(verbose_stream() << "cn ", lits, eqs));
|
||||||
if (get_context().get_fparams().m_seq_validate) {
|
if (get_context().get_fparams().m_seq_validate) {
|
||||||
expr_ref_vector fmls(m);
|
expr_ref_vector fmls(m);
|
||||||
validate_fmls(eqs, lits, fmls);
|
validate_fmls(eqs, lits, fmls);
|
||||||
|
@ -2227,7 +2246,7 @@ void theory_seq::validate_conflict(enode_pair_vector const& eqs, literal_vector
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::validate_assign(literal lit, enode_pair_vector const& eqs, literal_vector const& lits) {
|
void theory_seq::validate_assign(literal lit, enode_pair_vector const& eqs, literal_vector const& lits) {
|
||||||
IF_VERBOSE(10, display_deps(verbose_stream() << "; assign\n", lits, eqs); display_lit(verbose_stream(), ~lit) << "\n");
|
IF_VERBOSE(10, display_deps_smt2(verbose_stream() << "eq ", lits, eqs); display_lit(verbose_stream(), ~lit) << "\n");
|
||||||
if (get_context().get_fparams().m_seq_validate) {
|
if (get_context().get_fparams().m_seq_validate) {
|
||||||
literal_vector _lits(lits);
|
literal_vector _lits(lits);
|
||||||
_lits.push_back(~lit);
|
_lits.push_back(~lit);
|
||||||
|
@ -2269,6 +2288,7 @@ void theory_seq::validate_fmls(enode_pair_vector const& eqs, literal_vector cons
|
||||||
for (expr* f : fmls) {
|
for (expr* f : fmls) {
|
||||||
k.assert_expr(f);
|
k.assert_expr(f);
|
||||||
}
|
}
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "validate: " << fmls << "\n";);
|
||||||
lbool r = k.check();
|
lbool r = k.check();
|
||||||
if (r != l_false && !m.limit().get_cancel_flag()) {
|
if (r != l_false && !m.limit().get_cancel_flag()) {
|
||||||
model_ref mdl;
|
model_ref mdl;
|
||||||
|
|
|
@ -678,6 +678,7 @@ namespace smt {
|
||||||
std::ostream& display_disequation(std::ostream& out, ne const& e) const;
|
std::ostream& display_disequation(std::ostream& out, ne const& e) const;
|
||||||
std::ostream& display_deps(std::ostream& out, dependency* deps) const;
|
std::ostream& display_deps(std::ostream& out, dependency* deps) const;
|
||||||
std::ostream& display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const;
|
std::ostream& display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const;
|
||||||
|
std::ostream& display_deps_smt2(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const;
|
||||||
std::ostream& display_nc(std::ostream& out, nc const& nc) const;
|
std::ostream& display_nc(std::ostream& out, nc const& nc) const;
|
||||||
std::ostream& display_lit(std::ostream& out, literal l) const;
|
std::ostream& display_lit(std::ostream& out, literal l) const;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -103,7 +103,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ref_pair_vector_core& push_back(T * a, T* b) {
|
ref_pair_vector_core& push_back(T * a, T* b) {
|
||||||
return push_back(std::make_pair(a, b));
|
inc_ref(a);
|
||||||
|
inc_ref(b);
|
||||||
|
m_nodes.push_back(elem_t(a, b));
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
|
|
Loading…
Reference in a new issue