From a0b359212eb98f317e2c656cbce973d9b5756613 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 05:39:33 +0000 Subject: [PATCH] Apply ZIPT improvements: fix loop nullable, drop bounds check, symmetric star merging Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com> --- src/ast/euf/euf_seq_plugin.cpp | 7 ++++++- src/ast/euf/euf_sgraph.cpp | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/ast/euf/euf_seq_plugin.cpp b/src/ast/euf/euf_seq_plugin.cpp index 618b1699a..0a025c5c7 100644 --- a/src/ast/euf/euf_seq_plugin.cpp +++ b/src/ast/euf/euf_seq_plugin.cpp @@ -212,11 +212,16 @@ namespace euf { if (same_star_body(a, b)) push_merge(n, a); - // Rule 1 extended: concat(v*, concat(v*, c)) = concat(v*, c) + // Rule 1 extended (right): concat(v*, concat(v*, c)) = concat(v*, c) enode* b1, *b2; if (is_concat(b, b1, b2) && same_star_body(a, b1)) push_merge(n, b); + // Rule 1 extended (left): concat(concat(c, v*), v*) = concat(c, v*) + enode* a1, *a2; + if (is_concat(a, a1, a2) && same_star_body(a2, b)) + push_merge(n, a); + // Rule 2: Nullable absorption by .* // concat(.*, v) = .* when v is nullable if (is_full_seq(a) && is_nullable(b)) diff --git a/src/ast/euf/euf_sgraph.cpp b/src/ast/euf/euf_sgraph.cpp index eff926004..b332cd2a4 100644 --- a/src/ast/euf/euf_sgraph.cpp +++ b/src/ast/euf/euf_sgraph.cpp @@ -200,13 +200,18 @@ namespace euf { n->m_length = 1; break; - case snode_kind::s_loop: + case snode_kind::s_loop: { + bool body_nullable = n->num_args() > 0 && n->arg(0)->is_nullable(); + unsigned lo = 0, hi = 0; + expr* body = nullptr; + bool lo_zero = n->get_expr() && m_seq.re.is_loop(n->get_expr(), body, lo, hi) && lo == 0; n->m_ground = n->num_args() > 0 ? n->arg(0)->is_ground() : true; n->m_regex_free = false; - n->m_nullable = false; // depends on lower bound + n->m_nullable = lo_zero || body_nullable; n->m_level = 1; n->m_length = 1; break; + } case snode_kind::s_union: SASSERT(n->num_args() == 2); @@ -461,13 +466,17 @@ namespace euf { } snode* sgraph::drop_left(snode* n, unsigned count) { - for (unsigned i = 0; i < count && !n->is_empty(); ++i) + if (count == 0 || n->is_empty()) return n; + if (count >= n->length()) return mk_empty(); + for (unsigned i = 0; i < count; ++i) n = drop_first(n); return n; } snode* sgraph::drop_right(snode* n, unsigned count) { - for (unsigned i = 0; i < count && !n->is_empty(); ++i) + if (count == 0 || n->is_empty()) return n; + if (count >= n->length()) return mk_empty(); + for (unsigned i = 0; i < count; ++i) n = drop_last(n); return n; }