Skip to content

Feature: Nonlinear Arithmetic (Sum-of-Squares) #1831

Description

@charles-cooper

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:

  1. Normalize all terms to canonical polynomial form (via existing REAL_POLY_CONV)
  2. Compute the Newton polytope to minimize the monomial basis
  3. Formulate "this polynomial is non-negative" as a semidefinite program (SDP)
  4. Call CSDP (external, untrusted SDP solver) to find a numerical solution
  5. Round the floating-point result to exact rational coefficients
  6. Build a positivstellensatz certificate (Square, Sum, Product, ...)
  7. 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: CSDPcoinor-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

  1. File placement: src/real/sosLib.{sig,sml} alongside RealField? Or a new src/real/sos/ directory?

  2. positivstellensatz constructors: Which approach for accessing the abstract type? (see above)

  3. 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)

  4. 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.

  5. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions