← Adversarial Math From First Principles

Constraints and Models with Z3

Z3 as a satisfiability checker for encoded nonlinear real arithmetic: the negated-goal method, its three outcomes, and why unsat is a fact about one formula, not a theorem.

A solver says unsat. What has been shown?

Not “the theorem is true.” What has been shown is that one specific formula has no model: the conjunction of the recorded assumptions and the negation of the goal. If that formula is the wrong encoding of the claim, unsat is a true fact about the wrong formula. The evidence policy states the rule: “Interpret Z3 unsat only as unsatisfiability of the recorded negation and assumptions.”

Z3 is an SMT solver. Here it is used to decide satisfiability of encoded nonlinear real-arithmetic formulas. Its nlsat engine is designed as a complete decision procedure for quantifier-free polynomial real arithmetic, but that is not the same as handling arbitrary nonlinear arithmetic (transcendental terms, for example). Z3 can still return unknown, and the engine does not check an unsat certificate.

The engine uses Z3 in three ways: to support a claim when its negation is unsatisfiable, to refute a claim by finding a model of its negation, and to test whether a repair’s premise can be satisfied at all. This chapter explains the method and its three outcomes. It builds on Chapter 3 and Chapter 5.

Where Z3 is used

Claim Z3’s role Recorded status
lorentz-interval-invariance-1d-algebraic@1.0.0 The negated goal plus $\gamma^2(1-v^2)=1$ is unsat computation_verified_within_stated_domain
incorrect-transform-preserves-interval@1.0.0 Search for a model of the negation; sat, then re-evaluate refuted_by_valid_counterexample
pythagorean-coordinate-2d@1.0.0 The negated goal plus $\text{dot}=0$ is unsat computation_verified_within_stated_domain
P7 repair premises Is the premise satisfiable? A: sat; C ($0=1$): unsat

The negated-goal method

To check “if $H$ then $G$”, ask Z3 for a model of $H \land \lnot G$:

unsat   ->  no assignment satisfies H and violates G          (supports the claim)
sat     ->  here is an assignment satisfying H and violating G (a candidate witness)
unknown ->  the solver gave up

For the algebraic Lorentz claim, the adapter declares four reals, adds γ·γ·(1 − v·v) == 1, adds transformed != original and calls check(). Executed:

with the gamma hypothesis:     unsat
without the gamma hypothesis:  sat,  model  v = 0, t = 0, gamma = 0, x = -1

The second line is worth a minute. With $\gamma=0$, $t=0$, $v=0$ and $x=-1$, the boosted interval is $0^2-0^2=0$, while $t^2-x^2=-1$. So the hypothesis is doing real work: remove it, and Z3 produces a concrete model in a fraction of a second. This is the solver’s version of the hidden-assumption test from Chapter 2.

Three outcomes, three statuses

The adapter classifies the outcome in one small function, and its design is the point of the chapter:

Z3 result on the negated claim Evidence status Execution status
unsat computation_verified_within_stated_domain succeeded
sat inconclusive failed
unknown inconclusive unsupported

A sat on the negated claim is not recorded as a refutation. The adapter’s summary says: “Z3 found a model for the negated encoding; the encoding requires audit.” The claim was expected to hold, so a model of its negation means either that the claim is false or that the encoding is wrong. The engine refuses to guess which, and sends the result to a person. Refutation is a separate path with its own validation, used for claims known to be negative controls (Chapter 5).

Z3 as a refuter

For the false shear, the counterexample path adds search constraints ($-1< v<1$, $v\neq0$, $t\neq0$, transformed $\neq$ original), gets sat, takes the model, re-evaluates the residual with z3.simplify, and records refuted_by_valid_counterexample only if the residual is nonzero. The recorded witness is $t=-1$, $x=0$, $v=1/2$, with residual $-1/4$. A sat whose model fails re-evaluation is inconclusive. An unsat here is also inconclusive: “no counterexample under the encoded search constraints.”

