CEisenhofer
706f62286e
Merge remote-tracking branch 'origin/master' into c3
2026-07-01 17:18:21 +02:00
Nikolaj Bjorner
15f33f458d
Derive with ranges ( #9965 )
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Margus Veanes <margus@microsoft.com>
Co-authored-by: Margus Veanes <veanes@users.noreply.github.com>
2026-06-26 08:44:13 -06:00
Nikolaj Bjorner
f034616950
Revert "Derive with ranges" ( #9964 )
...
Reverts Z3Prover/z3#9963
2026-06-25 19:57:30 -06:00
Nikolaj Bjorner
22c2635786
Derive with ranges ( #9963 )
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Margus Veanes <margus@microsoft.com>
Co-authored-by: Margus Veanes <veanes@users.noreply.github.com>
2026-06-25 19:47:25 -06:00
Nikolaj Bjorner
cb3fe3167f
rewrite replace_all constraints
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-23 10:45:28 -07:00
Nikolaj Bjorner
cb3d058067
fix build warnings
2026-06-22 18:20:23 -07:00
Nikolaj Bjorner
bcdb43451d
fix range rewrite again, again
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-22 11:02:18 -07:00
Nikolaj Bjorner
f487af3071
use empty sequence regex instead of empty set regex
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-21 16:26:05 -07:00
Nikolaj Bjorner
871b98169f
fix rewriting of complemnt of ranges
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-20 11:08:00 -07:00
Nikolaj Bjorner
bcc3523b23
Update seq_rewriter.cpp
2026-06-16 14:14:49 -06:00
Copilot
8c2a425e4b
Smart constructors for regex ranges: canonical form at construction time ( #9814 )
...
Regex range expressions (`re.range`) and Boolean operations over them
were left in unsimplified form, defeating downstream optimisations
(bisimulation classical fast-path, derivative engine) and producing
semantically-empty terms not syntactically equal to `re.none`.
## Changes
### `seq_decl_plugin.h` / `seq_decl_plugin.cpp`
- **`seq_util::rex::mk_range(sort*, unsigned lo, unsigned hi)`** — new
smart constructor that normalises at call time:
- `lo > hi` → `re.empty`
- `lo == hi` → `str.to_re` (singleton string)
- `lo < hi` → `re.range`
- **`mk_info_rec` `OP_RE_RANGE`** — concrete non-empty ranges (both
bounds are single-char literals with `lo ≤ hi`) now return `classical =
true`, enabling the XOR-bisimulation `classical_distinguishing`
fast-path on character-predicate leaves. Symbolic/unknown ranges retain
`classical = false`.
### `seq_rewriter.cpp`
- **`mk_re_range`** — singleton collapse: `(re.range "a" "a")` →
`(str.to_re "a")`
- **`mk_regex_inter_normalize`** — range × range intersection: `[a,b] ∩
[c,d]` → `[max(a,c), min(b,d)]`, or `re.none` (disjoint), or `str.to_re`
(boundary singleton); now delegates to `re().mk_range(sort*, lo, hi)`
- **`mk_regex_union_normalize`** — range × range union for
overlapping/adjacent ranges: `[a,b] ∪ [c,d]` → `[min(a,c), max(b,d)]`;
disjoint ranges fall through to existing `merge_regex_sets`; now
delegates to `re().mk_range(sort*, lo, hi)`
- **`mk_re_complement`** — range complement expands to one or two
concrete ranges instead of an opaque `re.comp` node; now delegates to
`re().mk_range(sort*, lo, hi)`:
- `comp([0, b])` → `[b+1, max]`
- `comp([a, max])` → `[0, a-1]`
- `comp([a, b])` → `[0, a-1] ∪ [b+1, max]`
```
(simplify (re.range "z" "a")) ; → re.none
(simplify (re.range "a" "a")) ; → (str.to_re "a")
(simplify (re.inter (re.range "a" "z") (re.range "f" "k"))); → (re.range "f" "k")
(simplify (re.union (re.range "a" "f") (re.range "g" "k"))); → (re.range "a" "k")
(simplify (re.comp (re.range "b" "y"))) ; → (re.union [0,a] [z,max])
```
### Tests
New `src/test/seq_rewriter.cpp` with 14 cases covering all the above
reductions plus downstream propagation (star/concat/union/inter
absorbing empty ranges).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-16 13:58:56 -06:00
Nikolaj Bjorner
a8271648bd
disable xor detection
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-14 15:25:17 -07:00
Nikolaj Bjorner
3a390dda18
add membership elimination to legacy elim_uncnstr pre-processor. Detect xor encodings
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-14 15:05:34 -07:00
CEisenhofer
671dfedebe
Merge branch 'master' into c3
2026-06-11 11:04:51 +02:00
Margus Veanes
513b81253b
Add OP_RE_XOR and union-find bisimulation for ground regex equivalence ( #9804 )
...
Implements the algorithm of Eq(p,q) = Empty(p XOR q)' using a union-find
driven bisimulation closure (per the CAV'26 ERE paper).
### What's added
* **New primitive OP_RE_XOR (re.xor)** wired through seq_decl_plugin:
parser signature, info propagation (nullable, min_length), and
pretty-printer.
* **seq_rewriter**: structural XOR rewrites ( XOR r = empty, XOR empty =
r, ull XOR r = comp(r), comp/comp absorption, complement push, AC
normalisation), nullability (Null(p XOR q) = Null(p) != Null(q)),
derivative (D_a(p XOR q) = D_a(p) XOR D_a(q)), reverse, antimirov
derivative, and `check_deriv_normal_form` coverage.
* **New class seq::regex_bisim** in
`src/ast/rewriter/seq_regex_bisim.{h,cpp}` to keep the bisim logic out
of the already-large `seq_rewriter.cpp`. Uses `basic_union_find` from
`util/union_find.h`, an `obj_map` for the node assignment, and a
50000-step bound (returns `l_undef` on overrun).
* **Integration** in `seq_rewriter::reduce_re_eq` (with a re-entry
guard) and in `seq_regex::propagate_eq` / `propagate_ne` for ground
regexes; on `l_undef` we fall back to the existing axiomatisation.
* **`sls_seq_plugin`**: extend `OP_RE_DIFF` switch arms to also cover
`OP_RE_XOR`.
### Validation
* Full release build with MSVC + Ninja.
* `./test-z3 /a` -- 89/89 tests passing.
* `./test-z3 /seq smt2print_parse` -- PASS.
* Smoke tests with `(a|b)*` vs `(a*b*)*` (equal) and `a*` vs `(a|b)*`
(not equal) return the expected `sat`/`unsat` quickly.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-10 14:58:20 -07:00
CEisenhofer
e3b80fc578
Merge branch 'master' into c3
2026-06-10 13:41:31 +02:00
Copilot
e093be8b60
seq_rewriter: add missing concat rewrites for nullable/full-seq/star cases ( #9782 )
...
`seq_rewriter.cpp` was missing several regex-concat normalizations
around `re.all` (`Σ*`), causing avoidable growth and missed
simplifications. This update fills the four gaps: nullable absorption,
guarded union distribution, intersection suffix elimination, and
nested-star collapse.
- **Nullable/full-seq absorption (A1)**
- Generalizes `Σ*·R → Σ*` and `R·Σ* → Σ*` beyond `Σ*·Σ*`.
- Applies when `R` is interpreted, nullable, and has `min_length = 0`.
- **Guarded distribution over union (A2)**
- Adds `Σ*·(R1 ∪ R2)` distribution when at least one arm is already
`Σ*`-headed.
- Rebuilds via normalized union so the redundant arm collapses to `Σ*`.
- **Intersection + full-seq tail elimination (A3)**
- Adds `(R1 ∩ … ∩ Rn)·Σ* → (R1 ∩ … ∩ Rn)` when every intersection leaf
already ends in `Σ*`.
- **Nested star concat collapse (A4)**
- Adds `R*·(R*·X) → R*·X`, covering non-adjacent star patterns not
handled by the prior adjacent-only rewrite.
```cpp
if (re().is_full_seq(a) && accepts_empty_word(b)) result = a; // A1
if (re().is_full_seq(a) && re().is_union(b, u1, u2) && ...) ... // A2
if (re().is_intersection(a, u1, u2) && re().is_full_seq(b) && ...) result=a; // A3
if (re().is_star(a, a1) && re().is_concat(b, b1, b2) && re().is_star(b1,b3) && a1==b3) result=b; // A4
```
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-09 14:38:38 -07:00
Copilot
f0956a622f
Refactor regex subset logic into seq_subset with depth-bounded recursion and optimized concat traversal ( #9777 )
...
`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 <nbjorner@microsoft.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-09 13:42:28 -07:00
Nikolaj Bjorner
8cc85a7d7b
code simplification, fix conflict in new_diseq_eh
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-21 10:17:43 +02:00
Nikolaj Bjorner
e172aa370d
add simplification rule to concatentations of regex to avoid stack overflow in derivatives of very long expressions
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-20 18:20:43 +02:00
Nikolaj Bjorner
6a6f9b1892
Merge remote-tracking branch 'origin/master' into c3
...
# Conflicts:
# .github/workflows/qf-s-benchmark.lock.yml
# .github/workflows/qf-s-benchmark.md
# .github/workflows/zipt-code-reviewer.lock.yml
# .github/workflows/zipt-code-reviewer.md
# .gitignore
# src/ast/rewriter/seq_rewriter.cpp
# src/test/main.cpp
2026-03-24 17:44:48 -07:00
Nikolaj Bjorner
bc5818e12d
fix bogus decompose_ite
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-24 14:43:56 -07:00
Nikolaj Bjorner
a5c0ecafda
fixes to model generation
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-24 13:27:28 -07:00
Nikolaj Bjorner
5803c6f202
fix bug in non-emptiness witness extraction
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-24 13:27:28 -07:00
Nikolaj Bjorner
dbdccbff97
use recursive function for not-contains
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-23 13:18:34 -07:00
CEisenhofer
88ef8c7cda
Another regex witness bug
2026-03-20 14:07:12 +01:00
Nikolaj Bjorner
1137d23725
fix bug reported in API coherence report
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-19 23:20:55 -07:00
CEisenhofer
109ab7d098
Fixed regex witness
2026-03-19 17:16:29 +01:00
Nikolaj Bjorner
32eedde897
disable rewrite that makes nseq solving harder
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-15 21:36:22 -07:00
Copilot
2212f59704
seq_model: address NSB review comments ( #8995 )
...
* Initial plan
* Address NSB review comments in seq_model.cpp
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Address code review feedback: improve null-sort handling in seq_model and some_seq_in_re
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-03-14 21:55:32 -07:00
Nikolaj Bjorner
ffd9207bc5
fix #8572
...
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-02-10 20:22:27 -08:00
Copilot
c4f75bc85a
Refactor seq_rewriter to use C++17 structured bindings ( #8381 )
...
* Initial plan
* Refactor seq_rewriter.cpp to use C++17 structured bindings
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Address code review feedback - move pair declaration inside loop
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-27 12:06:11 -08:00
Copilot
2436943794
Standardize for-loop increments to prefix form (++i) ( #8199 )
...
* Initial plan
* Convert postfix to prefix increment in for loops
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Fix member variable increment conversion bug
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Update API generator to produce prefix increments
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-14 19:55:31 -08:00
Lev Nachmanson
641741f3a8
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 10:30:58 -07:00
Lev Nachmanson
8af9a20e01
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 10:26:40 -07:00
Lev Nachmanson
6a9520bdc2
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 10:21:09 -07:00
Lev Nachmanson
8ccf4cd8f7
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 10:19:24 -07:00
Lev Nachmanson
40b980079b
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 10:14:02 -07:00
Lev Nachmanson
a41549eee6
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 10:06:43 -07:00
Lev Nachmanson
2b3068d85f
parameter eval order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-07 09:17:12 -07:00
Lev Nachmanson
3a2bbf4802
param eval order
2025-10-07 09:13:21 -07:00
Lev Nachmanson
6e52b9584c
param eval
2025-10-07 09:04:24 -07:00
Lev Nachmanson
93ff8c76db
parameter evaluation order
2025-10-07 08:53:49 -07:00
Lev Nachmanson
00f1e6af7e
parameter eval order
2025-10-07 08:40:24 -07:00
Lev Nachmanson
c154b9df90
param order evaluation
2025-10-07 08:34:56 -07:00
Lev Nachmanson
77c70bf812
param order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-06 15:52:09 -07:00
Lev Nachmanson
63bb367a10
param order
...
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-10-06 15:52:09 -07:00
Nikolaj Bjorner
6df8b39718
Update seq_rewriter.cpp
2025-08-14 14:40:26 -07:00
Nikolaj Bjorner
fcd3a70c92
remove theory_str and classes that are only used by it
2025-08-07 21:05:12 -07:00
Nikolaj Bjorner
1f8b08108c
#7739 optimization
...
add simplification rule for at(x, offset) = ""
Introducing j just postpones some rewrites that prevent useful simplifications. Z3 already uses common sub-expressions.
The example highlights some opportunities for simplification, noteworthy at(..) = "".
The example is solved in both versions after adding this simplification.
2025-07-26 14:02:34 -07:00