3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-20 23:50:25 +00:00
Commit graph

1491 commits

Author SHA1 Message Date
davedets
72973b00eb Use "override" keyword where needed. (#9892)
This is another PR towards the goal of getting Z3 to compile cleanly
when included via FetchContents into clang-tidy, which uses a pretty
strict set of warnings.

The PR adds
```
  "-Wsuggest-override"
  "-Winconsistent-missing-override"
 ```
 to the CLANG_ONLY_WARNINGS.  This exposes a relatively small number of places where method overrides did not use the "override" keyword.  The PR fixes those.
 
(In cmd_util.h, I also made the *_CMD macros be uniform in not ending the class they define with a semicolon; the invocation of the macro can add the semicolon.)
2026-06-19 17:36:19 -07:00
Lev Nachmanson
a99c69d3f1 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-19 17:36:07 -07: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
Arie
73151f1960
nla_grobner: add mod_residue pattern to propagate_quotients (#9597)
Adds a new lemma pattern to nla_grobner::propagate_quotients that
derives a modular-residue constraint from polynomial divisibility,
filling a gap between quotient1-5 (model-value-driven case splits) and
the polynomials Grobner actually produces on Skolem-encoded mod
arithmetic.

Pattern
-------

For a polynomial p with all-integer free variables and a linear monomial
c_v * v (single integer var), the pattern computes M = gcd(|c_i/c_v|)
over the other monomials and K = c0/c_v for the constant term. When both
are integers, dividing p by c_v gives

    v + M*Q + K = 0   with Q an integer

so v ≡ -K (mod M). The pattern emits the sound disjunctive lemma

    (v < 0)  ∨  (v ≥ M)  ∨  (v = target)

where target = (-K) mod M ∈ [0, M-1]. This encodes "v ∈ target + M·Z" in
a form the LP / SAT layer can refute against current bounds.

Motivation
----------

QF_UFNIA verification benchmarks over fixed-prime modular arithmetic
(e.g. zk applications using the BabyBear prime 2013265921) regularly
produce basis polynomials of the form

    -p*v_div + p*(v_a * v_b) - v_mod = 0

where v_mod is the result of (mod (* v_a v_b) p). The polynomial sits in
the Grobner basis but none of quotient1-5 fires: they all require
specific model-value alignments (r_value == 0, |v_value| > |r_value|,
etc.) that don't hold when all variables in scope are similarly sized
integers in [0, p). The proof spins on interval-tightening lemmas
without ever extracting the modular conclusion.

The author of propagate_quotients flagged this gap with the comment
\"other division lemmas are possible\" preceding the fall-through \"no
lemmas found\" CTRACE. This patch supplies one.

Soundness
---------

The lemma is sound regardless of v's LP bounds — the bound-negation
disjuncts (v < 0) and (v ≥ M) make the disjunction unconditionally true
under the polynomial identity, with v = target as the canonical residue
in [0, M-1]. M is derived from the polynomial's coefficient gcd, not
from any LP-side bound.

Validated under smt.arith.validate=true on the mod-factor-propagation
reproducers (PR #9235 follow-up), zk verifier benchmarks, and a broader
QF_UFNIA sample — 50+ files total, zero validate_conflict() assertion
violations.

Performance
-----------

A model-value gate (skip emission when v's current value already
satisfies one of the disjuncts) prevents the pattern from
short-circuiting the propagate_quotients || propagate_gcd_test ||
propagate_eqs || propagate_factorization || propagate_linear_equations
chain with redundant emissions. Without the gate, a single (v, M,
target) triple can re-emit each Grobner round and starve the downstream
propagators — observed in regression testing as thousands of identical
emissions on a small benchmark, turning a sub-second closure into a
timeout.

On six small mod-factor-propagation reproducers, the patch closes four
cases that previously timed out at 30 s (~1 s typical under the
Grobner-ramped config: smt.arith.nl.gr_q=50,
smt.arith.nl.grobner_eqs_growth=50,
smt.arith.nl.grobner_exp_delay=false, smt.arith.nl.grobner_frequency=1).
The two remaining timeouts in that set are attributable to different
gaps (Boolean-disjunction propagation, and the multi-bounded-mod-result
polynomial shape that needs Grobner over Z/pZ), not to mod_residue
itself.

Diagnostics
-----------

TRACE under the existing 'grobner' tag emits one line per lemma
emission, recording v, M, c_v, c0, and target.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2026-05-26 18:12:38 -07:00
Lev Nachmanson
43791ebf2a
Iss9139 fix (#9577)
Preserve the de-linearization of the linear constraints but fixing the
den bug. @ValentinPromies, that is what you had in mind.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-21 06:33:14 -07:00
Copilot
09396b72dd
nla_grobner: remove dead code and fix indentation (#9423)
* Initial plan

* [code-simplifier] nla_grobner: remove dead code and fix indentation

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/1dc7dd96-d7d7-4fca-94b4-bde677fee842

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-29 11:12:45 -07:00
Arie
6d38d5ed41
NLA tracing: emit varmap and grobner-linear-eq for trace analysis (#9415)
Two TRACE blocks under the existing nla_solver tag:

1. theory_lra::false_case_of_check_nla emits a "varmap:" line for each
   NLA lemma, listing j-var → SMT-name mappings for variables in the
   lemma's collect_vars set. Lets lemur nla resolve the LP-internal
   j-numbering back to the original SMT term names when displaying
   lemmas. Without this, lemma-level analysis has to either guess at
   variable identities (and j-numbers are reused across nlsat
   invocations under backtracking — see j-vars-unstable note) or use a
   different trace tag entirely (-tr:nra) for stable algebraic-number
   IDs.

2. nla_grobner emits a "grobner-linear-eq:" line at each call to
   add_term + update_column_type_and_bound that produces a Linear
   Propagation row from completion. Lets us count Gröbner's effective
   contribution to the LP tableau independently of the lemma stream.
   Useful when investigating Gröbner-deficit hypotheses in NLA cascade
   diagnosis.

Both are pure trace emission, behind TRACE(nla_solver, ...). Zero
runtime cost when tracing is off; no semantic change.
2026-04-28 17:31:11 -07:00
Arie
dbb91de64b
Add adaptive growth knobs for Gröbner under arith.nl.grobner_adaptive (#9390)
* Add adaptive growth knobs for Gröbner under arith.nl.grobner_adaptive

When enabled, the per-call growth budget (m_eqs_growth, m_expr_size_growth,
m_expr_degree_growth, m_max_simplified) is scaled by m_growth_boost:
- two consecutive productive runs bump the boost by 3/2 (cap 4x)
- a miss resets the streak and decays the boost toward 1.0x by 1/4 of excess

Default is off; the existing miss-frequency throttle (m_quota / m_delay_base)
is unchanged, so this only affects per-call power, not call frequency.

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

* Update src/params/smt_params_helper.pyg

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Arie Gurfinkel <arie.gurfinkel@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-28 08:50:38 -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
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
Arie
477a1d817d
Add mod-factor-propagation lemma to NLA divisions solver (#9235)
When a monic x*y has a factor x with mod(x, p) = 0 (fixed), propagate
mod(x*y, p) = 0. This enables Z3 to prove divisibility properties like
x mod p = 0 => (x*y) mod p = 0, which previously timed out even for
p = 2. The lemma fires in the NLA divisions check and allows Gröbner
basis and LIA to subsequently derive distributivity of div over addition.

Extends division tuples from (q, x, y) to (q, x, y, r) to track the
mod lpvar. Also registers bounded divisions from the mod internalization
path in theory_lra, not just the idiv path.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:34:11 -07:00
Lev Nachmanson
44e84dc5d0 refactor try_bivar_hensel_lift and outline the algorithm
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-03-24 06:25:29 -10:00
Lev Nachmanson
6fb68ac010
Nl2lin - integrate a linear under approximation of a CAD cell by Valentin Promies. (#8982)
* outline of signature for assignment based conflict generation

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

* outline of interface contract

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

* remove confusing construction

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

* add material in nra-solver to interface

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

* add marshaling from nlsat lemmas into core solver

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

* tidy

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

* add call to check-assignment

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

* Nl2lin (#7795)

* add linearized projection in nlsat

* implement nlsat check for given assignment

* add some comments

* fixup loop

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

* updates

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

* fixes

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

* debug nl2lin

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* Nl2lin (#7827)

* fix linear projection

* fix linear projection

* use an explicit cell description in check_assignment

* clean up (#7844)

* Simplify no effect checks in nla_core.cpp

Move up linear nlsat call to replace bounded nlsat.

* t

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* t

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* detangle mess

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

* remove the too early return

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* do not set use_nra_model to true

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* remove a comment

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* add a hook to add new multiplication definitions in nla_core

* add internalization routine that uses macro-expanded polynomial representation

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

* add internalization routine that uses macro-expanded polynomial representation

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

* fixup backtranslation to not use roots

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

* call setup_assignment_solver instead of setup_solver

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

* debug the setup, still not working

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* updated clang format

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

* simplify

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

* create polynomials with integer coefficients, use the hook to create new monomials

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* integrating changes from master related to work with polynomials

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* add forgotten files

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* Update nlsat_explain.cpp

Remove a duplicate call

* fix

* move linear cell construction to levelwise

* fix

* fix

* Port throttle and soundness fixes from master

- Fix soundness: pop incomplete lemma from m_lemmas on add_lemma failure
- Gracefully handle root atoms in add_lemma
- Throttle check_assignment with failure counter (decrement on success)
- Add arith.nl.nra_check_assignment parameter

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

* Add arith.nl.nra_check_assignment_max_fail parameter

Replace hardcoded failure threshold with configurable parameter (default 10).

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

* Add cha_abort_on_fail parameter to control failure counter decrement

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

* abort nla check_assignment after a set number of allowed failures

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* Add missing AST query methods to Java API (#8977)

* add Expr.isGround() to Java API

Expose Z3_is_ground as a public method on Expr. Returns true when the
expression contains no free variables.

* add Expr.isLambda() to Java API

Expose Z3_is_lambda as a public method on Expr. Returns true when the
expression is a lambda quantifier.

* add AST.getDepth() to Java API

Expose Z3_get_depth as a public method on AST. Returns the maximum
number of nodes on any path from root to leaf.

* add ArraySort.getArity() to Java API

Expose Z3_get_array_arity as a public method on ArraySort. Returns
the number of dimensions of a multi-dimensional array sort.

* add DatatypeSort.isRecursive() to Java API

Expose Z3_is_recursive_datatype_sort as a public method on
DatatypeSort. Returns true when the datatype refers to itself.

* add FPExpr.isNumeral() to Java API

Expose Z3_fpa_is_numeral as a public method on FPExpr. Returns true
when the expression is a concrete floating-point value.

* add isGroundExample test to JavaExample

Test Expr.isGround() on constants, variables, and compound
expressions.

* add astDepthExample test to JavaExample

Test AST.getDepth() on leaf nodes and nested expressions to verify
the depth computation.

* add arrayArityExample test to JavaExample

Test ArraySort.getArity() on single-domain and multi-domain array
sorts.

* add recursiveDatatypeExample test to JavaExample

Test DatatypeSort.isRecursive() on a recursive list datatype and a
non-recursive pair datatype.

* add fpNumeralExample test to JavaExample

Test FPExpr.isNumeral() on a floating point constant and a symbolic
variable.

* add isLambdaExample test to JavaExample

Test Expr.isLambda() on a lambda expression and a plain variable.

* change the default number of failures in check_assignment to 7

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* Fix high and medium priority API coherence issues (Go, Java, C++, TypeScript) (#8983)

* Initial plan

* Add missing API functions to Go, Java, C++, and TypeScript bindings

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>

* qf-s-benchmark: debug build + seq tracing + seq-fast/nseq-slow trace analysis (#8988)

* Initial plan

* Update qf-s-benchmark: debug build, seq tracing, trace analysis

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>

* disable linear approximation by default to check the merge

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* set check_assignment to true

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* fix restore_x by recalulating new column values

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* fix restore_x by recalulating new column values

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

* fix a memory leak

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>

---------

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Co-authored-by: ValentinPromies <44966217+ValentinPromies@users.noreply.github.com>
Co-authored-by: Valentin Promies <valentin.promies@rwth-aachen.de>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Angelica Moreira <48168649+angelica-moreira@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-03-15 06:13:04 -10:00
Lev Nachmanson
6d890fb026 Fix NLA optimization regression and relax restore_x
- Relax restore_x() to handle backup/current size mismatches: when
  backup is shorter (new columns added), call
  move_non_basic_columns_to_bounds() to find a feasible solution.
- Fix 100x performance regression in nonlinear optimization: save LP
  optimum before check_nla and return it as bound regardless of NLA
  result, so opt_solver::check_bound() can validate via full re-solve
  with accumulated NLA lemmas.
- Refactor theory_lra::maximize() into three helpers: max_with_lp(),
  max_with_nl(), and max_result().
- Add mk_gt(theory_var, impq const&) overload for building blockers
  from saved LP optimum values.
- Add BNH multi-objective optimization test (7/7 sat in <1s vs 1/7
  in 30s before fix).
- Add restore_x test for backup size mismatch handling.

Fixes #8890

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-10 16:38:08 -10:00
Lev Nachmanson
78fa6d5ee8 allow calling lp().restore_x() only in case the number of column in lp() remained the same: it might grow
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-03-09 10:51:31 -10:00
Lev Nachmanson
8a146a92ec fix: replace UNREACHABLE with VERIFY for non-COI constraint/monic violations in nra_solver
The NRA solver's check() uses cone-of-influence (COI) to select a subset
of constraints for nlsat. When nlsat returns l_true, the model is validated
against all constraints, but non-COI constraints can legitimately be
violated since nlsat only solved over the COI subset.

- Non-COI violations gracefully return l_undef (fallback to other strategies)
- COI violations still trigger an assertion (indicating a real nlsat bug)

Fixes #8883

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-06 08:54:34 -10:00
copilot-swe-agent[bot]
8e94cad8ab Fix static analysis findings: uninitialized vars, bitwise shift UB, garbage values
- nla_core.cpp: Initialize j = null_lpvar in is_octagon_term
- bit2int.cpp: Initialize sign_p, sign_n, sz_p, sz_n
- act_cache.cpp: Initialize debug vars to nullptr
- enum2bv_rewriter.cpp: Use unsigned literal in 1u << idx
- bit_matrix.cpp: Use unsigned literal in 1u << (n-1)
- bit_util.cpp: Guard against bit_shift == 0 in shl/shr
- mpff.cpp: Cast exp to unsigned before shifting
- sorting_network.h: Guard against bits == 0
- dl_sparse_table.h: Use >= 64 instead of == 64

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-03-02 00:13:55 +00:00
Lev Nachmanson
ffe29b1433 Fix #7951: add cancellation checks to polynomial gcd_prs and HNF computation
Add checkpoint() call in gcd_prs() main loop so polynomial GCD
computation respects rlimit/timeout. Add cancellation callback to
HNF calculation so it can be interrupted when the solver is cancelled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-27 10:26:28 -10:00
Copilot
20fef3f449
Eliminate unnecessary copy operations in function parameters and range-based loops (#8589) 2026-02-11 21:14:32 +00:00
Nuno Lopes
915ad35012 remove a few copies 2026-02-10 09:52:03 +00:00
Lev Nachmanson
f5b8dfc2f1 Revert "optionally throttle patch_basic_columns() especially useful in unsat cases"
This reverts commit bee2b45743.
2026-02-07 10:45:15 -10:00
Lev Nachmanson
73696725e4 Revert "try fixed int patch period"
This reverts commit 3e2027ec11.
2026-02-07 10:45:15 -10:00
Lev Nachmanson
3e2027ec11 try fixed int patch period
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-02-06 14:40:04 -10:00
Lev Nachmanson
bee2b45743 optionally throttle patch_basic_columns() especially useful in unsat cases
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-02-06 10:14:39 -10:00
Copilot
23c531a4c1
Remove redundant default constructors when they're the only constructor (#8461)
* Initial plan

* Modernize C++ constructors to use C++11 default member initialization - Phase 1

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

* Fix theory_pb.h struct definition - move reset() back inside struct

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

* Modernize C++ constructors to use C++11 default member initialization - Phase 2

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

* Fix opt_solver.h - revert rational initialization (complex type)

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

* Modernize C++ constructors to use C++11 default member initialization - Phase 3

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

* Fix sparse_matrix.h - explicitly initialize union member in default constructor

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

* Remove unnecessary default constructors when they're the only constructor

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>
2026-02-01 16:51:26 -08:00
Copilot
97bf2a5145
Remove redundant non-virtual destructors with = default (#8462)
* Initial plan

* Remove 6 non-virtual destructors with no code (= default)

Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com>
2026-02-01 15:22:58 -08:00
Lev Nachmanson
adac953e87 - When removing a fresh var xt, collect all fresh defs that transitively reference it
- Remove them all from m_fresh_k2xt_terms and m_row2fresh_defs
    - Mark rows containing those vars in m_changed_rows for recalculation
    - Move remove_irrelevant_fresh_defs() before the recalculate loop so all affected rows get recalculated

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-01-29 06:17:14 -10:00
Nikolaj Bjorner
8a0207700c
Fix implicit conversion warnings: use UINT_MAX instead of -1 for unsi… (#8342)
* Fix implicit conversion warnings: use UINT_MAX instead of -1 for unsigned variables

Replace implicit conversion from negative literal to unsigned type
with explicit UINT_MAX constant to eliminate compiler warnings.

Fixed 10 instances across 6 files:
- src/ast/rewriter/bv_rewriter.cpp: 1 instance
- src/ast/sls/sls_bv_tracker.h: 2 instances
- src/math/lp/dioph_eq.cpp: 3 instances
- src/math/lp/lp_primal_core_solver.h: 2 instances
- src/muz/transforms/dl_mk_array_instantiation.cpp: 1 instance
- src/muz/transforms/dl_mk_synchronize.cpp: 1 instance

These changes preserve the exact same runtime behavior (UINT_MAX
equals the wrapped value of -1 for unsigned types) while making
the code more explicit and warning-free.

* Update bv_rewriter.cpp

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-25 22:35:43 -08:00
Lev Nachmanson
b154667092 Fix memory leak in undo_fixed_column for big numbers
The undo_fixed_column struct is region-allocated via trail_stack, so its
destructor is never called. When m_fixed_val contains a big number (one
that doesn't fit in a small int), the heap-allocated memory for the mpq
numerator/denominator was never freed.

Fix by calling m_fixed_val.reset() in undo() to explicitly free the
heap memory before the region deallocates the struct.

Verified with macOS leaks tool:
- Before: 126 leaks (6048 bytes) on convert-jpg2gif-query-1584.smt2
- After: 0 leaks on normal completion, 10 leaks on timeout (unfinished trail)
2026-01-24 08:17:49 -10:00
Copilot
c392592831
[WIP] Find and update std::optional usage in code base (#8272)
* Initial plan

* Add try_get_value for std::map and use it in var_register.h and dioph_eq.cpp

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

* Add try_get_value overload for unordered_map with custom hash and use in lar_solver.cpp

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

* Remove redundant try_get_value template overload

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

* Remove std::map include and try_get_value overload from lp_utils.h

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-21 19:55:36 -08:00
Copilot
1bb471447e
Adopt std::optional for try_get_value and try_get_size functions (#8268)
* Initial plan

* Convert try_get_value and try_get_size to use std::optional

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

* Add unit tests for std::optional conversions and fix compilation error

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

* Address code review comments - improve readability and reduce code duplication

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-21 12:41:50 -08:00
Copilot
2e7b700769
Migrate codebase to std::string_view (except z3++.h) (#8266)
* Initial plan

* Update z3 codebase to use std::string_view (except z3++.h)

- Updated params.cpp/h to use string_view internally for parameter descriptions
- Updated trace.h/cpp to accept string_view for trace tag functions
- Updated hash.h/cpp to use string_view for string_hash function
- Updated all callers of string_hash to use string_view
- Properly handled nullptr to empty string_view conversions
- All tests passing

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

* Add missing string_view includes to headers

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-21 09:30:41 -08:00
Lev Nachmanson
d60373c5d5
Merge pull request #8218 from Z3Prover/copilot/fix-segmentation-fault-ufnira 2026-01-17 05:18:38 -10:00
copilot-swe-agent[bot]
522aa69e09 Fix segfault in dioph_eq.cpp by adding bounds check
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-17 00:04:21 +00:00
Copilot
36323f723b
Fix 13 compiler warnings: sign-comparison and unused parameters (#8215)
* Initial plan

* Fix 13 compiler warnings: sign-comparison and unused parameters

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-16 16:00:42 -08:00
Copilot
2436943794
Standardize for-loop increments to prefix form (++i) (#8199)
* Initial plan

* Convert postfix to prefix increment in for loops

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

* Fix member variable increment conversion bug

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

* Update API generator to produce prefix increments

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-14 19:55:31 -08:00
Copilot
7377d28c30
Replace empty destructors with = default for compiler optimization (#8189)
* Initial plan

* Replace empty destructors with = default

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-13 10:50:10 -08:00
Copilot
4d188f07e9
Replace custom util/optional with std::optional (#8162)
* Initial plan

* Replace optional with std::optional in source files

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

* Fix array_map contains() and remove optional_benchmark test

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

* Address code review feedback - simplify array_map and test

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-11 19:47:39 -08:00
Copilot
31122b0c10
Adopt C++17 structured bindings for map/pair iteration (#8159)
* Initial plan

* Adopt structured bindings for map iteration

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

* Fix DEBUG_CODE macro issue with structured bindings

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2026-01-11 17:44:12 -08:00
Lev Nachmanson
623b32239c when deleting the last row from m_e_matrix go over fresh variables defined for this row and mark the rows depending on them as changed
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-01-02 11:56:35 -10:00
Lev Nachmanson
918722d2f6 add a check in entry_invariant()
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-01-02 10:54:36 -10:00
Lev Nachmanson
17dffc67c9 catch a conflict with a fractional sum of fixed variables in a term
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-12-30 16:09:35 -10:00
Lev Nachmanson
58462938fa cosmetics
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-12-30 16:09:35 -10:00
Nikolaj Bjorner
c12425c86f fix #8099 (again)
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2025-12-25 14:16:54 -08:00
Lev Nachmanson
ce2405aab6 assert entry_invariant only when all changes are done
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2025-12-25 11:33:32 -10:00
Nikolaj Bjorner
60926e0347 fix #8092
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2025-12-16 15:49:49 -08:00
Nikolaj Bjorner
a5488cf6e7 fix #8054
inherit denominators when evaluating polynomials
2025-11-30 07:51:06 -08:00
Nikolaj Bjorner
62b3668beb remove set cardinality operators from array theory. Make final-check use priority levels
Issue #7502 shows that running nlsat eagerly during final check can block quantifier instantiation.
To give space for quantifier instances we introduce two levels for final check such that nlsat is only applied in the second and final level.
2025-11-26 15:35:19 -08:00
Nikolaj Bjorner
d1272defeb fix warnings in nla_pp
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2025-11-25 21:48:23 -08:00