Z3 as a check on premises

The repair work (the P7 phase) uses sat and unsat for a different job. A repair’s premise must be satisfiable, or the repair is vacuous (Chapter 27). For Candidate C, whose premise is $0=1$, Z3 returns unsat, and that is the engine’s evidence that the premise is impossible.

Here unsat is not support for a claim. It is a reason to reject. The same solver answer carries opposite meaning depending on which formula was asked, which is why every result stores its inputs (the assumptions and the negated goal) next to the outcome.

What the encoding leaves out

The adapter’s recorded limitations list the gaps:

  • “Unsat applies only to the exact nonlinear-real-arithmetic encoding.”
  • “This is a solver result, not a proof reconstructed in Lean or Rocq.”
  • “Z3’s encoding excludes square root and the physical interpretation of gamma.”

The last item is why the Z3 result is for the algebraic claim, while SymPy and the kernel bridges cover the physical one. Z3 never sees a square root. It reasons about a real $\gamma$ constrained by a polynomial equation, which is exactly the algebraic claim and nothing more.

What this establishes

Z3 is strongest as a witness-finder: a sat model checked by substitution is a small certificate anyone can verify. It is weaker as a prover. The engine does not check an unsat certificate; it takes the solver’s word, within the encoding, and labels the result computation_verified_within_stated_domain, one rung below a kernel proof. The hand check for the refutation is the substitution in Chapter 5.

Z3 and the kernels agree on the algebraic claim, but as Chapter 6 warned, agreement is not an argument. Both work from statements written by the same project, so if the statement is wrong, they agree on the wrong thing. That is why the R3 audit compares the statements structurally (Chapter 12).

Try it yourself

uv run python content/examples/math/tool-chapters/ch09_10_sympy_z3_demo.py

(Download the script.) Expect unsat with the gamma hypothesis and sat without it, with the model above. Z3 may return a different model on another version; the chapter relies only on the outcome.

Seeded error. Weaken the hypothesis to γ·γ·(1 − v·v) >= 1 in a scratch copy and rerun. Executed on 2026-11-09 with Z3 5.3.1, using ch05_10_18_22_24_checks.py:

ch10 weakened hypothesis negation: sat
ch10 weakened model: [x = -1, t = 0, gamma = -2, v = 0]

The weakened hypothesis leaves room for a model, so the negation is satisfiable. The original hypothesis is doing real work. The model is a candidate witness, not a refutation, until it is interpreted and re-evaluated.

Exercise. Check the weakened model by hand. Does it satisfy $\gamma^2(1-v^2)\ge1$? What are the boosted and original intervals? (Answer: $\gamma^2(1-v^2)=4\ge1$; $t'=0$ and $x'=2$, so the boosted interval is $-4$, while the original is $-1$.)

Open questions.

  1. Should a sat on a negated claim ever be recorded as a refutation without re-evaluation? Today the answer is no, and the result goes to audit.
  2. Can the project check an unsat certificate (a proof object) and upgrade the status? That would move Z3 evidence toward the kernel rung.
  3. Solver outcomes can vary with version and heuristics. Which of the P6 and P7 Z3 results would break if Z3 answered unknown on a harder instance, and does the dossier degrade gracefully? (By design it should: unknown is inconclusive.)

Evidence record

From the accepted R2 report, Z3 5.3.1: math01-z3-algebraic-invariance-v1 is succeeded, computation_verified_within_stated_domain; math01-z3-incorrect-transform-counterexample-v1 is refuted_by_valid_counterexample. P6 adds two Z3 checks (the coordinate unsat and the false-claim witness). P7 adds four: candidate A premise sat, candidate B negation unsat, candidate C premise unsat, and the overfit witness under the patch sat.

Sources

The wider theory of real-closed-field decision procedures is not otherwise cited. In the repository: src/math_engine/adapters/z3_adapter.py and docs/methodology/evidence-policy.md.