primarily authored by Claude Opus 4.6, updated with review feedback
Feature: Nonlinear Arithmetic for HOL4
Problem
HOL4 handles polynomial equalities via Gröbner bases (REAL_RING, NUM_RING, INT_RING) and linear inequality reasoning via REAL_ARITH / ARITH_TAC / COOPER_TAC. But there is no automated support for nonlinear inequalities:
(* These all fail with "linear_ineqs: no contradiction" *)
REAL_ARITH ``x pow 2 >= &0``
REAL_ARITH ``x >= &5 /\ y >= &5 ==> x * y >= &25``
REAL_ARITH ``&2 * x * y <= x pow 2 + y pow 2`` (* AM-GM *)
Users must currently manually decompose these into sum-of-squares form by hand.
Proposed Solution: Layered Approach
A three-phase approach, where each phase is independently useful and builds on the last:
- Phase 0: Heuristic nonlinear prover — no external dependencies (~500 LOC)
- Phase 1: SOS via CSDP with certificate caching (~1100 LOC)
- Phase 2: Univariate Sturm sequences — complete for 1 variable (~2000 LOC)
Phase 0: Heuristic Nonlinear Prover (no external dependencies)
The key insight is that HOL4 already has the positivstellensatz certificate verifier (hol_of_positivstellensatz in RealArith0.sml) and the GEN_REAL_ARITH framework. What's missing is a certificate finder for nonlinear goals. Phase 0 adds simple heuristic strategies that find certificates for common patterns without any external solver:
Strategy 1 — Linearization (adapted from Coq micromega's nra): Abstract nonlinear monomials as fresh variables, derive bounds from hypotheses, then call the existing REAL_LINEAR_PROVER. For example, given x ≥ 5 ∧ y ≥ 5 ⊢ x*y ≥ 25: introduce z = x*y, derive z ≥ 5*5 = 25 from the hypothesis bounds, then the goal is linear in z.
Strategy 2 — Simple certificate patterns: Try basic positivstellensatz certificate shapes:
Square(t) for goals like t² ≥ 0
Sum(Square(t₁), Square(t₂)) for t₁² + t₂² ≥ 0
Product(Axiom_le i, Axiom_le j) for product-of-nonneg goals
Strategy 3 — Multiplication of hypotheses: Given hypotheses h₁ ≥ 0, ..., hₙ ≥ 0, try multiplying pairs/triples and adding to see if the goal follows by linear reasoning. This is what enumerate_products does in HOL-Light's SOS but with a bounded search.
Strategy 4 — Exact rational Cholesky for quadratic forms: For a goal p(x₁,...,xₙ) ≥ 0 where p has degree 2, write p = vᵀMv where v = [1, x₁, ..., xₙ]. Compute M by coefficient matching (exact rationals). Attempt exact rational Cholesky decomposition of M. If M = LLᵀ succeeds, read off the SOS decomposition directly — no SDP, no numerics, no rounding. This handles all nonneg quadratic forms: e.g. x² - xy + y² ≥ 0 → Cholesky → (x - y/2)² + 3y²/4 ≥ 0.
Strategy 5 — Verify-then-search with Z3/cvc5: If HolSmt is available, send the goal to Z3/cvc5 in oracle mode first. If it returns SAT (goal is invalid), fail immediately — don't waste time searching for a certificate that doesn't exist. If it returns UNSAT (goal is valid), run the heuristic search with higher degree bounds since we know a certificate exists. If heuristics find a certificate, produce a kernel-verified theorem (no oracle tag). If heuristics fail despite knowing the goal is valid, fall back to oracle-tagged theorem. This turns HolSmt from "alternative" into "complement."
This phase handles goals like x² ≥ 0, x ≥ 0 ∧ y ≥ 0 ⟹ x*y ≥ 0, x ≥ 5 ∧ y ≥ 5 ⟹ x*y ≥ 25, 2*x*y ≤ x² + y², and all nonneg quadratic forms — with no external dependencies.
Phase 1: SOS via SDP (CSDP)
For goals that heuristics can't handle, use the full Positivstellensatz approach from HOL-Light's sos.ml:
- Normalize all terms to canonical polynomial form (via existing
REAL_POLY_CONV)
- Compute the Newton polytope to minimize the monomial basis
- Formulate "this polynomial is non-negative" as a semidefinite program (SDP)
- Call CSDP (external, untrusted SDP solver) to find a numerical solution
- Round the floating-point result to exact rational coefficients
- Build a
positivstellensatz certificate (Square, Sum, Product, ...)
- Verify the certificate in HOL4's kernel via
hol_of_positivstellensatz
Key property: CSDP is untrusted. It only finds certificates. Verification is purely algebraic, inside the HOL4 kernel. A buggy solver can cause the tactic to fail, never to produce an unsound theorem.
Certificate caching (following Isabelle's pattern): When CSDP finds a certificate, print it in a serialized form. Users can then embed the certificate string in their proof script (e.g., REAL_SOS_CERT "...") so the proof replays without CSDP. This means:
- Development time: need CSDP installed to discover proofs
- CI / distribution: certificates are self-contained, no CSDP needed
- Proofs are reproducible and deterministic
Phase 2: Univariate Sturm Sequences
For completeness on univariate goals, formalize Sturm's theorem in HOL4. This gives a complete decision procedure for sentences of univariate real arithmetic.
HOL4 already has: polynomial evaluation, IVT (POLY_IVT_POS), root finiteness (POLY_ROOTS_FINITE), squarefree decomposition (POLY_SQUAREFREE_DECOMP_ORDER). What's needed:
- Sturm sequence (pseudo-remainder sequence) computation
- Sign variation counting
- The Sturm-Tarski theorem connecting sign variations to root counts
- Root isolation
Architecture follows Li/Paulson (Isabelle): the actual root isolation can be done by an untrusted oracle (even a small SML implementation of ~300 LOC), with the kernel verifying that the sample points cover all sign-invariant regions via Sturm evaluation.
Existing Infrastructure
Most of the infrastructure has already been ported from HOL-Light:
| Component |
Source |
HOL4 Status |
| Gröbner bases |
grobner.ml |
✅ Grobner.sml |
| Polynomial normalization |
normalizer.ml |
✅ Normalizer.sml |
positivstellensatz type |
realarith.ml |
✅ RealArith0.sml |
Certificate verifier (hol_of_positivstellensatz) |
realarith.ml |
✅ RealArith0.sml (handles Square, Sum, Product, Eqmul, Axiom_le, etc.) |
GEN_REAL_ARITH framework |
realarith.ml |
✅ RealArith.sml (takes a prover function as parameter) |
| Polynomial theory (IVT, roots, order, squarefree) |
— |
✅ polyScript.sml |
| Heuristic nonlinear prover |
— |
❌ Phase 0 |
| SOS core (SDP formulation + CSDP) |
sos.ml |
❌ Phase 1 |
| Sturm sequences / root isolation |
— |
❌ Phase 2 |
Architecture
All phases plug into the existing GEN_REAL_ARITH framework, cascading from fast/simple to slow/powerful:
GEN_REAL_ARITH (existing framework)
│
├── REAL_LINEAR_PROVER (existing, handles linear goals)
│
└── REAL_NONLINEAR_PROVER (new, cascading):
│
├── 1. Linearization (abstract monomials → linear) [Phase 0]
├── 2. Simple certificate search (squares, products) [Phase 0]
├── 3. SOS via CSDP (full Positivstellensatz) [Phase 1]
└── 4. Univariate Sturm (if single variable) [Phase 2]
│
└── hol_of_positivstellensatz (existing, trusted verifier)
Proposed API
(* Phase 0: no external dependencies *)
val NLA_TAC : tactic (* heuristic nonlinear arithmetic *)
val NLA_PROVE : term -> thm
(* Phase 1: requires CSDP for certificate discovery *)
val REAL_SOS : term -> thm (* nonlinear real arithmetic via SOS *)
val REAL_SOS_TAC : tactic
val REAL_SOS_CERT : string -> term -> thm (* replay cached certificate, no CSDP needed *)
val INT_SOS : term -> thm (* integer via embedding into reals *)
val SOS_RULE : term -> thm (* natural numbers via NUM_TO_INT_CONV *)
val SOS_CONV : conv (* prove p >= 0 by SOS decomposition *)
val PURE_SOS : term -> thm (* pure SOS, no hypothesis handling *)
(* Phase 2 *)
val STURM_TAC : tactic (* univariate decision procedure *)
External Dependencies
- Phase 0: None
- Phase 1: CSDP —
coinor-csdp on Debian/Ubuntu. Communication via temp files in SDPA format. Configurable via HOL4_CSDP_EXECUTABLE env var. With certificate caching (REAL_SOS_CERT), CSDP is only needed at proof development time, not for replay.
- Phase 2: None (or optionally Z3/cvc5 as untrusted oracle for faster root isolation)
Example Goals
(* Basic positivity *)
REAL_SOS ``x pow 2 >= &0``
REAL_SOS ``x pow 2 + y pow 2 >= &0``
REAL_SOS ``x pow 4 + y pow 4 + z pow 4 >= &0``
(* With hypotheses *)
REAL_SOS ``x >= &5 /\ y >= &5 ==> x * y >= &25``
REAL_SOS ``x >= &0 /\ y >= &0 ==> x * y >= &0``
(* Classic inequalities *)
REAL_SOS ``&2 * x * y <= x pow 2 + y pow 2`` (* AM-GM *)
REAL_SOS ``x pow 6 + y pow 6 + z pow 6
>= &3 * x pow 2 * y pow 2 * z pow 2`` (* Schur-like *)
PURE_SOS ``x pow 4 + y pow 4 + z pow 4
- &4 * x * y * z + x + y + z + &3 >= &1 / &7``
(* Integer / Natural number *)
INT_SOS ``(x:int) * x >= 0``
SOS_RULE ``x >= 5 /\ y >= 5 ==> x * y >= 25``
SOS_RULE ``n * n + n >= n``
(* From HOL-Light's test suite *)
REAL_SOS ``&2 * x pow 4 + &2 * x pow 3 * y
- x pow 2 * y pow 2 + &5 * y pow 4 >= &0``
Completeness Properties
| Phase |
Domain |
Completeness |
Notes |
| 0 |
ℝ (heuristic) |
Incomplete |
Handles common patterns: squares, products of nonneg, linearizable goals |
| 1 |
ℝ (REAL_SOS) |
Theoretically complete |
By Stengle's Positivstellensatz. Practically limited by SDP precision and degree bound. |
| 1 |
ℤ (INT_SOS) |
Incomplete |
Sound: embeds into reals. Fails when integrality matters. |
| 1 |
ℕ (SOS_RULE) |
Incomplete |
Via NUM_TO_INT_CONV → INT_SOS. ℕ subtraction/DIV/MOD handled by NUM_SIMPLIFY_CONV preprocessing. |
| 2 |
ℝ univariate |
Complete |
Sturm-Tarski theorem gives a decision procedure for univariate real arithmetic. |
Connection to HolSmt / cvc5 Alethe Replay
The cvc5 Alethe proof replay work (#1829) falls back to oracle for nonlinear theory lemmas (la_generic only handles linear arithmetic). Even Phase 0 heuristics would allow kernel-verified replay of many nonlinear theory lemma steps that currently require oracle tags.
Alternatives Considered
| Approach |
Pros |
Cons |
Verdict |
| SMT oracle (Z3 nlsat / cvc5 CAD) |
Complete for QF_NRA, no new code |
Oracle-tagged theorems, no kernel verification |
Complementary — useful for finding goals are valid, but SOS/heuristics verify in kernel |
| Implementing Z3's nlsat in HOL4 tactics |
Complete, no external deps |
nlsat is a search procedure, not certificate-based; doesn't fit the trusted-kernel architecture well. Would need ~5000+ LOC of verified search. |
Not practical as first step |
| Full multivariate CAD (Collins-style) |
Complete decision procedure |
Nobody has formalized this in any prover. BKR hybrid (Isabelle) took ~11K LOC of Isabelle theory. |
Future work; univariate CAD (Phase 2) is achievable |
| Interval arithmetic |
Simple, no dependencies |
Very incomplete, ground terms only |
Useful complement but not a substitute |
| Manual decomposition |
Works today |
Requires user expertise, tedious |
What users do now; we're automating this |
Why this layered approach: Phase 0 (heuristics) gives immediate value with zero dependencies. Phase 1 (SOS) handles harder goals with an optional external solver. Phase 2 (Sturm) gives completeness for univariate problems. Each phase is independently useful.
Why not Z3's nlsat directly? @someplaceguy suggested implementing Z3's nonlinear algorithm in HOL4 tactics. Z3's nlsat uses MCSAT + CAD projections — a search procedure that incrementally builds models and generates conflict clauses. This doesn't naturally produce compact checkable certificates the way SOS does. The Positivstellensatz certificate architecture (untrusted finder → trusted kernel checker) is a better fit for theorem provers, and is what HOL-Light, Isabelle, and Coq all use.
Implementation Details
positivstellensatz Constructor Access
The SOS and heuristic code must construct certificates using Square, Sum, Product, Axiom_le, etc. Currently these constructors are abstract (not exported from RealArith0.sig). Options:
- (a) Export the datatype constructors from
RealArith0.sig
- (b) Add smart constructor functions (e.g.,
mk_Square : term -> positivstellensatz)
- (c) Place the nonlinear prover code inside a structure that has access (same compilation unit)
Natural Number Ergonomics
Most HOL4 users write over ℕ. The ℕ → ℤ → ℝ → SOS → back chain involves NUM_TO_INT_CONV and NUM_SIMPLIFY_CONV (already in Grobner.sml) to handle truncating subtraction, DIV, MOD, PRE, EVEN/ODD before converting to real arithmetic.
Benchmarks
Test cases should come from:
- HOL-Light's
sos.ml test suite (~50 examples)
- SMT-LIB QF_NRA benchmarks (adapted)
- Real HOL4 proofs that currently use oracle-mode SMT for nonlinear goals
- Coq micromega test suite
Questions
-
File placement: src/real/sosLib.{sig,sml} alongside RealField? Or a new src/real/sos/ directory?
-
positivstellensatz constructors: Which approach for accessing the abstract type? (see above)
-
Integration with REAL_ARITH: Should REAL_ARITH automatically try nonlinear heuristics as a fallback when linear arithmetic fails? Or keep them strictly separate? (HOL-Light keeps them separate; Coq's auto doesn't call nra)
-
CI: Phase 0 tests need no special setup. Phase 1 (CSDP) tests should gate on availability like HolSmt gates on Z3/cvc5. Phase 2 tests need no special setup.
-
Naming: sosLib (algorithm name) vs nlrealLib (domain name) vs nonlinearLib? The Phase 0 heuristics aren't really "SOS" so a broader name might be better.
primarily authored by Claude Opus 4.6, updated with review feedback
Feature: Nonlinear Arithmetic for HOL4
Problem
HOL4 handles polynomial equalities via Gröbner bases (
REAL_RING,NUM_RING,INT_RING) and linear inequality reasoning viaREAL_ARITH/ARITH_TAC/COOPER_TAC. But there is no automated support for nonlinear inequalities:Users must currently manually decompose these into sum-of-squares form by hand.
Proposed Solution: Layered Approach
A three-phase approach, where each phase is independently useful and builds on the last:
Phase 0: Heuristic Nonlinear Prover (no external dependencies)
The key insight is that HOL4 already has the
positivstellensatzcertificate verifier (hol_of_positivstellensatzinRealArith0.sml) and theGEN_REAL_ARITHframework. What's missing is a certificate finder for nonlinear goals. Phase 0 adds simple heuristic strategies that find certificates for common patterns without any external solver:Strategy 1 — Linearization (adapted from Coq micromega's
nra): Abstract nonlinear monomials as fresh variables, derive bounds from hypotheses, then call the existingREAL_LINEAR_PROVER. For example, givenx ≥ 5 ∧ y ≥ 5 ⊢ x*y ≥ 25: introducez = x*y, derivez ≥ 5*5 = 25from the hypothesis bounds, then the goal is linear inz.Strategy 2 — Simple certificate patterns: Try basic
positivstellensatzcertificate shapes:Square(t)for goals liket² ≥ 0Sum(Square(t₁), Square(t₂))fort₁² + t₂² ≥ 0Product(Axiom_le i, Axiom_le j)for product-of-nonneg goalsStrategy 3 — Multiplication of hypotheses: Given hypotheses
h₁ ≥ 0, ..., hₙ ≥ 0, try multiplying pairs/triples and adding to see if the goal follows by linear reasoning. This is whatenumerate_productsdoes in HOL-Light's SOS but with a bounded search.Strategy 4 — Exact rational Cholesky for quadratic forms: For a goal
p(x₁,...,xₙ) ≥ 0where p has degree 2, write p = vᵀMv where v = [1, x₁, ..., xₙ]. Compute M by coefficient matching (exact rationals). Attempt exact rational Cholesky decomposition of M. If M = LLᵀ succeeds, read off the SOS decomposition directly — no SDP, no numerics, no rounding. This handles all nonneg quadratic forms: e.g.x² - xy + y² ≥ 0→ Cholesky →(x - y/2)² + 3y²/4 ≥ 0.Strategy 5 — Verify-then-search with Z3/cvc5: If HolSmt is available, send the goal to Z3/cvc5 in oracle mode first. If it returns SAT (goal is invalid), fail immediately — don't waste time searching for a certificate that doesn't exist. If it returns UNSAT (goal is valid), run the heuristic search with higher degree bounds since we know a certificate exists. If heuristics find a certificate, produce a kernel-verified theorem (no oracle tag). If heuristics fail despite knowing the goal is valid, fall back to oracle-tagged theorem. This turns HolSmt from "alternative" into "complement."
This phase handles goals like
x² ≥ 0,x ≥ 0 ∧ y ≥ 0 ⟹ x*y ≥ 0,x ≥ 5 ∧ y ≥ 5 ⟹ x*y ≥ 25,2*x*y ≤ x² + y², and all nonneg quadratic forms — with no external dependencies.Phase 1: SOS via SDP (CSDP)
For goals that heuristics can't handle, use the full Positivstellensatz approach from HOL-Light's
sos.ml:REAL_POLY_CONV)positivstellensatzcertificate (Square,Sum,Product, ...)hol_of_positivstellensatzKey property: CSDP is untrusted. It only finds certificates. Verification is purely algebraic, inside the HOL4 kernel. A buggy solver can cause the tactic to fail, never to produce an unsound theorem.
Certificate caching (following Isabelle's pattern): When CSDP finds a certificate, print it in a serialized form. Users can then embed the certificate string in their proof script (e.g.,
REAL_SOS_CERT "...") so the proof replays without CSDP. This means:Phase 2: Univariate Sturm Sequences
For completeness on univariate goals, formalize Sturm's theorem in HOL4. This gives a complete decision procedure for sentences of univariate real arithmetic.
HOL4 already has: polynomial evaluation, IVT (
POLY_IVT_POS), root finiteness (POLY_ROOTS_FINITE), squarefree decomposition (POLY_SQUAREFREE_DECOMP_ORDER). What's needed:Architecture follows Li/Paulson (Isabelle): the actual root isolation can be done by an untrusted oracle (even a small SML implementation of ~300 LOC), with the kernel verifying that the sample points cover all sign-invariant regions via Sturm evaluation.
Existing Infrastructure
Most of the infrastructure has already been ported from HOL-Light:
grobner.mlGrobner.smlnormalizer.mlNormalizer.smlpositivstellensatztyperealarith.mlRealArith0.smlhol_of_positivstellensatz)realarith.mlRealArith0.sml(handlesSquare,Sum,Product,Eqmul,Axiom_le, etc.)GEN_REAL_ARITHframeworkrealarith.mlRealArith.sml(takes a prover function as parameter)polyScript.smlsos.mlArchitecture
All phases plug into the existing
GEN_REAL_ARITHframework, cascading from fast/simple to slow/powerful:Proposed API
External Dependencies
coinor-csdpon Debian/Ubuntu. Communication via temp files in SDPA format. Configurable viaHOL4_CSDP_EXECUTABLEenv var. With certificate caching (REAL_SOS_CERT), CSDP is only needed at proof development time, not for replay.Example Goals
Completeness Properties
NUM_SIMPLIFY_CONVpreprocessing.Connection to HolSmt / cvc5 Alethe Replay
The cvc5 Alethe proof replay work (#1829) falls back to oracle for nonlinear theory lemmas (
la_genericonly handles linear arithmetic). Even Phase 0 heuristics would allow kernel-verified replay of many nonlinear theory lemma steps that currently require oracle tags.Alternatives Considered
Why this layered approach: Phase 0 (heuristics) gives immediate value with zero dependencies. Phase 1 (SOS) handles harder goals with an optional external solver. Phase 2 (Sturm) gives completeness for univariate problems. Each phase is independently useful.
Why not Z3's nlsat directly? @someplaceguy suggested implementing Z3's nonlinear algorithm in HOL4 tactics. Z3's nlsat uses MCSAT + CAD projections — a search procedure that incrementally builds models and generates conflict clauses. This doesn't naturally produce compact checkable certificates the way SOS does. The Positivstellensatz certificate architecture (untrusted finder → trusted kernel checker) is a better fit for theorem provers, and is what HOL-Light, Isabelle, and Coq all use.
Implementation Details
positivstellensatz Constructor Access
The SOS and heuristic code must construct certificates using
Square,Sum,Product,Axiom_le, etc. Currently these constructors are abstract (not exported fromRealArith0.sig). Options:RealArith0.sigmk_Square : term -> positivstellensatz)Natural Number Ergonomics
Most HOL4 users write over ℕ. The ℕ → ℤ → ℝ → SOS → back chain involves
NUM_TO_INT_CONVandNUM_SIMPLIFY_CONV(already inGrobner.sml) to handle truncating subtraction,DIV,MOD,PRE,EVEN/ODDbefore converting to real arithmetic.Benchmarks
Test cases should come from:
sos.mltest suite (~50 examples)Questions
File placement:
src/real/sosLib.{sig,sml}alongside RealField? Or a newsrc/real/sos/directory?positivstellensatz constructors: Which approach for accessing the abstract type? (see above)
Integration with REAL_ARITH: Should
REAL_ARITHautomatically try nonlinear heuristics as a fallback when linear arithmetic fails? Or keep them strictly separate? (HOL-Light keeps them separate; Coq'sautodoesn't callnra)CI: Phase 0 tests need no special setup. Phase 1 (CSDP) tests should gate on availability like HolSmt gates on Z3/cvc5. Phase 2 tests need no special setup.
Naming:
sosLib(algorithm name) vsnlrealLib(domain name) vsnonlinearLib? The Phase 0 heuristics aren't really "SOS" so a broader name might be better.