3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-15 03:25:43 +00:00

bug fixes to split-set

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2026-07-03 19:31:29 -07:00
parent b095adfa81
commit 52e6f885b9
4 changed files with 35 additions and 39 deletions

View file

@ -81,6 +81,7 @@ struct split_set::iterator::imp {
}
}
void consume() override {
TRACE(seq, tout << "intersection consume\n");
while (!at_end() && !parent().has_split()) {
auto [a1, a2] = *a_it;
auto [b1, b2] = *b_it;
@ -146,6 +147,7 @@ struct split_set::iterator::imp {
}
void consume() override {
TRACE(seq, tout << "complement consume\n");
init();
if (m_intersection)
m_intersection->consume();
@ -161,6 +163,7 @@ struct split_set::iterator::imp {
: a_s(std::move(a_src)), a_it(a_s.begin()), a_end(a_s.end()), b(b, a_s.m_imp->m) {}
void consume() override {
TRACE(seq, tout << "concat_left consume\n");
while (a_it != a_end && !parent().has_split()) {
auto [p, q] = *a_it;
parent().push_split(p, parent().i.rw.mk_re_append(q, b));
@ -179,6 +182,7 @@ struct split_set::iterator::imp {
concat_right(expr* a, split_set&& b_src) : a(a, b_src.m_imp->m), b_s(std::move(b_src)), b_it(b_s.begin()), b_end(b_s.end()) {}
void consume() override {
TRACE(seq, tout << "concat_right consume\n");
while (b_it != b_end && !parent().has_split()) {
auto [p, q] = *b_it;
parent().push_split(parent().i.rw.mk_re_append(a, p), q);
@ -206,7 +210,9 @@ struct split_set::iterator::imp {
}
void consume() override {
TRACE(seq, tout << "concat-start: " << mk_pp(a, parent().i.m) << " " << mk_pp(b, parent().i.m) << "\n");
while (!parent().has_split() && !at_end() && !a_it.failed() && !b_it.failed()) {
TRACE(seq, tout << "concat: " << mk_pp(a, parent().i.m) << " " << mk_pp(b, parent().i.m) << "\n");
if (a_it == a_end) {
auto [p, q] = *b_it;
parent().push_split(parent().i.rw.mk_re_append(a, p), q);
@ -233,9 +239,10 @@ struct split_set::iterator::imp {
bool m_init = false;
unsigned m_qhead = 0;
scoped_ptr<split_set::consumer> m_consumer;
bool m_at_end;
bool m_end_marker;
bool m_at_end = false;
bool m_failure = false;
imp(split_set &s, bool at_end) : s(s), i(*s.m_imp), m(i.m), seq(i.seq), re(i.re), m_cont(m), m_at_end(at_end) {
imp(split_set &s, bool at_end) : s(s), i(*s.m_imp), m(i.m), seq(i.seq), re(i.re), m_cont(m), m_end_marker(at_end) {
if (at_end)
m_init = true;
else if (i.r) {
@ -255,6 +262,7 @@ struct split_set::iterator::imp {
}
void rewind() {
TRACE(seq, tout << "rewind: " << m_splits.size() << "\n";);
m_qhead = 0;
m_at_end = m_qhead == m_splits.size();
SASSERT(m_cont.empty());
@ -292,7 +300,6 @@ struct split_set::iterator::imp {
void push_split(expr *_a, expr *_b) {
expr_ref a(_a, m), b(_b, m);
if (m_failure)
return;
if (i.m_filter && !i.m_filter(a, b))
@ -364,6 +371,7 @@ struct split_set::iterator::imp {
}
if (re.is_concat(r, a, b)) {
TRACE(seq, tout << "concat-start: " << mk_pp(a, i.m) << " " << mk_pp(b, i.m) << "\n");
m_consumer = alloc(concat, i.rw, a, b, i.m_threshold);
m_consumer->set_parent(*this);
return;
@ -452,7 +460,7 @@ struct split_set::iterator::imp {
}
bool at_end() const {
return m_failure || (m_at_end && m_qhead == m_splits.size());
return m_failure || m_end_marker || (m_at_end && m_qhead == m_splits.size());
}
};
@ -512,29 +520,15 @@ std::pair<expr_ref, expr_ref> split_set::try_split_sequence(expr *str) {
ast_manager &m = m_imp->m;
auto &seq = m_imp->seq;
if (!seq.str.is_concat(str))
return {expr_ref(m), expr_ref(m)};
expr_ref_vector tokens(m);
vector<expr *> stack;
stack.push_back(str);
while (!stack.empty()) {
expr *cur = stack.back();
stack.pop_back();
expr *l, *r;
if (seq.str.is_concat(cur, l, r)) {
stack.push_back(r);
stack.push_back(l);
}
else
tokens.push_back(expr_ref(cur, m));
}
seq.str.get_concat(str, tokens);
SASSERT(tokens.size() > 1);
expr *ch;
unsigned i = 0;
// TODO: Do this for the back as well (also, why did no rule before do that?)
if (tokens.empty())
return {expr_ref(m), expr_ref(m)};
// Choose the factorization boundary so the tail starts with the
// longest run of concrete characters c.
@ -543,12 +537,12 @@ std::pair<expr_ref, expr_ref> split_set::try_split_sequence(expr *str) {
const unsigned total = tokens.size();
unsigned run_start = 0, run_len = 0;
for (i = 1; i < total;) {
if (!(seq.str.is_unit(tokens.get(i), ch) && seq.is_const_char(ch))) {
if (!(seq.str.is_unit(tokens.get(i), ch) && m.is_value(ch))) {
i++;
continue;
}
unsigned j = i;
while (j < total && seq.str.is_unit(tokens.get(j), ch) && seq.is_const_char(ch)) {
while (j < total && seq.str.is_unit(tokens.get(j), ch) && m.is_value(ch)) {
j++;
}
if (j - i > run_len) {
@ -560,16 +554,16 @@ std::pair<expr_ref, expr_ref> split_set::try_split_sequence(expr *str) {
// No constant run => fall back to splitting off the first token.
const unsigned p = run_len == 0 ? 1 : run_start;
SASSERT(p >= 1);
expr *head = tokens.get(0);
for (i = 1; i < p; i++) {
head = seq.str.mk_concat(head, tokens.get(i));
}
expr *tail = seq.str.mk_empty(head->get_sort());
if (tokens.size() > p + run_len) {
tail = tokens.get(p + run_len);
for (i = p + run_len + 1; i < tokens.size(); i++) {
tail = seq.str.mk_concat(tail, tokens.get(i));
}
}
return {expr_ref(head, m), expr_ref(tail, m)};
SASSERT(p < total);
expr_ref head(tokens.get(p - 1), m);
for (unsigned i = p - 1; i-- > 0;)
head = seq.str.mk_concat(tokens.get(i), head);
expr_ref tail(tokens.back(), m);
for (unsigned i = tokens.size() - 1; i-- > p;)
tail = seq.str.mk_concat(tokens.get(i), tail);
TRACE(seq, tout << "split_set::try_split_sequence: " << mk_pp(str, m) << " -> " << head << " | "
<< tail << "\n");
return { head, tail };
}

View file

@ -51,6 +51,8 @@ public:
split_set(split_set&& other) noexcept;
split_set &operator=(split_set const &other) = delete;
class iterator {
struct imp;
imp *m_imp;

View file

@ -27,7 +27,7 @@ Author:
namespace smt {
seq_regex::split_cont::split_cont(seq_regex &sr, split_set &&ss, literal lit, expr *u, expr *v, expr *r)
: m_regex(sr), m_u(u), m_v(v), m_split(std::move(ss)), m_it(m_split.begin()), m_end(m_split.end()),
: m_regex(sr), m_u(u, sr.m), m_v(v, sr.m), m_r(r, sr.m), m_split(std::move(ss)), m_it(m_split.begin()), m_end(m_split.end()),
m_in_re2(sr.m), m_lit(lit) {}
bool seq_regex::split_cont::failed() const {
@ -476,7 +476,7 @@ namespace smt {
if (re().is_empty(q))
return false;
}
return re().is_empty(q);
return !re().is_empty(q);
};
split_set result(seq_rw(), r, threshold, filter);

View file

@ -119,7 +119,7 @@ namespace smt {
class split_cont {
seq_regex &m_regex;
split_set m_split;
expr *m_u, *m_v, *m_r;
expr_ref m_u, m_v, m_r;
split_set::iterator m_it;
split_set::iterator m_end;
expr_ref_vector m_in_re2;