3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-25 16:32:35 +00:00
Commit graph

18634 commits

Author SHA1 Message Date
Nikolaj Bjorner
bcc3523b23
Update seq_rewriter.cpp 2026-06-16 14:14:49 -06:00
Nikolaj Bjorner
1d9c770d74
Fix reference to recfun::util in lia2card_tactic.cpp 2026-06-16 14:02:24 -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
Copilot
897c4475af
goal2sat: drop unsafe ref_count≤1 cache-skip optimization; keep bit_blaster mk_eq improvement (#9882)
PR #9872 caused timeouts in QF_UFBV, QF_BV, and QF_FP regressions
(`t135`, `t136`, `nl53`, `3397`, `4841-1`, `fp-lt-gt`, `fp-rem-11`).

## Root cause

The `goal2sat` change skipped caching AST nodes with `ref_count ≤ 1`
under the assumption they're visited only once. This assumption is
wrong: EUF, BV, and FP theory extensions all call `internalize()` from
the theory solver side, outside the main DFS traversal. On the second
`internalize(n)` call, the missing cache entry causes the entire subtree
to be re-encoded with a fresh literal — inconsistent encoding and
exponential blowup.

## Changes

- **`goal2sat.cpp`**: revert the `ref_count ≤ 1` skip-caching
optimization entirely; it is unsafe whenever any theory extension is
active.
- **`bit_blaster_tpl_def.h`**: retain the `mk_eq` micro-optimization
from #9872 — pre-size with `resize(sz)` and use index assignment instead
of `push_back`. This is correct: `resize` null-initializes slots and
`element_ref::operator=` handles ref-counting via `inc_ref`/`dec_ref`.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-16 12:09:20 -06:00
Peter Chen J.
ec7462024a
Strengthen historical nlsat regression tests (#9857)
This tightens two historical `nlsat` regressions that were still
print-only.

Closes #9859.

In `tst_16`, the test already exercises the old `lws2380` shape, but it
only dumped the projected clause. On current `master`, both projection
paths still keep the `x7`-linked root constraints, so this change turns
that observation into an assertion and updates the stale comment to
describe the current invariant.

In `tst_22`, the test already computes whether the projected lemma is
falsified at the stored counterexample. It previously printed the result
and kept going. This change adds `ENSURE(!all_false)` so the test fails
if that historical unsoundness shape comes back.

Testing:
`cmake --build . --target test-z3 -j1`
`./test-z3 /seq nlsat`
2026-06-16 11:36:13 -06:00
dependabot[bot]
d457f9f5d3
Bump markdown-it from 14.1.0 to 14.2.0 in /src/api/js (#9881)
Bumps [markdown-it](https://github.com/markdown-it/markdown-it) from
14.1.0 to 14.2.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/markdown-it/markdown-it/blob/master/CHANGELOG.md">markdown-it's
changelog</a>.</em></p>
<blockquote>
<h2>[14.2.0] - 2026-05-24</h2>
<h3>Added</h3>
<ul>
<li><code>isPunctCharCode</code> to utilities.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Don't end HTML comment blocks on a blank line, <a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1155">#1155</a>.</li>
<li>Properly recognize astral chars (surrogates) in delimiter scans for
emphasis-like markers, <a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1072">#1072</a>.
Big thanks to <a
href="https://github.com/tats-u"><code>@​tats-u</code></a> for his
global efforts
with improving CJK support.</li>
<li>Preserve unicode whitespaces when trimm headings/paragraphs, <a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1074">#1074</a>.</li>
<li>More strict entities decode to avoid false positives <code>;</code>,
<a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1096">#1096</a>.</li>
<li>Restore block parser state on fail in <code>lheading</code> rule, <a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1131">#1131</a>.</li>
</ul>
<h3>Security</h3>
<ul>
<li>Fixed poor smartquotes perfomance on &gt; 70k quotes in single
block</li>
<li>Bumped linkify-it to 5.0.1 with fixed potential perfomance
issues.</li>
</ul>
<h2>[14.1.1] - 2026-01-11</h2>
<h3>Security</h3>
<ul>
<li>Fixed regression from v13 in linkify inline rule. Specific patterns
could
cause high CPU use. Thanks to <a
href="https://github.com/ltduc147"><code>@​ltduc147</code></a> for
report.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="829797aa00"><code>829797a</code></a>
14.2.0 released</li>
<li><a
href="9ce2087562"><code>9ce2087</code></a>
Fix smartquotes perfomance</li>
<li><a
href="02e73b88fd"><code>02e73b8</code></a>
linkify-it bump</li>
<li><a
href="68cfb8c079"><code>68cfb8c</code></a>
fix: don't end HTML comment blocks on a blank line (<a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1155">#1155</a>)</li>
<li><a
href="108313756c"><code>1083137</code></a>
Readme cleanup</li>
<li><a
href="97c7ca2571"><code>97c7ca2</code></a>
Update funding info</li>
<li><a
href="c471b55c10"><code>c471b55</code></a>
Changelog update</li>
<li><a
href="77696210d1"><code>7769621</code></a>
isPunctChar =&gt; isPunctCharCode</li>
<li><a
href="aa2aa70b30"><code>aa2aa70</code></a>
fix: always reset parentType in lheading rule (<a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1131">#1131</a>)</li>
<li><a
href="59955f2ad3"><code>59955f2</code></a>
Polish PRs <a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1072">#1072</a>,
<a
href="https://redirect.github.com/markdown-it/markdown-it/issues/1074">#1074</a></li>
<li>Additional commits viewable in <a
href="https://github.com/markdown-it/markdown-it/compare/14.1.0...14.2.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=markdown-it&package-manager=npm_and_yarn&previous-version=14.1.0&new-version=14.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/Z3Prover/z3/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-16 11:34:20 -06:00
Nikolaj Bjorner
0270817b31 block lia2card on recursive functions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-16 11:25:14 -06:00
Copilot
b6c7ef2f68
dotnet: force PlatformTarget=AnyCPU to fix arm64 host load failure (#9868)
`Microsoft.Z3.dll` was being emitted with PE `Machine=0x8664` (AMD64)
despite being pure IL, because the Windows x64 CI environment
(`vcvarsall.bat x64`) injects `Platform=x64` into MSBuild, which sets
the COFF machine type when `PlatformTarget` is not explicitly specified.
This causes `FS0193` / architecture mismatch errors on any arm64 .NET
host (macOS Apple Silicon, Linux aarch64, Windows on ARM).

## Changes

- **`scripts/mk_util.py`** — Add
`<PlatformTarget>AnyCPU</PlatformTarget>` to the in-memory `.csproj`
template generated by the Python build system (`mk_win_dist.py`,
`mk_unix_dist.py`)
- **`src/api/dotnet/Microsoft.Z3.csproj.in`** — Add
`<PlatformTarget>AnyCPU</PlatformTarget>` to the CMake build system
template

Both paths now produce `Machine=0x014C` (i386/AnyCPU) regardless of host
or CI environment, matching the assembly's actual nature (`ILONLY=True`,
`32BIT_REQUIRED=False`). The native side already ships six RIDs; no
changes needed there.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-16 09:52:04 -06:00
Nuno Lopes
ff2e0a3ab0
Remove a few unneeded constructors (#9879) 2026-06-16 14:55:59 +01:00
davedets
86de0cbd71
Eliminate unused private fields and local variables. (#9875)
This is another PR towards the goal of getting a clean build with clang,
using the compiler options used in building clang-tidy.

By default, without any new -W flags, clang warns about unused local
variables and private class fields. This PR deletes the handful of these
that clang found.

I'm assuming that the class "enode" in smt_context.cpp is the one in
smt_enode.h, so that
```
parent->get_expr()
```
calls a const method with no side effects.
2026-06-16 14:55:18 +01:00
Margus Veanes
c67bb140dc
Treat each transition-regex leaf as a single bisimulation state (#9871)
## Summary

egex_bisim::collect_leaves used to descend through `re.union` and
`re.antimirov_union` at the top of each leaf of the transition regex,
splitting a single bisimulation state into multiple states before they
were merged into the union-find. This contradicts the bisimulation
invariant: **each leaf of a t-regex represents one state, regardless of
its top-level shape**. The fix descends into `ite` only (which is the
actual structural splitter of guarded transitions).

## Why it matters

The split happens to be *sound* for the current algorithm when the goal
is asserting `L(union(A, B)) = empty` (since `L(A) = empty AND L(B) =
empty` is equivalent), but it:

1. Adds spurious merges to the union-find that distort state-class
identities.
2. Slows convergence on hard equivalence queries (and causes early
timeouts in practice).
3. Creates latent unsoundness risk for any extension that interprets
leaves more semantically (XOR pair handling, classical-flag propagation,
future antimirov re-enable, etc.).

## Empirical validation

Run on the 1523-file regex-equivalence corpus, 5s/file timeout, 8
workers:

| metric | pre-fix master | post-fix |
|---|---|---|
| sat | 1008 | 1014 |
| unsat | 368 | 368 |
| timeout | 145 | 139 |
| unknown | 2 | 2 |
| SAT&harr;UNSAT verdict flips | &mdash; | **0** |
| timeout&rarr;sat flips | &mdash; | 6 |
| commonly-solved wall ratio | 1.000x | **0.902x** |

The 6 `timeout` &rarr; `sat` cases all return the *same* `sat` under
pre-fix master if given 60s; they are previously-slow cases not
previously-wrong ones.

Z3 unit tests: 89/89 pass (`test-z3 /a`).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-15 10:59:41 -07:00
Lev Nachmanson
f508854fe5
Lcube (#9858)
Implemented the largest cube heuristic from Bromberger and Weidenbach's
paper on cubes. Also fixes an overflow bug in mzp.
Use vswhere to find the visual studio version on windows in the build's ymls.
---------

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-14 16:25:21 -07:00
Nikolaj Bjorner
4bf4fbd48c revert updates
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-06-14 15:57:23 -07: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
1feb610daa Probably quite instable, but included the splitting into the legacy solver 2026-06-12 17:05:38 +02:00
CEisenhofer
871a2b3bc8 Porting seq_split to master 2026-06-12 15:18:14 +02:00
Copilot
054d71455d
Fix Homebrew/macOS build break by defining obj_map::key_data constructors (#9815)
Homebrew upgrade from Z3 4.15.4 to 4.16.0 failed on macOS 12 during
`src/ast/ast.cpp` compilation because `obj_map::key_data` was used with
`(key, value)` construction but only implicit constructors existed. This
surfaced at `m_poly_roots.insert(new_node, new_node)` and similar map
operations.

- **Root cause addressed**
- `obj_map<Key, Value>::key_data` relied on implicit constructors, which
are insufficient under stricter toolchains when `key_data(k, v)` /
`key_data(k)` are instantiated via `obj_map` helpers.

- **Code change (minimal, targeted)**
- Added explicit struct constructors in `src/util/obj_hashtable.h` for:
    - default initialization
    - key-only construction (`key_data(Key* k)`)
    - key + lvalue value (`key_data(Key* k, Value const& v)`)
    - key + rvalue value (`key_data(Key* k, Value&& v)`)
- No behavioral changes to map semantics; this only makes existing call
sites well-formed across compilers.

- **Example of the change**
  ```c++
  struct key_data {
      Key * m_key = nullptr;
      Value m_value;
      key_data() = default;
      key_data(Key* k): m_key(k) {}
      key_data(Key* k, Value const& v): m_key(k), m_value(v) {}
      key_data(Key* k, Value&& v): m_key(k), m_value(std::move(v)) {}
      // ...
  };
  ```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-11 23:09:07 -07:00
CEisenhofer
f126b60369 Giving up is still no conflict 2026-06-11 16:27:59 +02:00
CEisenhofer
b9d5f273ee Removed logging 2026-06-11 16:14:07 +02:00
CEisenhofer
fd8100475c Eliminate top-level nonsense cases from regex decomposition 2026-06-11 16:01:08 +02:00
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
Eric Astor
677abb589e
Add rlimit support in fixedpoint parameters (#9798)
The C++ implementation of the fixedpoint engine (in
z3/src/api/api_datalog.cpp) already attempts to read `rlimit` from its
local parameters:

```c++
unsigned rlimit = to_fixedpoint(d)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit());
```

However, because `rlimit` was not registered in the public fp parameter
schema (`fp_params.pyg`), any attempt by clients to set it locally via
`Z3_fixedpoint_set_params` was rejected by the Z3 parameter validator
with an "unknown parameter" error.
2026-06-10 15:13:05 -07: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
dependabot[bot]
589bd9e6f5
Bump shell-quote from 1.7.3 to 1.8.4 in /src/api/js (#9803)
Bumps [shell-quote](https://github.com/ljharb/shell-quote) from 1.7.3 to
1.8.4.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ljharb/shell-quote/blob/main/CHANGELOG.md">shell-quote's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/ljharb/shell-quote/compare/v1.8.3...v1.8.4">v1.8.4</a>
- 2026-05-22</h2>
<h3>Commits</h3>
<ul>
<li>[Fix] <code>quote</code>: validate object-token shapes <a
href="4378a6e613"><code>4378a6e</code></a></li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code>,
<code>auto-changelog</code>, <code>eslint</code>, <code>npmignore</code>
<a
href="22ebec0434"><code>22ebec0</code></a></li>
<li>[Tests] increase coverage <a
href="9f3caa3190"><code>9f3caa3</code></a></li>
<li>[readme] replace runkit CI badge with shields.io check-runs badge <a
href="3344a047dd"><code>3344a04</code></a></li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code> <a
href="699c5113d1"><code>699c511</code></a></li>
</ul>
<h2><a
href="https://github.com/ljharb/shell-quote/compare/v1.8.2...v1.8.3">v1.8.3</a>
- 2025-06-01</h2>
<h3>Fixed</h3>
<ul>
<li>[Fix] remove unnecessary backslash escaping in single quotes <a
href="https://redirect.github.com/ljharb/shell-quote/issues/15"><code>[#15](https://github.com/ljharb/shell-quote/issues/15)</code></a></li>
</ul>
<h2><a
href="https://github.com/ljharb/shell-quote/compare/v1.8.1...v1.8.2">v1.8.2</a>
- 2024-11-27</h2>
<h3>Fixed</h3>
<ul>
<li>[Fix] <code>quote</code>: preserve empty strings <a
href="https://redirect.github.com/ljharb/shell-quote/issues/18"><code>[#18](https://github.com/ljharb/shell-quote/issues/18)</code></a></li>
</ul>
<h3>Commits</h3>
<ul>
<li>[meta] fix changelog tags <a
href="0fb9fd8441"><code>0fb9fd8</code></a></li>
<li>[actions] split out node 10-20, and 20+ <a
href="819bd842e0"><code>819bd84</code></a></li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code>,
<code>auto-changelog</code>, <code>npmignore</code>, <code>tape</code>
<a
href="fc564086c8"><code>fc56408</code></a></li>
<li>[actions] update npm for windows tests <a
href="fdeb0fd102"><code>fdeb0fd</code></a></li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code>,
<code>aud</code>, <code>tape</code> <a
href="b8a4a3b3f5"><code>b8a4a3b</code></a></li>
<li>[actions] prevent node 14 on ARM mac from failing <a
href="9eecafc048"><code>9eecafc</code></a></li>
<li>[meta] exclude more files from the package <a
href="4044e7fad4"><code>4044e7f</code></a></li>
<li>[Tests] replace <code>aud</code> with <code>npm audit</code> <a
href="8cfdbd8ec3"><code>8cfdbd8</code></a></li>
<li>[meta] add missing <code>engines.node</code> <a
href="843820e1a4"><code>843820e</code></a></li>
<li>[Dev Deps] add missing peer dep <a
href="4c3b88d792"><code>4c3b88d</code></a></li>
<li>[Dev Deps] pin <code>jackspeak</code> since 2.1.2+ depends on npm
aliases, which kill the install process in npm &lt; 6 <a
href="80322ed591"><code>80322ed</code></a></li>
</ul>
<h2><a
href="https://github.com/ljharb/shell-quote/compare/v1.8.0...v1.8.1">v1.8.1</a>
- 2023-04-07</h2>
<h3>Fixed</h3>
<ul>
<li>[Fix] <code>parse</code>: preserve whitespace in comments <a
href="https://redirect.github.com/ljharb/shell-quote/issues/6"><code>[#6](https://github.com/ljharb/shell-quote/issues/6)</code></a></li>
<li>[Fix] properly support the <code>escape</code> option <a
href="https://redirect.github.com/ljharb/shell-quote/issues/5"><code>[#5](https://github.com/ljharb/shell-quote/issues/5)</code></a></li>
</ul>
<h3>Commits</h3>
<ul>
<li>[Refactor] <code>parse</code>: hoist <code>getVar</code> to module
level <a
href="b42ac73e39"><code>b42ac73</code></a></li>
<li>[Refactor] hoist some vars to module level <a
href="8f0c5c3c9d"><code>8f0c5c3</code></a></li>
<li>[Refactor] <code>parse</code>: use <code>slice</code> over
<code>substr</code>, cache some values <a
href="fcb2e1acd5"><code>fcb2e1a</code></a></li>
<li>[Refactor] <code>parse</code>: a bit of cleanup <a
href="6780ec5194"><code>6780ec5</code></a></li>
<li>[Refactor] <code>parse</code>: tweak the regex to not match nothing
<a
href="227d4742a0"><code>227d474</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ff166e2b63"><code>ff166e2</code></a>
v1.8.4</li>
<li><a
href="4378a6e613"><code>4378a6e</code></a>
[Fix] <code>quote</code>: validate object-token shapes</li>
<li><a
href="22ebec0434"><code>22ebec0</code></a>
[Dev Deps] update <code>@ljharb/eslint-config</code>,
<code>auto-changelog</code>, <code>eslint</code>, `npmig...</li>
<li><a
href="9f3caa3190"><code>9f3caa3</code></a>
[Tests] increase coverage</li>
<li><a
href="3344a047dd"><code>3344a04</code></a>
[readme] replace runkit CI badge with shields.io check-runs badge</li>
<li><a
href="699c5113d1"><code>699c511</code></a>
[Dev Deps] update <code>@ljharb/eslint-config</code></li>
<li><a
href="487a9b41a7"><code>487a9b4</code></a>
v1.8.3</li>
<li><a
href="01faafff97"><code>01faaff</code></a>
[Fix] remove unnecessary backslash escaping in single quotes</li>
<li><a
href="b19fc77e66"><code>b19fc77</code></a>
v1.8.2</li>
<li><a
href="59d29ea694"><code>59d29ea</code></a>
[Fix] <code>quote</code>: preserve empty strings</li>
<li>Additional commits viewable in <a
href="https://github.com/ljharb/shell-quote/compare/v1.7.3...v1.8.4">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~ljharb">ljharb</a>, a new releaser for
shell-quote since your current version.</p>
</details>
<details>
<summary>Install script changes</summary>
<p>This version adds <code>prepublish</code> script that runs during
installation. Review the package contents before updating.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=shell-quote&package-manager=npm_and_yarn&previous-version=1.7.3&new-version=1.8.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/Z3Prover/z3/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-10 08:40:36 -07:00
CEisenhofer
aec52551c3 Remove duplicates from unions/intersections 2026-06-10 15:58:36 +02:00
Lev Nachmanson
1b2ca1a1bf
Fix off-by-one column after comment lines in SMT2 scanner (#9808)
This bug was discovered by claude analyzing the descrepency of outputs
in https://github.com/Z3Prover/bench/discussions/2516. The benchmark was
edited - a line required stats was commented out - and this exposed the
scanner inconsistent behavior.
read_comment and read_multiline_comment handled end-of-line newlines as
new_line(); next();, the reverse of the main scan() loop's next();
new_line();. This left m_spos one higher on the line following a
comment, shifting every reported column on that line by +1 (e.g. a (pop)
error reported column 5 instead of 4 when the previous line was a
comment). Reorder both comment readers to match scan() so column numbers
are consistent regardless of whether the preceding line is a comment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-10 06:49:31 -07:00
CEisenhofer
dbb3f70873 Moved the regex splitting into rewriter
Added some simplifications
2026-06-10 15:00:58 +02:00
Copilot
03a76c0309
euf_sgraph: make drop_left/drop_right depth-linear and simplify string classification (#9771)
ZIPT review identified two hot-path inefficiencies in `euf_sgraph`:
`drop_left`/`drop_right` were implemented as repeated single-token drops
(`O(count × depth)`), and `classify` performed redundant string checks.
This change aligns behavior with the intended tree-navigation approach
while keeping semantics unchanged.

- **Algorithmic update: `drop_left` / `drop_right`**
- Replaced iterative `drop_first`/`drop_last` loops with direct
recursion over concat children.
- New logic drops across subtree boundaries using child lengths,
reducing work to tree depth (`O(depth)`).

- **Classification cleanup: `classify`**
- Collapsed double `is_string` probing into a single `is_string(e, s)`
call.
- Preserves existing kind mapping (`empty` vs non-empty string constant
handling).

- **Focused test coverage extension**
- Added boundary checks in `test_sgraph_drop` for `drop_left(..., 1)`
and `drop_right(..., 1)` on a 4-token concat tree.

```cpp
snode* sgraph::drop_left(snode* n, unsigned count) {
    if (count == 0 || n->is_empty()) return n;
    if (count >= n->length()) return mk_empty_seq(n->get_sort());
    SASSERT(n->is_concat());
    unsigned left_len = n->arg(0)->length();
    if (count < left_len)
        return mk_concat(drop_left(n->arg(0), count), n->arg(1));
    return drop_left(n->arg(1), count - left_len);
}
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-10 14:46:03 +02:00
CEisenhofer
294ee984b8 Remove cyclic dependency 2026-06-10 13:56: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
d415ead6a2
Port is_classical attribute to seq_util::rex::info (#9796)
`is_classical` (tracks whether a regex uses only classical operators —
no complement, intersection, diff, or empty-language/fail) was only
available on `euf::snode`. Moving it into `seq_util::rex::info` makes it
accessible to all regex-handling code without going through the snode
layer.

### Changes

**`seq_decl_plugin.h`**
- Added `bool classical { true }` to `seq_util::rex::info`
- The general `info` constructor requires `bool is_classical` explicitly
(no default)

**`seq_decl_plugin.cpp`**
- `mk_info_rec`: `OP_RE_EMPTY_SET` (fail) sets `classical=false`
- `mk_info_rec`: `OP_RE_RANGE`, `OP_RE_FULL_CHAR_SET`, `OP_RE_OF_PRED`
set `classical=false`
- `complement()`, `conj()` (intersection), `diff()`: always produce
`classical=false`
- `star()`, `plus()`, `opt()`, `concat()`, `disj()`, `orelse()`,
`loop()`: propagate `classical` via logical AND over operands
- `operator=` and `display()` updated to include `classical`

### Semantics

| Operation | `classical` |
|-----------|-------------|
| `re.empty` (fail) | `false` |
| `re.range`, `re.allchar`, `re.of.pred` | `false` |
| `re.comp` (complement) | `false` |
| `re.inter` (intersection) | `false` |
| `re.diff` | `false` |
| `re.all` (full sequence set) | `true` |
| `str.to.re` (string literal) | `true` |
| `re.*`, `re.+`, `re.opt`, `re.++`, `re.union`, `re.loop` | inherited
from operands |

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-09 14:35:48 -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
Lev Nachmanson
6eeb274cd2
Fix FPA incremental soundness for fp.to_* terms (#9022) (#9787)
Fixes #9022.

## Problem

After a `(push)`, Z3 could incorrectly report `unsat` for satisfiable
FPA formulas in which an uninterpreted function returns a floating-point
value (e.g. `int_to_fp`). The example in #9022 has a single `push` and a
single `check-sat` (no `pop`), so the `m_rw.reset()` added in
`pop_scope_eh` by #8712 does not apply.

## Root cause

`theory_fpa` lazily converts FP constraints to bit-vectors and asserts
the equivalences/side conditions as **unit theory axioms**
(`assert_cnstr` → `mk_th_axiom`, which `assign`s the literal at the
current decision level).

For `fp.to_*` terms (`fp.to_real`, `fp.to_ubv`, …) the conversion
equality and side conditions are emitted **only** in
`internalize_term()`, which runs exactly once. The `else if` branch for
fpa-family conversion terms in `relevant_eh` previously did nothing.

These unit axioms are level-local: on DPLL backtracking the assignment
is undone, but `internalize_term()` is not re-run for the
already-internalized term (in particular when the term lives at the
user-`push` base level, where its clause is not a reinit clause). The
side conditions include the axioms linking FP uninterpreted functions to
their bit-vector counterparts (`int_to_fp(i) =
fp(extract(int_to_fp_bv(i)))`). Once lost, `int_to_fp_bv` becomes
unconstrained, enabling an unsound `unsat`. This is exactly the behavior
described in #8345/#9022 (and why the result flips with vs. without
`push`).

## Fix

`relevant_eh` re-fires on relevancy re-propagation after a backtrack.
Re-emit the conversion equality and side conditions for `fp.to_*` terms
there, mirroring `internalize_term`, so the FP↔BV linking axioms stay in
force across backtracking. On an `m_conversions` cache hit this just
re-asserts the (hash-consed) conversion equality and a `true` side
condition, so it adds no new terms and no clause bloat. The change only
adds sound constraints, so it can never turn a satisfiable formula
`unsat`.

## Validation

- #9022 reproducer: no longer reports `unsat` across many random seeds
and longer timeouts; a model (`sat`) is still found (the problem is
inherently hard quantified FP + nonlinear arithmetic, so timeouts are
expected).
- #8345 reproducer: first `check-sat` still `unsat` (the negated
quantifier axiom is valid).
- Additional incremental push/pop FP cases with
`fp.to_real`/`fp.add`/`fp.sub` and FP-returning UFs: correct, consistent
results.
- `test-z3 /a`: all 89 unit tests pass.
- Debug build (soundness assertions enabled): no assertion failures on
the above cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-09 10:22:03 -07:00
CEisenhofer
89a2ac133f Derived by the wrong "leading character" 2026-06-09 16:56:05 +02:00
CEisenhofer
9f44a9cce8 Flatten concat when deciding if it is constant 2026-06-09 16:39:09 +02:00
Copilot
a5495b78fa
Avoid invalidated column-cell references in LP pivot paths (#9783)
MSVC ASan reports showed a container-overflow in LP tableau pivoting,
reproducible from both examples and solver tests (issue #9781). The
failure came from reading a `column_cell` through a reference after
pivoting removed that entry from the backing column.

- **Root cause**
- `pivot_column_tableau` and the analogous Diophantine elimination loop
both held `auto& c = column.back()` across a call
(`pivot_row_to_row_given_cell`) that immediately removes that very cell
from the column via `remove_element`.
- After the mutation, the subsequent read `c.var()` used for bookkeeping
observed invalid memory.

- **Change**
- Record the affected row in the bookkeeping set (`m_touched_rows` /
`m_changed_rows`) by reading `c.var()` **before** the pivot call, while
the back cell is still valid.
- Make `static_matrix::pivot_row_to_row_given_cell` return `void`
instead of `bool`. Its result (`!rowii.empty()`) was always `true`: both
callers keep the matrix at full row rank (the tableau basis columns form
an identity submatrix; the Diophantine `m_l_matrix` stays invertible),
so an elementary row operation can never empty a row. The dead `if
(!...) return false;` early-exit in `pivot_column_tableau` is removed
and replaced with a `SASSERT(!rowii.empty())` documenting the invariant.

- **Affected code paths**
- `src/math/lp/static_matrix.h`, `src/math/lp/static_matrix.cpp`,
`src/math/lp/static_matrix_def.h`
  - `src/math/lp/lp_core_solver_base_def.h`
  - `src/math/lp/dioph_eq.cpp`

- **Behavioral impact**
  - No algorithmic change to pivoting.
- Removes the stale-reference hazard in the loops that repeatedly
eliminate entries from a column.

```c++
while (column.size() > 1) {
    auto& c = column.back();
    SASSERT(c.var() != piv_row_index);
    if (m_touched_rows != nullptr)
        m_touched_rows->insert(c.var());
    m_A.pivot_row_to_row_given_cell(piv_row_index, c, j);
}
```

- **Verification**
- Reproduced the exact issue #9781 failure on a local ASan build
(`container-overflow` in `pivot_column_tableau`) using the pre-fix code,
and confirmed it is gone with this change.
- The 4 reported tests pass clean under ASan: `c_example`,
`cpp_example`, `test-z3 get_implied_equalities`, `test-z3 quant_solve`.
  - Full `test-z3 /a` suite: 89 passed, 0 failed, 0 ASan errors.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Lev Nachmanson <levnach@hotmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-09 07:36:05 -07:00
CEisenhofer
2e4c165a16 Misclassified giving-up on decomposition as conflict 2026-06-09 16:22:41 +02:00
CEisenhofer
8229bcc5fc Conflicts are not reported correctly in eager regex factorization 2026-06-09 16:14:25 +02:00
CEisenhofer
64f422abc5 sigma of full_seq was missing 2026-06-09 15:49:41 +02:00
CEisenhofer
069068ce5e Don't use enodes for justifying disequality conflicts 2026-06-09 15:40:28 +02:00
CEisenhofer
3c39fc4238 Complement 2026-06-09 15:12:50 +02:00
CEisenhofer
9b357373b0 Preprocess away leading characters; otw. we are unsound 2026-06-09 14:44:41 +02:00