From f0956a622f32f013803d12b2a01dbc2fb3a1e37c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Jun 2026 13:42:28 -0700 Subject: [PATCH] Refactor regex subset logic into `seq_subset` with depth-bounded recursion and optimized concat traversal (#9777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `seq_rewriter::is_subset` was too localized and missed key subset implications for regex concatenations. This change extracts subset reasoning into a dedicated component and adds heuristic closure/monotonicity rules, then tunes the recursion strategy based on profiling feedback. - **Architecture: isolate subset reasoning** - Introduce `seq_subset` in `src/ast/rewriter` (`seq_subset.h/.cpp`). - Add `seq_subset` as an attribute on `seq_rewriter` and route `seq_rewriter::is_subset` through it. - Keep `seq_rewriter` focused on rewrite orchestration while subset logic evolves independently. - **Subset rules: broaden inferable cases** - Add derive-style subset decomposition across `union`, `intersection`, `complement`, `concat`, and bounded `loop`. - Add E3-style closure rules: - `R ⊆ R*` - `R1* ⊆ R2* ⇐ R1 ⊆ R2` - `R1+ ⊆ R2+ ⇐ R1 ⊆ R2` - Add missing cheap cases: - `ε ⊆ R` when `R` is nullable - `R ⊆ R+` - `R+ ⊆ R*` - Range containment: `[c1–c2] ⊆ [c3–c4]` when `c3 ≤ c1 ∧ c2 ≤ c4` - `to_re(s) ⊆ range` for single-character string constants - Difference monotonicity: `a1 \ a2 ⊆ b` when `a1 ⊆ b` - Star absorption checks for concat/star combinations (`R·R* ⊆ R*`, `R*·R ⊆ R*`) - Preserve nullable-based `. +` handling and top/bottom regular-language shortcuts. - **Concatenation reasoning and traversal tuning** - Remove `flatten_concat` and assume right-associative concatenation traversal. - Keep containment shortcuts for both `R ⊆ Σ*·R'` and `R ⊆ R'·Σ*` when `R ⊆ R'`. - Make concat/concat handling tail-recursive on second arguments. - **Depth-bounded recursion (profiling follow-up)** - Replace visited-pair hash-table recursion state with an explicit depth parameter in `is_subset_rec`. - Add `m_max_depth = 3` and return `false` when the bound is reached. - Increment depth on recursive calls, except for the tail-recursive concat-second-argument step. - **Build integration** - Register `seq_subset.cpp` in `src/ast/rewriter/CMakeLists.txt`. ```cpp // seq_rewriter.cpp bool seq_rewriter::is_subset(expr* r1, expr* r2) const { return m_subset.is_subset(r1, r2); } ``` --------- Signed-off-by: Nikolaj Bjorner Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Nikolaj Bjorner --- gmon.out | Bin 0 -> 14458562 bytes src/ast/rewriter/CMakeLists.txt | 1 + src/ast/rewriter/seq_rewriter.cpp | 47 +--------- src/ast/rewriter/seq_rewriter.h | 5 +- src/ast/rewriter/seq_subset.cpp | 146 ++++++++++++++++++++++++++++++ src/ast/rewriter/seq_subset.h | 30 ++++++ 6 files changed, 181 insertions(+), 48 deletions(-) create mode 100644 gmon.out create mode 100644 src/ast/rewriter/seq_subset.cpp create mode 100644 src/ast/rewriter/seq_subset.h diff --git a/gmon.out b/gmon.out new file mode 100644 index 0000000000000000000000000000000000000000..cba10a19b2a99a2517d591f2bf1b928974a77eb5 GIT binary patch literal 14458562 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 C(qiub literal 0 HcmV?d00001 diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 9d529f9b5..ba7eda277 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -39,6 +39,7 @@ z3_add_component(rewriter rewriter.cpp seq_axioms.cpp seq_eq_solver.cpp + seq_subset.cpp seq_rewriter.cpp seq_skolem.cpp th_rewriter.cpp diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 4453c94a7..26455e2f1 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -4587,51 +4587,7 @@ bool seq_rewriter::are_complements(expr* r1, expr* r2) const { * basic subset checker. */ bool seq_rewriter::is_subset(expr* r1, expr* r2) const { - // return false; - expr* ra1 = nullptr, *ra2 = nullptr, *ra3 = nullptr; - expr* rb1 = nullptr, *rb2 = nullptr, *rb3 = nullptr; - unsigned la, ua, lb, ub; - if (re().is_complement(r1, ra1) && - re().is_complement(r2, rb1)) { - return is_subset(rb1, ra1); - } - auto is_concat = [&](expr* r, expr*& a, expr*& b, expr*& c) { - return re().is_concat(r, a, b) && re().is_concat(b, b, c); - }; - while (true) { - if (r1 == r2) - return true; - if (re().is_full_seq(r2)) - return true; - if (re().is_dot_plus(r2) && re().get_info(r1).nullable == l_false) - return true; - if (is_concat(r1, ra1, ra2, ra3) && - is_concat(r2, rb1, rb2, rb3) && ra1 == rb1 && ra2 == rb2) { - r1 = ra3; - r2 = rb3; - continue; - } - if (re().is_concat(r1, ra1, ra2) && - re().is_concat(r2, rb1, rb2) && re().is_full_seq(rb1)) { - r1 = ra2; - continue; - } - // r1=ra3{la,ua}ra2, r2=rb3{lb,ub}rb2, ra3=rb3, lb<=la, ua<=ub - if (re().is_concat(r1, ra1, ra2) && re().is_loop(ra1, ra3, la, ua) && - re().is_concat(r2, rb1, rb2) && re().is_loop(rb1, rb3, lb, ub) && - ra3 == rb3 && lb <= la && ua <= ub) { - r1 = ra2; - r2 = rb2; - continue; - } - // ra1=ra3{la,ua}, r2=rb3{lb,ub}, ra3=rb3, lb<=la, ua<=ub - if (re().is_loop(r1, ra3, la, ua) && - re().is_loop(r2, rb3, lb, ub) && - ra3 == rb3 && lb <= la && ua <= ub) { - return true; - } - return false; - } + return m_subset.is_subset(r1, r2); } br_status seq_rewriter::mk_re_union0(expr* a, expr* b, expr_ref& result) { @@ -6163,4 +6119,3 @@ bool seq_rewriter::get_bounds(expr* e, unsigned& low, unsigned& high) { } return low <= high; } - diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 583720911..4ebd770a7 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -23,6 +23,7 @@ Notes: #include "ast/arith_decl_plugin.h" #include "ast/rewriter/rewriter_types.h" #include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/seq_subset.h" #include "util/params.h" #include "util/lbool.h" #include "util/sign.h" @@ -128,6 +129,7 @@ class seq_rewriter { }; seq_util m_util; + seq_subset m_subset; arith_util m_autil; bool_rewriter m_br; // re2automaton m_re2aut; @@ -340,7 +342,7 @@ class seq_rewriter { public: seq_rewriter(ast_manager & m, params_ref const & p = params_ref()): - m_util(m), m_autil(m), m_br(m, p), // m_re2aut(m), + m_util(m), m_subset(m_util.re), m_autil(m), m_br(m, p), // m_re2aut(m), m_op_cache(m), m_es(m), m_lhs(m), m_rhs(m), m_coalesce_chars(true) { } @@ -424,4 +426,3 @@ public: */ lbool some_string_in_re(expr* r, zstring& s); }; - diff --git a/src/ast/rewriter/seq_subset.cpp b/src/ast/rewriter/seq_subset.cpp new file mode 100644 index 000000000..2fc4d1f71 --- /dev/null +++ b/src/ast/rewriter/seq_subset.cpp @@ -0,0 +1,146 @@ +/*++ +Copyright (c) 2026 Microsoft Corporation + +Module Name: + + seq_subset.cpp + +Abstract: + + Heuristic regular-expression subset checks used by seq_rewriter. + +Author: + + Nikolaj Bjorner (nbjorner) 2026-6-8 + +--*/ + +#include "ast/rewriter/seq_subset.h" + +bool seq_subset::is_subset_rec(expr* a, expr* b, unsigned depth) const { + while (true) { + + if (a == b) + return true; + if (m_re.is_empty(a)) + return true; + if (m_re.is_full_seq(b)) + return true; + if (m_re.is_epsilon(a) && m_re.get_info(b).nullable == l_true) + return true; + + if (depth >= m_max_depth) + return false; + + expr* a1 = nullptr, * a2 = nullptr, * b1 = nullptr, * b2 = nullptr; + unsigned la, ua, lb, ub; + + // a ⊆ .+ iff a is non-nullable + if (m_re.is_dot_plus(b) && m_re.get_info(a).nullable == l_false) + return true; + + // a ⊆ a* + if (m_re.is_star(b, b1) && is_subset_rec(a, b1, depth)) + return true; + + // e ⊆ a* + if (m_re.is_epsilon(a) && m_re.is_star(b, b1)) + return true; + + // R ⊆ R* + if (m_re.is_star(b, b1) && is_subset_rec(a, b1, depth + 1)) + return true; + + // R1* ⊆ R2* if R1 ⊆ R2 + if (m_re.is_star(a, a1) && m_re.is_star(b, b1) && is_subset_rec(a1, b1, depth + 1)) + return true; + + // R1+ ⊆ R2+ if R1 ⊆ R2 + if (m_re.is_plus(a, a1) && m_re.is_plus(b, b1) && is_subset_rec(a1, b1, depth)) + return true; + + // R ⊆ R+ + if (m_re.is_plus(b, b1) && is_subset_rec(a, b1, depth)) + return true; + + // R+ ⊆ R* + if (m_re.is_plus(a, a1) && m_re.is_star(b, b1) && is_subset_rec(a1, b1, depth + 1)) + return true; + + // range containment + if (m_re.is_range(a, la, ua) && m_re.is_range(b, lb, ub) && lb <= la && ua <= ub) + return true; + + // to_re(s) ⊆ range + if (m_re.is_to_re(a, a1) && m_re.is_range(b, lb, ub) && is_app(a1)) { + func_decl* f = to_app(a1)->get_decl(); + if (f->get_decl_kind() == OP_STRING_CONST && f->get_num_parameters() == 1) { + zstring const& s = f->get_parameter(0).get_zstring(); + if (s.length() == 1 && lb <= s[0] && s[0] <= ub) + return true; + } + } + + // a ⊆ b1 ∪ b2 if a ⊆ b1 or a ⊆ b2 + if (m_re.is_union(b, b1, b2) && (is_subset_rec(a, b1, depth + 1) || is_subset_rec(a, b2, depth + 1))) + return true; + + // a1 ∪ a2 ⊆ b if a1 ⊆ b and a2 ⊆ b + if (m_re.is_union(a, a1, a2) && is_subset_rec(a1, b, depth + 1) && is_subset_rec(a2, b, depth + 1)) + return true; + + // a1 ∩ a2 ⊆ b if a1 ⊆ b or a2 ⊆ b + if (m_re.is_intersection(a, a1, a2) && (is_subset_rec(a1, b, depth + 1) || is_subset_rec(a2, b, depth + 1))) + return true; + + // a ⊆ b1 ∩ b2 if a ⊆ b1 and a ⊆ b2 + if (m_re.is_intersection(b, b1, b2) && is_subset_rec(a, b1, depth + 1) && is_subset_rec(a, b2, depth + 1)) + return true; + + // R{la,ua} ⊆ R'{lb,ub} if R ⊆ R', lb<=la, ua<=ub + if (m_re.is_loop(a, a1, la, ua) && + m_re.is_loop(b, b1, lb, ub) && + lb <= la && ua <= ub && is_subset_rec(a1, b1, depth + 1)) { + return true; + } + + // a1 \ a2 ⊆ b if a1 ⊆ b + if (m_re.is_diff(a, a1, a2) && is_subset_rec(a1, b, depth + 1)) + return true; + + // R ⊆ Σ*·R' if R ⊆ R' + if (m_re.is_concat(b, b1, b2) && m_re.is_full_seq(b1) && is_subset_rec(a, b2, depth)) + return true; + + // R ⊆ R'·Σ* if R ⊆ R' + if (m_re.is_concat(b, b1, b2) && m_re.is_full_seq(b2) && is_subset_rec(a, b1, depth)) + return true; + + // star absorption: R·R* ⊆ R*, R*·R ⊆ R* + bool const is_concat_star = m_re.is_concat(a, a1, a2) && m_re.is_star(b, b1); + if (is_concat_star && + is_subset_rec(a1, b1, depth + 1) && is_subset_rec(a2, b, depth + 1)) + return true; + if (is_concat_star && + is_subset_rec(a2, b1, depth + 1) && is_subset_rec(a1, b, depth + 1)) + return true; + + // concat monotonicity: + // tail-recursive on second arguments (without increasing depth bound). + if (m_re.is_concat(a, a1, a2) && m_re.is_concat(b, b1, b2) && is_subset_rec(a1, b1, depth + 1)) { + a = a2; + b = b2; + continue; + } + + // complement: ~a ⊆ ~b if b ⊆ a + if (m_re.is_complement(a, a1) && m_re.is_complement(b, b1)) + return is_subset_rec(b1, a1, depth + 1); + + return false; + } +} + +bool seq_subset::is_subset(expr* a, expr* b) const { + return is_subset_rec(a, b, 0); +} diff --git a/src/ast/rewriter/seq_subset.h b/src/ast/rewriter/seq_subset.h new file mode 100644 index 000000000..7329c898e --- /dev/null +++ b/src/ast/rewriter/seq_subset.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 2026 Microsoft Corporation + +Module Name: + + seq_subset.h + +Abstract: + + Heuristic regular-expression subset checks used by seq_rewriter. + +Author: + + Nikolaj Bjorner (nbjorner) 2026-6-8 + +--*/ +#pragma once + +#include "ast/seq_decl_plugin.h" + +class seq_subset { + seq_util::rex& m_re; + static constexpr unsigned m_max_depth = 3; + + bool is_subset_rec(expr* a, expr* b, unsigned depth) const; + +public: + explicit seq_subset(seq_util::rex& re) : m_re(re) {} + bool is_subset(expr* a, expr* b) const; +};