3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-05-07 02:45:19 +00:00
Commit graph

22121 commits

Author SHA1 Message Date
Lev Nachmanson
c40f8a200e
smt: reset give-up state when escalating final_check level (#9408)
theory_lra reports num_final_check_levels()==2: full nlsat (m_nra.check)
only runs at level >= 2. When a level-1 round-trip ends with FC_GIVEUP
and the loop escalates to level 2, the previously accumulated 'result',
'f', and 'm_incomplete_theories' were retained, so a subsequent
successful (FC_DONE) round at level 2 was still reported as
(incomplete (theory arithmetic)). Reset that state on each level
escalation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-28 03:33:28 +02:00
Nikolaj Bjorner
6cbc504f0b upgrade workflows
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-27 13:59:30 -07:00
Nikolaj Bjorner
63003b5795 convert z3_exception to tactic exception in try_for
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-26 16:37:39 -07:00
Nikolaj Bjorner
7461103802 making try-for tactic exception resilient on cancelation
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-26 15:58:24 -07:00
Copilot
245c117aba
simplify: replace ad-hoc reset_unsafe RAII with on_scope_exit in solve_eqs::reduce() (#9383)
* Initial plan

* simplify: replace reset_unsafe RAII struct with on_scope_exit in solve_eqs::reduce()

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/ff5650aa-02db-4a71-976f-845debd7222f

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-04-26 22:21:02 +02:00
Nikolaj Bjorner
0e07b218bc exception protection for nlsat_tactic
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-26 13:12:08 -07:00
Arie
d99d5a736f
Improvements to NLA lemmas (#9391)
* Add dual-row shared-factor sandwich for NLA bound propagation

When enabled via arith.nl.monomial_sandwich (default off), monomial_bounds
finds LP term columns whose term has shape  a_m * m + a_v * v  with exactly
two variables — both factors of a binary monomial m = u*v. The term column's
bound bounds (a_m * m + a_v * v); substituting m = u*v gives v * (a_m*u + a_v),
and sign-aware interval division by v plus an affine shift yields a numeric
bound on u. The derived interval is fed to the existing propagate_value path
so the lemma channel and integer rounding logic are shared with the rest of
NLA's forward/backward propagation; no new emit code.

Catches conflicts of the form
  α_v1 * v + α_m * m ≥ k1
  α_v2 * v + α_m * m ≤ k2
that today require nlsat (when no single row alone yields infeasibility but
their conjunction tightly bounds u after factoring v).

Scope: binary monomials only (m.size()==2, no squares); cap of 16 term-columns
scanned per call; one lemma per (u,v) attempt to keep the lemma channel quiet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add arith.nl.order.binomial_sign flag (default true)

Granular gate for order_lemma_on_binomial_sign — the only order family that
embeds a model-snapshot literal (x ≷ val(x)) in the lemma body. Disabling it
keeps the always-good structural mon-ol family running while removing the
SAT-splitter shape that cascades under model perturbations (e.g., from
arith.nl.monomial_sandwich tightening factor bounds).

Default true preserves master behaviour; the flag is intended as an
experimental knob to measure how much of an observed cascade is specifically
attributable to the binomial-sign splitter vs. the structural cancellation
lemmas in the same module.

See ord-binom-opportunities.md for the full gap analysis and the
deterministic-replacement directions (sandwich, McCormick) that would let
this flag eventually default to false without regressing leaves where
ord-binom currently carries the proof.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add sign-pinned binomial bound for NLA (Opportunity 1 from ord-binom doc)

When enabled via arith.nl.monomial_binomial_sign (default off), monomial_bounds
adds a third pass alongside propagate_down (existing) and propagate_shared_factor
(sandwich). For a binary monomial m = u*v in m_to_refine whose model value mv
disagrees with val(u)*val(v), and where v has a determined sign:

  1. synthesize a one-sided interval for m.var() at mv (no deps; the snapshot
     enters as a literal in the lemma body, not as an antecedent)
  2. divide by v's interval (sign-aware via dep.div<with_deps>) to get a
     deterministic interval for u
  3. emit a propagate_value-style lemma whose body is
        m.var() < mv (or > mv) ∨ u-bound
     conditioned on v's bound witness

Targets the case ord-binom currently handles: factors have determined signs,
m.var() may have no LP bound. The clause is sound modulo the monomial
definition (same condition propagate_down, propagate_shared_factor, and
ord-binom already rely on).

A new throttle kind MONOMIAL_BINOMIAL_SIGN keyed on (m.var, u, v, direction)
prevents cascading: without it, each new val(m.var()) snapshot would re-emit
across model changes the same way ord-binom does.

Validated via smt.arith.validate=true: 0 soundness errors across the
32-leaf test corpus.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add McCormick box-corner tangent points (Opportunity 2 from ord-binom doc)

When enabled via arith.nl.tangents.box_corners (default off, sub-flag of
arith.nl.tangents), tangent_imp::get_points selects m_a, m_b at the corners
of the bound box [x_lo, x_hi] × [y_lo, y_hi] instead of the model-centered
points val(x) ± delta. The selection follows the classical McCormick
under/over envelope:

  - m_below=true (under-approximation):
      m_a = (x_lo, y_lo),  m_b = (x_hi, y_hi)
  - m_below=false (over-approximation):
      m_a = (x_lo, y_hi),  m_b = (x_hi, y_lo)

The existing generate_plane already produces the McCormick linear form
xy ≷ pl.y·x + pl.x·y − pl.x·pl.y at any chosen point pl. push_point is
skipped in box-corner mode: corners are extremes, so doubling the offset
moves out of the box and would invalidate the McCormick property.

Falls back to the existing model-driven point selection when either factor
has an unbounded side or the box is degenerate (single-point in a
dimension).

Soundness — non-strict inequality at corners. The classical model-driven
flow uses pl strictly in the interior of the box, so generate_plane emits
xy > T (strict). At the box corners the tangent meets the surface along
the box's edges (xy = T when x = pl.x or y = pl.y), so the strict
inequality is violated by any model with x at the box boundary. A new
m_pl_strict_interior member, set false on a successful set_box_corners(),
switches generate_plane's emission to ≥/≤ (non-strict). The model-driven
path keeps strict — its push_point + plane_is_correct_cut chain already
guarantees pl is interior.

Validated via smt.arith.validate=true: 0 validate_conflict() failures
across the 32-leaf test corpus with box_corners=true.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 21:07:28 +02:00
Nikolaj Bjorner
b0956429fe fix regression from nlsat integration
updates to nlsat polynomial simplification introduced checkpoints.
These can throw exceptions (if setting a timeout).
The code that uses this was not properly protected from exceptions to distinguish timeout based tactics from genuine exceptions that should terminate solving altogether.

see updates such as: 117da362f0
2026-04-26 11:52:46 -07:00
Nikolaj Bjorner
6420bff843 skip other tseitin literals 2026-04-26 11:52:46 -07:00
Copilot
c8453d05f9
Add noop report-as-issue: false to code-simplifier workflow (#9397)
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/4dbec82b-a305-4164-bd35-294761afc2e7

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-04-26 18:28:30 +02:00
Nikolaj Bjorner
cd6fad428b code review updates
1. unit extraction could skip some units
2. create a shared method to check satisfiability that handles exception cases. They are the same among different workers, so shared in the batch manager.
2026-04-25 17:34:09 -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
cd94f8541f fix #9234
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-23 13:54:09 -07:00
Nikolaj Bjorner
844e248b1e disable elim-uncnstr under quantifiers #9293 2026-04-23 13:42:53 -07:00
Nikolaj Bjorner
101a9233bc fix #9309
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-23 11:07:24 -07:00
Copilot
f37f87422a
[code-simplifier] Simplify backbone/parallel code from PR #9343 (#9357)
* Initial plan

* Simplify backbone and parallel code paths from PR #9343

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/5bcd7f31-c5cc-4d1f-9ef1-6647950bab25

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-04-23 16:17:42 +02:00
Copilot
99f64b80fa
Prevent unsound solve-eqs elimination across recursive-function definitions (#9358)
* Initial plan

* Prevent unsound solve-eqs elimination across recursive-function definitions

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/9a2fc92f-15e8-4806-988b-28bce96e8007

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

* Update solve_eqs.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-04-23 16:17:21 +02:00
Nikolaj Bjorner
abd378e9d8 assert backbone to local context in backbone worker
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-22 18:40:44 -07:00
Nikolaj Bjorner
725772dfec add failed literal backbone variant
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-22 17:30:10 -07:00
Nikolaj Bjorner
c6b595d981 fix inverted logic of is-linear, #9311
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-22 09:28:14 -07:00
Arie
87e45accd9
Throttle lia2card in QF_NIA preamble (#9362)
mk_qfnia_preamble invoked lia2card with no params, so the default
max_range=101 was in effect. Any integer variable with a concrete
range hi-lo <= 101 was expanded into that many fresh Booleans plus
a sum-of-ITEs, bloating SAT search alongside the nonlinear structure.
On an observed QF_UFNIA benchmark this drove a 0.2s problem to a 30s
timeout.

Mirror the throttle already applied in mk_preamble_tactic
(qflia_tactic.cpp, commit 99cbfa715): limit lia2card to 0-1 integer
variables and nesting depth 1. Wrap with using_params so the
override survives and_then's downstream updt_params calls (passing
the params to mk_lia2card_tactic alone is overwritten when and_then
re-propagates the ambient params to each child).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:58:28 +02:00
dependabot[bot]
a155b2f86f
Bump nuget/setup-nuget from 3 to 4 (#9350)
Bumps [nuget/setup-nuget](https://github.com/nuget/setup-nuget) from 3 to 4.
- [Release notes](https://github.com/nuget/setup-nuget/releases)
- [Commits](https://github.com/nuget/setup-nuget/compare/v3...v4)

---
updated-dependencies:
- dependency-name: nuget/setup-nuget
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-21 19:26:55 +02:00
dependabot[bot]
7c32f65c37
Bump julia-actions/setup-julia from 2 to 3 (#9349)
Bumps [julia-actions/setup-julia](https://github.com/julia-actions/setup-julia) from 2 to 3.
- [Release notes](https://github.com/julia-actions/setup-julia/releases)
- [Commits](https://github.com/julia-actions/setup-julia/compare/v2...v3)

---
updated-dependencies:
- dependency-name: julia-actions/setup-julia
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-21 19:26:41 +02:00
Ilana Shapiro
19e95f40af
Add global backbones to parallel architecture (#9343)
* setting up new backbone experiment

* fix phase scores bug

* debug crash from negated atoms

* backbone thread/global backbones in progress, does NOT compile yet

* debug, still need to add backbones worker as a new thread

* setting up complicated condition variable thing for backbones worker thread

* debug

* debug lock contention

* it's a little messy, but change how i'm checking backbones by initiating with batch check

* don't split on global backbones, share global backbones once detected. still need to prune search tree with backbones

* close global backbone branches in search tree

* fix backbone ranking (take average of bb age over cubes and incorporate hits/num cubes the bb appears in

* add stats to backbone experiment

* gate the backbones experiment by local vs global

* update stats and fix bug about unsat core size=1 means global backbone

* phase negation ablation

* unforce phase ablation

* reset ablations

* add todo notes

* fix backbone aging

* first draft of Janota Alg 7

* process exactly 10 bb candidates in each batch

* fixing the Janota algorithm

* add backbone stats for Janota algorithm

* fix bug about global backbones not being checked unless local is also true

* hopefully fix bug about closing global backbones in search tree

* fix another bug in janota alg

* report random seed for debug

* print random seed for debug

* refactor janota alg code, still can't repro the crash

* fix some bugs in the janota algorithm

* try to fix weird memory leak thing with ramon/linux

* revert fix, it didn't work

* add second backbones thread

* increase chunk size when undef

* fix how the 2 backbone threads work on batches (they each race to finish the same batch). this was very complicated to code due to thread synchronization and while it runs there may be bugs

* update how we report stats for backbones

* first draft of doing the bb threads in neg and pos mode, needs revising

* fix some bugs in the positive version of the bb check, still need to review

* debug some more things in the positive bb worker

* keep bb candidates sorted, increase batch and chunk size

* try to resolve a couple of bugs

* fix very bad bug about backbones workers not doing anything

* ablate positive backbone thread

* fix how we record backbones in positive mode (shouldn't impact previous run)

* clarify code about adding found backbones

* add back the positive bb thread

* try to fix the random segfault bug + ablate the postiive bb thread again

* clean up logs

* share clauses with bb threads

* fixes

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* resolve deadlock

* add comment about SAT bb case

* todo comments

* complete TODOs in code, still need to debug bb threads

* debug bb threads, add bb_positive thread back in

* ablate bb_positive thread

* style

* configure num bb threads as param

* enable sat and unsat mode

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* updates

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* remove while true

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* updates

* try to fix rewriter_exception bug

* possibly reduce code under lock when only 1 bb thread

* add some copilot-suggested optimizations

* add copilot suggestions to fix condition variable synchronization with bb threads

* revert changes that are too messy with the code

* ablate collect clauses

* ablate condition variable logic changes

* ablate reset batch

* revert ablation

* remove m_batch_in_progress that makes the bb threads wait until both have exited the batch after one signals cancel (can be long if one is stuck in ctx check)

* sharing theory lemmas

* finish setup for search tree thread modes, and fix local bb setup to pull from the global pool

* variable renames

* update bb hyperparams after copilot (hopefully??) ran tuning experiments

* fix possible AST manager bug

* ablate collect clauses

* remove bb collect shared clauses

* fix local bb experiment bug and reinstate collect clauses for global bb

* local bb cands are thread-local ablation

* remove thread-local local bb ablation

* fix bug in nonthread-local bb experiment

* fix more nonthreadlocal bb bugs

* try to fix local bb bug

* AST manager mismatch bugfix

* attempt to fix another canonicalization bug

* try another bugfix

* try another bugfix

* try yet another bugfix

* thread local bb ablation

* ablate force phase

* ablate set activity

* undo ablations since apparently it's not forcing phase or boosting activities

* remove old experiments

* try guarding m_birthdate size

* try to fix several bugs including with m_birthdate initialization and how we're storing original phases

* one more bugfix

* remove local bb experiment after negative signals on experiments, and change bb ranking to VSIDS scores as opposed to phase

* select bb polarity based on phase, not VSIDS

* first attempt with codex. Codex notes:
What changed:

  - Each tree node now tracks:
      - active worker count
      - lease epoch
      - cancel epoch
  - get_cube() now hands each worker an explicit lease: (node, epoch, cancel_epoch).
  - try_split() and backtrack() now operate on that lease, and the batch manager releases the worker’s lease under the tree lock before mutating the
    node.
  - If another worker closes the leased node or subtree, the batch manager cancels only the workers whose current leased nodes are now closed.
  - Workers detect canceled leases after check(), reset their local cancel flag, abandon the stale lease, and continue instead of turning that into a
    global exception.
  - The “reopen immediately into the open queue” policy is preserved. I did not add a barrier waiting for all workers on a node to finish.
  - Active-worker accounting is now separate from the open/active/closed scheduling status, so reopening a node no longer erases the fact that other
    workers are still on it.

  I also updated search_tree bookkeeping so:

  - closure bumps node cancel/lease epochs
  - active-node counting uses actual active-worker presence, not just status == active

* fix smts bugfix git merge issues with backtrack

* fix(parallel-smt): gate split/backtrack by lease epoch

What it changes:

  - util/search_tree.h
      - bumps node epoch on split
      - threads epoch through should_split(...) and try_split(...)
      - always records effort, but only split/reopen if the lease epoch still matches
  - smt/smt_parallel.cpp
      - requires is_lease_valid(..., lease.epoch) before backtrack(...)
      - passes lease.epoch into m_search_tree.try_split(...)

* clean up code and add some comments

* fix bug about backtracking condition being too strict: The epoch guard should not block backtrack(...) the same way it blocks try_split(...). A stale worker that proves UNSAT for n should still be able to
  close n, and that closure should then cancel the other workers on n and its subtree.

  I changed smt/smt_parallel.cpp accordingly:

  - try_split(...) still uses epoch to reject stale structural splits
  - backtrack(...) no longer requires is_lease_valid(..., epoch); it only requires that the lease is not already canceled

  So the intended asymmetry is now restored:

  - stale split: reject
  - stale unsat/backtrack: allow closure, then cancel affected workers

* ablate to no backtracking on stale leases

* fix merge

* revert codex change about exception handling

* fix linux bugs

* ablate backtrack gating

* attempt to fix linux crashes

* ablate backtracking on global bb

* the rare bb bug appears to be from creating the synthetic lease for a bb node and then backtracking on the synthetic lease. this is an attempt to fix it

* clean up code

* try to fix bug about active worker counts/lease accounting. current policy should hold: - stale leases: release/decrement
  - canceled leases: do not release/decrement (just ignore since we have an invariant that canceled leases mean closed nodes that are never revisited

* delay premature root activation

* fix major semantic bug about threads continually choosing the root if their lease is reset

* fix cancellation to unknown status

* fix very bad bug about all threads needing to start at the root

* ablate active ranking: now nodes are only reopened if they are truly inactive (active worker count is 0)

* fix some bugs about leases

* ablate adding static effort only

* fix some bugs about leases

* don't explode effort for portfolio nodes

* fix: still accumulate per-node effort, but don't over-accumulate on portfolio solves

* restore dynamically scaled effort

* clean up merge from cherry pick

* tighten which nodes we detect for proven global bb closure (only detect nonclosed nodes)

* fix cancel to unknown exception on bb code

* lease cancellation doens't touch rlimit now, it just sets max conflicts to 0. also fix a VERY BAD BUG about effort never being updated until all leases are done on a node, which meant we never left the root

* cross-thread modification of max conflicts is unsafe, so create an atomic lease canceled variable that's ch
ecked in ctx where max conflicts is also checked

* move atomic lease check in the context to the more global get_cancel_flag function

* Fix new SIGSEV. issue: The root cause: get_cancel_flag() is called from within propagation loops (mid-BCP, mid-equality-propagation, mid-atom-propagation). When it returns true there, the solver exits early and leaves the context in an intermediate state —
  propagation queues partially processed, theory state potentially inconsistent with boolean state.

  For the global cancel (m.limit().cancel()), this is harmless: the worker exits entirely and the context is destroyed. Intermediate state doesn't matter.

  For a lease cancel, the context is reused — the worker gets a new cube and calls ctx->check() again on the same context object. Re-entering check() on a context interrupted mid-propagation causes it to access that corrupted intermediate
  state → SIGSEGV.

  The m_max_conflicts check is the only checkpoint that's safe for re-entry: it only fires post-conflict-resolution, pre-decision, when propagation queues are empty and theory state is consistent.

  Fix: Remove m_lease_canceled from get_cancel_flag(). Keep it only at safe, between-phase checkpoints where the context is in a known-consistent state. The result is two safe checkpoints for m_lease_canceled: after each conflict (post-resolution, queues empty) and before each theory final check (not yet entered the theory). Neither interrupts the solver mid-mutation. The SIGSEGV should be
   gone, and NIA performance should improve because long theory final checks (where NIA burns most time) are now preemptable before they start.

* fix new inconsistent theory bug: The problem is returning FC_GIVEUP from inside final_check() after some theories have already run final_check_eh() and pushed propagations into the queue. Those pending propagations reference context state that gets invalidated on the next check() call → SIGSEGV. The fix: check m_lease_canceled before entering final_check() in bounded_search(), never from inside it. That way the context is always in a clean pre-final-check state when we bail out. This is safe: decide() returned false (all variables assigned, no pending propagations), theories haven't been touched yet, context is in a fully consistent state. For NIA, this is still a meaningful win — we avoid entering expensive arithmetic final checks entirely when the lease is already canceled.

* ablate lease cancel check in ctx final theory check due to crash (??)

* gate bb-specific code behind param

* try some possible bugfixes for the sigsev

* ablate some bugfixes

* remove second lease cancel check in smt_context, not sure it's safe. only check where we do the max conflicts check

* restore exception handling logic to master branch

* restore reslimit cancels since the bug appears to be latent

* add bookkeeping for race condition of multiple lease cancels on a single node (messes with reslimit)

* restore unrelated code to master

---------

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MacBook-Pro.local>
Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MBP.lan1>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Ilana Shapiro <ilanashapiro@Mac.localdomain>
Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MBP.localdomain>
Co-authored-by: Ilana Shapiro <ilanashapiro@Mac.lan1>
2026-04-20 18:22:07 +02:00
dependabot[bot]
75039d631c
Bump actions/upload-artifact from 7.0.0 to 7.0.1 (#9300)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v7...v7.0.1)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-19 16:51:02 +02:00
dependabot[bot]
36e1bd15ea
Bump actions/github-script from 8.0.0 to 9.0.0 (#9296)
Bumps [actions/github-script](https://github.com/actions/github-script) from 8.0.0 to 9.0.0.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v8...3a2844b7e9c422d3c10d287c895573f7108da1b3)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-19 16:49:03 +02:00
Ilana Shapiro
44966e1733
Terminate on Demand and some algorithmic bugfixes in the search tree (#9336)
* first attempt with codex. Codex notes:
What changed:

  - Each tree node now tracks:
      - active worker count
      - lease epoch
      - cancel epoch
  - get_cube() now hands each worker an explicit lease: (node, epoch, cancel_epoch).
  - try_split() and backtrack() now operate on that lease, and the batch manager releases the worker’s lease under the tree lock before mutating the
    node.
  - If another worker closes the leased node or subtree, the batch manager cancels only the workers whose current leased nodes are now closed.
  - Workers detect canceled leases after check(), reset their local cancel flag, abandon the stale lease, and continue instead of turning that into a
    global exception.
  - The “reopen immediately into the open queue” policy is preserved. I did not add a barrier waiting for all workers on a node to finish.
  - Active-worker accounting is now separate from the open/active/closed scheduling status, so reopening a node no longer erases the fact that other
    workers are still on it.

  I also updated search_tree bookkeeping so:

  - closure bumps node cancel/lease epochs
  - active-node counting uses actual active-worker presence, not just status == active

* fix(parallel-smt): gate split/backtrack by lease epoch

What it changes:

  - util/search_tree.h
      - bumps node epoch on split
      - threads epoch through should_split(...) and try_split(...)
      - always records effort, but only split/reopen if the lease epoch still matches
  - smt/smt_parallel.cpp
      - requires is_lease_valid(..., lease.epoch) before backtrack(...)
      - passes lease.epoch into m_search_tree.try_split(...)

* clean up code and add some comments

* fix bug about backtracking condition being too strict: The epoch guard should not block backtrack(...) the same way it blocks try_split(...). A stale worker that proves UNSAT for n should still be able to
  close n, and that closure should then cancel the other workers on n and its subtree.

  I changed smt/smt_parallel.cpp accordingly:

  - try_split(...) still uses epoch to reject stale structural splits
  - backtrack(...) no longer requires is_lease_valid(..., epoch); it only requires that the lease is not already canceled

  So the intended asymmetry is now restored:

  - stale split: reject
  - stale unsat/backtrack: allow closure, then cancel affected workers

* ablate to no backtracking on stale leases

* revert codex change about exception handling

* remove old code

* ablate backtracking gate

* attempt to fix linux crashes

* try to fix bug about active worker counts/lease accounting. current policy should hold: - stale leases: release/decrement
  - canceled leases: do not release/decrement (just ignore since we have an invariant that canceled leases mean closed nodes that are never revisited

* delay premature root activation

* fix major semantic bug about threads continually choosing the root if their lease is reset

* fix cancellation to unknown status

* fix very bad bug about all threads needing to start at the root

* ablate active ranking: now nodes are only reopened if they are truly inactive (active worker count is 0)

* fix some bugs about leases

* ablate adding static effort only

* fix some bugs about leases

* don't explode effort for portfolio nodes

* fix: still accumulate per-node effort, but don't over-accumulate on portfolio solves

* restore dynamically scaled effort

* lease cancellation doens't touch rlimit now, it just sets max conflicts to 0. also fix a VERY BAD BUG about effort never being updated until all leases are done on a node, which meant we never left the root

* cross-thread modification of max conflicts is unsafe, so create an atomic lease canceled variable that's ch
ecked in ctx where max conflicts is also checked

* move atomic lease check in the context to the more global get_cancel_flag function

* Fix new SIGSEV. issue: The root cause: get_cancel_flag() is called from within propagation loops (mid-BCP, mid-equality-propagation, mid-atom-propagation). When it returns true there, the solver exits early and leaves the context in an intermediate state —
  propagation queues partially processed, theory state potentially inconsistent with boolean state.

  For the global cancel (m.limit().cancel()), this is harmless: the worker exits entirely and the context is destroyed. Intermediate state doesn't matter.

  For a lease cancel, the context is reused — the worker gets a new cube and calls ctx->check() again on the same context object. Re-entering check() on a context interrupted mid-propagation causes it to access that corrupted intermediate
  state → SIGSEGV.

  The m_max_conflicts check is the only checkpoint that's safe for re-entry: it only fires post-conflict-resolution, pre-decision, when propagation queues are empty and theory state is consistent.

  Fix: Remove m_lease_canceled from get_cancel_flag(). Keep it only at safe, between-phase checkpoints where the context is in a known-consistent state. The result is two safe checkpoints for m_lease_canceled: after each conflict (post-resolution, queues empty) and before each theory final check (not yet entered the theory). Neither interrupts the solver mid-mutation. The SIGSEGV should be
   gone, and NIA performance should improve because long theory final checks (where NIA burns most time) are now preemptable before they start.

* fix new inconsistent theory bug: The problem is returning FC_GIVEUP from inside final_check() after some theories have already run final_check_eh() and pushed propagations into the queue. Those pending propagations reference context state that gets invalidated on the next check() call → SIGSEGV. The fix: check m_lease_canceled before entering final_check() in bounded_search(), never from inside it. That way the context is always in a clean pre-final-check state when we bail out. This is safe: decide() returned false (all variables assigned, no pending propagations), theories haven't been touched yet, context is in a fully consistent state. For NIA, this is still a meaningful win — we avoid entering expensive arithmetic final checks entirely when the lease is already canceled.

* remove second lease cancel check in smt_context, not sure it's safe. only check where we do the max conflicts check

* check epoch match in release_lease_unlocked

* restore exception handling logic to master branch

* restore reslimit cancels since the bug appears to be latent

---------

Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MacBook-Pro.local>
Co-authored-by: Ilana Shapiro <ilanashapiro@Mac.lan1>
2026-04-19 16:21:41 +02:00
dependabot[bot]
0669cdd829
Bump actions/cache from 5.0.4 to 5.0.5 (#9299)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/actions/cache/releases)
- [Commits](https://github.com/actions/cache/compare/v5.0.4...v5.0.5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-19 15:57:29 +02:00
dependabot[bot]
62ab8fc4f5
Bump mymindstorm/setup-emsdk from 15 to 16 (#9297)
Bumps [mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk) from 15 to 16.
- [Release notes](https://github.com/mymindstorm/setup-emsdk/releases)
- [Commits](https://github.com/mymindstorm/setup-emsdk/compare/v15...v16)

---
updated-dependencies:
- dependency-name: mymindstorm/setup-emsdk
  dependency-version: '16'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-19 15:57:13 +02:00
Guangyu (Gary) HU
d397a071a6
Fix two bugs in Python examples (#9303)
- bincover.py: typo `NOne` -> `None` in _value2bin fallback path
  (would raise NameError if bin_index is out of range).

- complex/complex.py: rename `__neq__` to `__ne__`. Python has no
  `__neq__` dunder, so `!=` was not using the intended definition.
  On Python 3 it silently fell back to the auto-derived inverse of
  `__eq__`; on Python 2 it fell back to identity comparison.
2026-04-19 15:56:40 +02:00
Arie
38fbf486dc
fix(anum): give anum move semantics to prevent sort-triggered double-free (#9320)
Fixes a double-free (SIGSEGV in mpz_manager::del) in
algebraic_numbers::manager:👿:del_poly, reached through the
destruction of nlsat::evaluator's scoped_anum_vector members on a
subsequent call to nra::solver:👿:reset.

Root cause: sort_roots runs std::sort over a numeral_vector with a
comparator (lt_proc -> manager::lt -> compare_core) that legitimately
throws when the reslimit fires mid-comparison. libc++'s insertion sort
shifts elements via move-assignment inside its inner loop, and because
anum previously had only compiler-generated shallow copy/move (both
just copied m_cell without nulling the source), a throw between two
consecutive shifts could leave two vector slots pointing at the same
algebraic_cell. When the owning scoped_anum_vector was later destroyed
it del'd the same cell twice, reading through a freed chunk whose
first bytes had been overwritten by small_object_allocator's free-list
next pointer.

Fix: give anum proper move constructor and move assignment that
transfer the tagged m_cell pointer and null the source. Copy stays
a shallow handle copy (ownership is still tracked externally by the
manager / owning vector, as before). With the new move, every
intermediate state of sort's move-via-tmp sequence has at most one
slot referencing any given cell, so a throwing comparator can leak
the in-flight tmp cell but cannot produce aliased slots and therefore
cannot cause the downstream double-free.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:55:52 +02:00
Copilot
daf2506b60
fix(ostrich-benchmark): add safeoutputs keepalive noop calls before long benchmark run (#9313)
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/7d129a85-614d-4927-a598-05ae902ab771

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-04-16 03:22:33 +02:00
Copilot
1d19d4a0dc
fix(qf-s-benchmark): add safeoutputs keepalive noop after build, reduce cap 500→300 (#9290)
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/52450c65-ef77-45d4-80fa-b617f9df88e8

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-04-12 18:26:55 -07:00
Arie
665d4f36ff
Fixes for lar_term== operator (#9284)
* Fix broken term_comparer in m_normalized_terms_to_columns lookup

The `m_normalized_terms_to_columns` map in `lar_solver` uses a
`term_comparer` that delegates to `lar_term::operator==`, which
intentionally returns `false` (with comment "take care not to create
identical terms"). This makes `fetch_normalized_term_column` unable to
find any term, rendering the Horner module's `interval_from_term`
bounds-recovery path dead code.

History: `lar_term::operator==` returning `false` has been present since
the original "merge LRA" commit (911b24784, 2018). The
`m_normalized_terms_to_columns` lookup was added later (dfe0e856,
c95f66e0, Aug 2019) as "toward fetching existing terms intervals from
lar_solver". The initial code had `lp_assert(find == end)` on
registration (always true with broken ==) and `lp_assert(find != end)`
on deregister (always false). The very next commit (207c1c50, one day
later) removed both asserts, replacing them with soft checks. The
`term_comparer` struct delegating to `operator==` was introduced during
a later PIMPL refactor (b375faa77).

Fix: Replace the `term_comparer` implementation with a structural
comparison that checks size and then verifies each coefficient-variable
pair via `coeffs().find_core()`. This is localized to the
`m_normalized_terms_to_columns` map and does not change
`lar_term::operator==`, preserving its intentional semantics elsewhere.

Validated: on a QF_UFNIA benchmark, `interval_from_term` lookups go
from 0/573 successful to 34/573 successful. Unit test added for the
`fetch_normalized_term_column` round-trip.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Disable operator== for lar_term

The operator== for lar_term was never intended to be used.
This changes physically disables it to identify what happens to depend
on the operator.

* Work around missing lar_term==

Previous commit disabled lar_term==. This is the only use of the
operator that seems meaningful. Changed it to compare by references
instead.

Compiles, but not sure this is the best solution.

* replace with e

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* Delete unused ineq::operator==

The operator is unused, so there is no need to figure what is
the best fix for it.

* Remove lp tests that use ineq::operator==

---------

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-12 14:31:18 -07:00
Copilot
68e528eaf7
Go/OCaml API gaps: substitution, AST introspection, Spacer, Goal completion (#9277)
* fix: address issues 1,2,4,5 and add Goal API to Go bindings

Issue 2 (Go): Add Substitute, SubstituteVars, SubstituteFuns to Expr
Issue 4 (Go): Add GetDecl, NumArgs, Arg to Expr for AST app introspection
Goal API (Go): Add IsInconsistent and ToDimacsString to Goal
ASTVector (Go): Add public Size, Get, String methods
ASTMap (Go): Add ASTMap type with full CRUD API in spacer.go
Issue 1 (Go): Add Spacer fixedpoint methods QueryFromLvl, GetGroundSatAnswer,
  GetRulesAlongTrace, GetRuleNamesAlongTrace, AddInvariant, GetReachable
Issue 1 (Go): Add context-level QE functions ModelExtrapolate, QeLite,
  QeModelProject, QeModelProjectSkolem, QeModelProjectWithWitness
Issue 5 (OCaml): Add substitute_funs to z3.ml and z3.mli

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/afa18588-47af-4720-8cea-55fe0544ae55

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

* fix: add substitute_funs to Expr module sig in z3.ml

The internal sig...end block in z3.ml (the module type declaration for Expr)
was missing val substitute_funs, causing OCaml compiler error:
  The value substitute_funs is required but not provided

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/c6662702-46a3-4aa0-b225-d6b73c2a2505

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-04-12 14:00:03 -07:00
Nikolaj Bjorner
1566d3cc41 add flag to control non-linear substitutions: smt.solve_eqs.linear is by default false, setting it to true restricts solutions to substitutions to only use linear terms. This can have an effect on cross-multiplication of nested substitutions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-12 09:41:46 -07:00
Nikolaj Bjorner
1544462f47 recompiled aw
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-11 11:17:51 -07:00
Copilot
853c62f58a
Fix qf-s-benchmark: broken code fence, OOM build, and timeout budget (#9268)
* Initial plan

* fix qf-s-benchmark: Release mode build, fix broken code fence, reduce timeouts

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/8eaace11-bbc1-49d9-993d-67290f5b1841

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

* recompile all workflow lock files with gh-aw v0.68.1

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/a5c25542-de48-41e0-a48b-b7128fcb49bf

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

* revert unaffected lock files to pre-PR state, keep only qf-s-benchmark compiled

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/8ec3816f-882f-459b-b7cc-49d0c91b25c3

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-04-11 11:17:05 -07:00
Copilot
d29a1ebd38
Fix Ostrich Benchmark workflow: allow NuGet and guarantee safe output (#9267)
* Initial plan

* fix ostrich-benchmark: add api.nuget.org to network allowlist and ensure safe output is always produced

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/7eb3a93e-e81b-4b79-b84b-080a7bacfec0

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-04-11 11:16:00 -07:00
Copilot
2ce410d45e
Fix Issue Backlog Processor: prevent context exhaustion by batching and requiring safe output (#9272)
* Initial plan

* Fix Issue Backlog Processor: limit batch size and require safe output

- Add CRITICAL instruction requiring create-discussion or noop before finishing
- Limit processing to 30 issues per run to avoid context exhaustion
- Add lazy comment fetching with concrete criteria
- Add batch cursor tracking in cache memory for pagination across runs
- Add explicit MANDATORY note before create-discussion step
- Improve guidelines with always-produce-output, batch processing rules

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/8c4e23ac-8562-423b-baf7-62986f23abe0

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-04-11 10:21:01 -07:00
Copilot
4a1f448a06
Fix agentic workflow compilation errors (gh-aw v0.68 compat) (#9275)
* Start: recompile agentic workflows, fix errors and security issues

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/88b80d94-e7d6-4e8f-a106-baa2e7e212d6

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

* Fix agentic workflow compilation errors: remove glob/view tools, resolve merge conflict, fix serena tool and missing imports

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/88b80d94-e7d6-4e8f-a106-baa2e7e212d6

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-04-11 10:19:45 -07:00
Nikolaj Bjorner
3c7e5c8197 add fold-unfold simplifier
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-10 18:04:09 -07:00
Nikolaj Bjorner
e0401a6544 fix truncation error
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-10 18:04:08 -07:00
Copilot
04bf2623fa
fix(workflow): ZIPT Code Reviewer always call noop when no improvements found (#9269)
* Initial plan

* fix: instruct ZIPT Code Reviewer agent to call noop when no improvements found

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/5ebc812f-84d3-443f-97fd-ccb97000c7c0

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-04-10 17:47:54 -07:00
Copilot
9c81571eb8
Apply qf-s-benchmark fix: replace ZIPT/dotnet workflow with seq vs nseq only (#9266)
* Apply qf-s-benchmark fix from agentics/qf-s-benchmark.md: remove ZIPT/dotnet dependency

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/c36bada5-c222-4b97-99c4-08392955b32d

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

* Update qf-s-benchmark title prefix and note to QF_S Benchmark

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/c36bada5-c222-4b97-99c4-08392955b32d

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-04-10 14:30:44 -07:00
Arie
58ad1f0918
Fix scaled_min test failure from #9235 mod-factor-propagation (#9260)
The is_mod handler in theory_lra called ensure_nla(), which
unnecessarily created the NLA solver for pure linear problems, causing
the optimizer to return a finite value instead of -infinity.

Fix: check `m_nla` instead of calling `ensure_nla()`, matching the
pattern used by the is_idiv handler. The mod division is only registered
when NLA is already active due to nonlinear terms.

Update mod_factor tests to use QF_NIA logic and assert the mul term
before the mod term so that internalize_mul triggers ensure_nla() before
mod internalization.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 12:52:42 -07:00
Nikolaj Bjorner
23ae00a57e update count to 2
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-09 16:39:51 -07:00
Guangyu (Gary) HU
fbd51981c3
mini_quip: port to Python 3 and fix several bugs (#9246)
* mini_quip: port to Python 3 and fix several bugs

examples/python/mini_quip.py was Python 2 only and had several
latent bugs that prevented it from running on Python 3 or producing
correct results on benchmarks beyond horn1..5.

Python 3 / import fixes:
- Convert `print stmt` to `print(...)` calls (lines 457-458, 567,
  710, 747, 765, 776).
- The bare `print("Test file: %s") % file` form was applying `%`
  to the return value of print() (None); rewrite as
  `print("Test file: %s" % file)`.
- Add `import sys` (used by sys.stdout.write/flush) and
  `import copy` (used by QReach.state2cube via copy.deepcopy);
  neither was previously imported.
- next()/prev() passed `zip(...)` directly to z3.substitute. In
  Python 3 zip returns a one-shot generator; wrap with list() the
  same way mini_ic3 already does.

Bug fixes:
- is_transition(): when an init rule's body is an And without any
  Invariant predicate, is_body() returns (And(...), None). The
  function then passed inv0=None to subst_vars and crashed inside
  get_vars(). Add an explicit None check so the rule falls through
  to is_init() (same fix as mini_ic3).
- generalize(): guard against an empty unsat core. Without the
  guard, an empty core can be returned and become
  cube2clause([])=Or([])=False, poisoning all frames (same class
  of bug as in mini_ic3).
- check_reachable(): self.prev(cube) on an empty cube produced an
  empty list which was then added to a solver as a no-op
  constraint, so an empty cube would always look reachable. Only
  add the constraint when cube is non-empty.
- quip_blocked() at f==0 for must goals contained
  `assert is_sat == s.check()` where `is_sat` is undefined in that
  scope; the intent is `assert sat == s.check()`.
- Inside the lemma-pushing loop in quip_blocked(), `is_sat == unsat`
  was a comparison whose result was discarded; the intended
  assignment is `is_sat = unsat`.

Verified on horn1..5 (unchanged behavior, all return same
SAFE/UNSAFE result and validate). Larger benchmarks (h_CRC,
h_FIFO, cache_coherence_three) now at least run without exceptions
(performance is a separate matter).

* mini_quip: guard against None from QReach.intersect in CEX trace loop

In quip_blocked, the must-goal CEX-tracing loop calls
self.reachable.intersect(self.prev(r)) and immediately uses
r.children() on the result. QReach.intersect can return None when
the model literals do not match any state in the partial reachable
set, which crashes with AttributeError: 'NoneType' object has no
attribute 'children'. Reproduces on data/h_FIFO.smt2.

Fix: save the model, and when intersect returns None fall back to
the raw self.project0(model) as the predecessor cube. This still
gives a concrete predecessor and lets the CEX trace make progress
instead of crashing.
2026-04-09 14:30:26 -07:00
Ilana Shapiro
ceb363d35d
SMTS tree algorithms (#9250)
* Refactor parallel search tree to use global node selection (SMTS-style) instead of DFS traversal.
Introduce effort-based prioritization, allow activation of any open node, and add controlled/gated
expansion to prevent over-partitioning and improve load balancing.

* clean up code

* ablations

* ablations2: effort

* ablations2: activation

* ablations3: more activations

* ablations4: visit all nodes before splitting

* throttle tree size min is based on workers not activated nodes

* ablate random throttling

* ablate nonlinear effort

* clean up code

* ablate throttle

* ablate where add_effort is

* reset

* clean up a function and add comment

---------

Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MBP.localdomain>
Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MacBook-Pro.local>
Co-authored-by: Ilana Shapiro <ilanashapiro@Ilanas-MBP.lan1>
2026-04-09 09:46:47 -07:00
Nikolaj Bjorner
c7879ed5ad fix #9254
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-04-09 09:19:40 -07:00