3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-28 03:18:49 +00:00
Commit graph

1510 commits

Author SHA1 Message Date
CEisenhofer
be627007e1 Use lookahead for regex decomposition
Make snode const
2026-06-11 15:34:25 +02:00
CEisenhofer
671dfedebe Merge branch 'master' into c3 2026-06-11 11:04:51 +02:00
Nikolaj Bjorner
384414b10c
Update seq_regex_bisim.h 2026-06-10 15:06:12 -07:00
Nikolaj Bjorner
44a561ec46
Update seq_regex_bisim.cpp 2026-06-10 15:04:24 -07:00
Nikolaj Bjorner
207e6b439a
Update seq_regex_bisim.cpp 2026-06-10 15:03:46 -07: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
2dbefbcd56 Lookahead for regex splits applied to membership constraints
Rewriting constraint/prefix/suffix with constant strings to regexes
2026-06-10 20:35:36 +02:00
CEisenhofer
f9f16550e0 Fixed propagation rule 2026-06-10 17:55:14 +02:00
CEisenhofer
aec52551c3 Remove duplicates from unions/intersections 2026-06-10 15:58:36 +02:00
CEisenhofer
dbb3f70873 Moved the regex splitting into rewriter
Added some simplifications
2026-06-10 15:00:58 +02: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
CEisenhofer
043c6c0ad1 Merge branch 'master' into c3 2026-06-03 17:33:26 +02:00
Nikolaj Bjorner
30df8e7ece build warnings 2026-05-29 10:17:46 -07:00
Nikolaj Bjorner
0b56db7f07 fix #9657 2026-05-28 09:01:48 -07:00
Copilot
34ba2962ef
Fix unsound array equality rewrite for const-array store chains (#9572)
Z3 could return `sat` for an unsatisfiable QF_ABV formula equating two
store chains over distinct constant arrays. The rewrite path for array
equalities was missing a necessary base-value constraint in
finite-domain cases where stores cannot cover all indices.

- **Root cause**
- In `array_rewriter::mk_eq_core`, equality rewriting for nested stores
over const-array bases did not enforce equality of the underlying const
values when the index domain size exceeds the number of updated indices.

- **Rewriter fix**
  - Added a sound rewrite branch for:
    - `store* ((as const ...) v)` vs `store* ((as const ...) w)`
  - When `|domain| > (#stores_lhs + #stores_rhs)`, rewrite now includes:
    - select equalities for touched indices (existing behavior)
    - **and** base-value equality `v = w` (new requirement)
- This prevents spurious models where only updated indices are
constrained.

- **Regression coverage**
- Added a focused regression in `src/test/mod_factor.cpp` that asserts
`unsat` for a minimized constant-array/store-chain BV case with
`(distinct x y)` and one store per side.

```cpp
(assert (distinct x y))
(assert (= (store A0 i0 e0) (store A1 i1 e1)))
(check-sat) ; expected: unsat
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-05-21 11:15:42 -07:00
Nikolaj Bjorner
af33dfaa7d detect quantifiers in patterns
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-05-21 10:37:36 -07:00
CEisenhofer
dd00dd7362 First step towards not-reusing variables 2026-05-20 10:11:50 +02:00
Nikolaj Bjorner
e242257070 avoid disequalities from str.at axioms
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-05-04 16:33:12 -07:00
Nikolaj Bjorner
51cbbe0a0e fix #9293
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-23 17:19:48 -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
352b14fe2b fix and optimize not-contains and regex equalities
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-21 09:16:00 +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
0bcdca787f fix crashes when using replace_all
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-16 22:37:36 +02:00
Nikolaj Bjorner
6d31bdcc21 use sk.mk_seq_eq to avoid disequality propagations
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-29 15:45:54 -07: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
Copilot
ced7952a7b
Implement not_contains_axiom in seq_axioms.cpp (#9098)
* Implement not_contains_axiom in seq_axioms.cpp

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/2df315a7-6f41-4d22-9e77-1e778d97fdb8

* Rewrite not_contains_axiom using recfun recursive function instead of skolem predicate

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/28c9f40f-e66f-41b6-bec0-efff6bc9f902

* Use structural decomposition a = unit(nth(a,0)) ++ tail(a) in not_contains_axiom else-branch

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/e35f6eaa-4c4a-4629-bce2-c6a2a96e2ace

* Refactor tail_s initialization in seq_axioms.cpp

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-22 21:34:45 -07:00
Copilot
ad94dd1b7a
implement replace_all_axiom using recursive predicate ra(s,p,t,r) (#9095)
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/c550da78-28c6-4ab4-9bfb-7403ecc3320b

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-22 18:44:29 -07:00
Nikolaj Bjorner
d1d050f69f not-contains placeholder
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-22 18:40:08 -07:00
Nikolaj Bjorner
00aac9a6a4 replace NYI by exceptions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-22 16:07:48 -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
Nikolaj Bjorner
0f4126f665 add filter for avoiding creating redundant disequality axioms
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-19 23:15:23 -07:00
Copilot
8795bf06fb
theory_nseq: dispatch assign_eh on all seq predicate cases via m_axioms, add enqueue/dequeue_axiom with variant prop_item (#9040)
* dispatch assign_eh cases via m_axioms: add prefix/suffix/contains true axioms

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* fix build: remove stale snode_label_html declaration from seq_nielsen.h

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* theory_nseq: add enqueue/dequeue_axiom + std::variant prop_item + relevant_eh

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>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-19 10:42:18 -07:00
CEisenhofer
109ab7d098 Fixed regex witness 2026-03-19 17:16:29 +01:00
CEisenhofer
149a087f65 Strengthened diseq axiom 2026-03-19 11:14:07 +01:00
Nikolaj Bjorner
a2352529f8 add diseq axiom
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-03-18 12:58:27 -07: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
copilot-swe-agent[bot]
822f19819c Remove unreachable return false in match_ubv2s1
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-03-05 17:59:50 +00:00
copilot-swe-agent[bot]
8e94cad8ab Fix static analysis findings: uninitialized vars, bitwise shift UB, garbage values
- nla_core.cpp: Initialize j = null_lpvar in is_octagon_term
- bit2int.cpp: Initialize sign_p, sign_n, sz_p, sz_n
- act_cache.cpp: Initialize debug vars to nullptr
- enum2bv_rewriter.cpp: Use unsigned literal in 1u << idx
- bit_matrix.cpp: Use unsigned literal in 1u << (n-1)
- bit_util.cpp: Guard against bit_shift == 0 in shl/shr
- mpff.cpp: Cast exp to unsigned before shifting
- sorting_network.h: Guard against bits == 0
- dl_sparse_table.h: Use >= 64 instead of == 64

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-03-02 00:13:55 +00:00
Nikolaj Bjorner
d906a0cc2d fix bug reported by Maria Novoszel
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-02-27 12:02:55 -08:00
Lev Nachmanson
21c23e78db Fix #7507: simplify (>= product_of_consecutive_ints 0) to true
The arith rewriter now recognizes that x * (x + 1) >= 0 for all
integers, since no integer lies strictly between -1 and 0.

Two changes:
1. is_non_negative: detect products where unpaired factors are
   consecutive integer expressions (differ by exactly 1), handling
   both +1 and -1 offsets and n-ary additions
2. is_separated: return true for (>= non_negative_mul 0), restricted
   to multiplication expressions to avoid disrupting other theories

Also adds regression tests for the new simplification.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-27 06:37:07 -10:00
Nikolaj Bjorner
776976cbd1 fix #8572
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-02-18 21:02:20 -08:00
Nuno Lopes
a3e7bbb92f replace some copies with moves 2026-02-18 21:02:17 -08:00