[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"OveUWA9ncl":3},"# sos\n\n[![CI](https://github.com/leanprover/sos/actions/workflows/ci.yml/badge.svg)](https://github.com/leanprover/sos/actions/workflows/ci.yml)\n\nHarrison's sum-of-squares decision procedure for nonlinear real\narithmetic, in Lean 4. Based on the design from\n[Harrison 2007 (TPHOLs)](https://link.springer.com/chapter/10.1007/978-3-540-74591-4_9).\n\n## Adding to your project\n\nAdd the following to your `lakefile.toml`:\n\n```toml\n[[require]]\nname = \"sos\"\ngit = \"https://github.com/leanprover/sos.git\"\nrev = \"main\"\n```\n\nOr, in a `lakefile.lean`:\n\n```lean\nrequire sos from git\n  \"https://github.com/leanprover/sos.git\" @ \"main\"\n```\n\nThen `import SOS` and use `by sos`. The system BLAS/LAPACK runtime must\nbe installed; see [Native dependency troubleshooting](#native-dependency-troubleshooting).\n\n## Status\n\nThe `by sos` tactic closes nonlinear-real-arithmetic goals end-to-end:\nreify the goal, encode an SDP, call CSDP, round the float Gram matrix\nto rationals, decompose via LDLᵀ + Lagrange four-square, and dispatch\nthe matching verifier-soundness lemma.\n\n## Examples\n\nA curated version of this section lives in\n[`SOSTest/Showcase.lean`](SOSTest/Showcase.lean), so `lake test`\nchecks that these public examples continue to elaborate.\n\n```lean\nimport SOS\n\n-- Cauchy–Schwarz (rank 1, deg 4, 4 vars)\nexample (a b c d : ℝ) :\n    0 ≤ (a^2 + b^2) * (c^2 + d^2) - (a*c + b*d)^2 := by sos\n\n-- Cyclic Schur, 3 vars\nexample (a b c : ℝ) : 0 ≤ a^2 + b^2 + c^2 - a*b - b*c - a*c := by sos\n\n-- AM ≥ GM squared\nexample (x y : ℝ) : 0 ≤ (x^2 + y^2)^2 - 4*x^2*y^2 := by sos\n\n-- Strict positivity, multivariate\nexample (x y : ℝ) : 0 \u003C x^2 + y^2 + 1 := by sos\n\n-- Infeasibility\nexample (x : ℝ) : ¬ (x^4 + 1 ≤ 0) := by sos\n\n-- Constrained\nexample (x : ℝ) (_h : 0 ≤ x) : 0 ≤ x^3 + x := by sos\nexample (x y : ℝ) (_hx : 0 ≤ x) (_hy : 0 ≤ y) :\n    0 ≤ x^2 + 2*x*y + y^2 := by sos\n\n-- Strict-inequality hypothesis (promoted to `0 ≤ x` via `le_of_lt`)\nexample (x : ℝ) (_h : 0 \u003C x) : 0 ≤ x^3 + x := by sos\n\n-- Equality constraint: discriminant of a real-rooted quadratic\nexample (a b c x : ℝ) (_h : a*x^2 + b*x + c = 0) :\n    0 ≤ b^2 - 4*a*c := by sos\n\n-- Discrete goal, lifted/refuted through ℝ\nexample : ∀ n : ℕ, n ≤ n * n := by sos\n\n-- Euclidean division over ℕ\nexample : ∀ a b : ℕ, b ≠ 0 → a = b * (a / b) + a % b := by sos\n```\n\n`by sos?` reports the witness it found as a `Try this:` suggestion\nthat you can paste back as a `sos_witness …` invocation, freezing the\nproof so it no longer depends on calling CSDP at compile time:\n\n```lean\nexample (x : ℝ) : 0 ≤ x^2 + 1 := by sos?\n-- Try this:\n--   [apply] sos_witness\n--     { sigmas := [([], { terms := [((1 : ℚ), CMvPolynomial.C (1 : ℚ)),\n--                                   ((1 : ℚ), CMvPolynomial.X 0)] })] }\n```\n\nWitness terms are `(c, p)` pairs interpreted as `c · p²`, with\n`0 ≤ c` enforced by `Certificate.checks`.\n\nAtoms are recovered as arbitrary `ℝ`-typed subterms (free variables,\nfunction applications, projections — anything the reifier doesn't\nrecognise as a known operator). Constraint hypotheses can come from\nthe local context or from `→`-introduced binders.\n\nThe Motzkin polynomial `x⁴y² + x²y⁴ + 1 - 3x²y²` is non-negative but\nnot a sum of squares (Hilbert 1888 / Motzkin 1967), so plain `by sos`\nhas no certificate to find and correctly fails, caught here by\n`fail_if_success`:\n\n```lean\nexample : True := by\n  fail_if_success\n    (have : ∀ x y : ℝ,\n        0 ≤ x^4 * y^2 + x^2 * y^4 + 1 - 3*x^2*y^2 := by sos)\n  trivial\n```\n\nOpting into the Positivstellensatz power refutation with\n`maxRefutationPower` closes it anyway — `by sos` negates the goal to\n`0 \u003C -M`, searches for `-M = σ₀ + σ₁·(-M)` (Harrison's\n`REAL_NONLINEAR_PROVER`), and recovers the exact rational certificate\nfrom CSDP's rank-deficient solution by facial reduction:\n\n```lean\nexample (x y : ℝ) : 0 ≤ x^4*y^2 + x^2*y^4 + 1 - 3*x^2*y^2 := by\n  sos (config := { maxRefutationPower := 1 })\n```\n\nThis is off by default because each power is a family of\ngrowing-degree CSDP solves whose required degree is not known in\nadvance; see [Scope and limits](#scope-and-limits).\n\nThe soundness lemmas reduce to `IsSumSq.nonneg` (Mathlib) once the\ngoal has been transported through the `aeval` ring-hom on CompPoly's\n`CMvPolynomial n ℚ`. Two design points worth flagging, both following\nHarrison's [TPHOLs 2007 paper]\n(https://link.springer.com/chapter/10.1007/978-3-540-74591-4_9):\n\n- **`min tr(X)` cost matrix.** CSDP's interior-point step has no\n  preferred direction on a singleton boundary feasible set, so we\n  give it the trace objective Harrison reports works empirically.\n- **Zero-pivot LDLᵀ.** Rank-deficient SOS Grams (`(x + y)²` has\n  Gram `[[1,1],[1,1]]`, rank 1) require the \"completing the square\"\n  routine to accept a zero pivot when the residual column is also\n  zero. Our `SOS.LDL.decompose` does this; `LDL.reconstruct` already\n  drops the zero-D contributions.\n\n## Implementation notes\n\nThis tactic depends on\n[`Verified-zkEVM/CompPoly`](https://github.com/Verified-zkEVM/CompPoly)\nfor a kernel-decidable computational multivariate-polynomial type\n(`CMvPolynomial n ℚ`), which is what the verifier reduces certificate\nchecks against. CompPoly itself depends on Mathlib. As a consequence,\n`sos` is a downstream library and cannot be migrated into Mathlib\nitself unless CompPoly is upstreamed first.\n\n## Scope and limits\n\n- **Rational certificates only.** Witnesses live in\n  `CMvPolynomial n ℚ` throughout. CSDP returns floats, which we round\n  against a denominator schedule (Harrison's `find_rounding` exactly:\n  the integers `[1..31]`, then the powers of two `2^5 … 2^66`, capped\n  per-call by `Config.maxRoundingDenomLog2`, the base-2 log of the cap,\n  default `66`) and decompose via rational LDLᵀ. Each σ-block is a\n  weighted sum of squares `Σᵢ cᵢ · pᵢ²` with `cᵢ ∈ ℚ≥0`; the\n  non-negativity is `decide +kernel`-checked at certificate time.\n  There is no support for algebraic-extension coefficients — a goal\n  whose only SOS witness involves `√2` (or any other irrational) is\n  out of reach by construction.\n\n- **Putinar form, with hypotheses as multipliers.** A certificate is\n  `target = σ₀ + Σᵢ σᵢ · gᵢ` with each `σᵢ` an SOS, where the `gᵢ`\n  are non-negativity hypotheses pulled from `intro`-binders and the\n  local context. Recognised constraint shapes are `0 ≤ g`, `g ≤ 0`\n  (encoded as `0 ≤ −g`), and `0 \u003C g` (used via `le_of_lt`).\n  Unconstrained goals reduce to `target = σ₀`. Strict positivity\n  `0 \u003C p` is handled by an LP-slack maximisation: one extra\n  decision variable `λ ≥ 0` enters the SDP via the constant-monomial\n  equality, CSDP maximises it to discover the largest admissible\n  slack `λ*`, and then `ε = 2^-k` near `λ*` is fed to the standard\n  feasibility pipeline to produce the verifiable certificate.\n  Infeasibility uses `target = −1`.\n\n- **Single fixed relaxation level by default.** Multiplier basis sizes\n  are set once from a degree bound `D = max(deg(target), maxᵢ deg(gᵢ))`:\n  the σ₀ basis is monomials up to `⌈D/2⌉`, and each σᵢ basis is monomials\n  up to `⌈max(0, D − deg(gᵢ))/2⌉`. The default search runs no hierarchy\n  walk that bumps the relaxation order on failure, so a goal needing a\n  higher order is left open.\n\n- **Non-SOS non-negative polynomials, opt-in.** A polynomial that is\n  non-negative but not a sum of squares (Motzkin\n  `x⁴y² + x²y⁴ + 1 − 3x²y²` is the canonical example) has no direct\n  certificate, so the default search fails. Setting\n  `maxRefutationPower := k` enables Harrison's `REAL_NONLINEAR_PROVER`\n  power refutation: for `i = 1 … k` it searches for a certificate of\n  `−(−p)^i` against `{−p ≥ 0}` (negate the goal, then refute `0 \u003C −p`),\n  and recovers the exact rational certificate from CSDP's rank-deficient\n  boundary solution by **facial reduction** — rationalising the\n  null-space projector of the float Gram and imposing it as exact linear\n  constraints. This is off by default: each power is a family of\n  growing-degree CSDP solves, the required degree is unknown a priori,\n  and the recovery adds a symmetric eigendecomposition per block.\n\n- **Search failure is not a soundness failure.** When CSDP returns an\n  unusable status, when no rounding denominator validates, or when\n  LDLᵀ reconstruction can't close the certificate, `by sos` reports\n  \"no certificate found\" and leaves the goal open. The\n  `Certificate.checks` predicate that closes the goal is\n  `decide +kernel`-checked against `Certificate n` data, so a proof\n  that goes through is independent of CSDP correctness.\n\n## Building and testing\n\nThis repository is pinned to the Lean version in\n[`lean-toolchain`](lean-toolchain); dependencies are pinned by\n[`lake-manifest.json`](lake-manifest.json).\n\n```\ngit clone https://github.com/leanprover/sos\ncd sos\nlake exe cache get\nlake test\n```\n\n`lake test` elaborates `SOSTest`, which runs `by sos` against every\nexample in [`SOSTest/Examples.lean`](SOSTest/Examples.lean) — each\ninvocation calls CSDP, rounds the Gram matrix, reconstructs the\ncertificate, and checks it. A passing `lake test` is end-to-end\nverification of the search/round/reconstruct/verify pipeline.\n\n### Native dependency troubleshooting\n\nThe tactic calls CSDP through `csdp-ffi`, so BLAS/LAPACK must be\navailable before Lean can load the native solver. If `lake build` or\n`lake test` fails while compiling or linking native code, run:\n\n```\n(cd .lake/packages/CSDP && lake script run checkNativeDeps)\n```\n\nThat preflight reports the platform-specific packages or SDK paths\nexpected by the native build. For examples that invoke CSDP, prefer\nLake targets such as `lake test`; running a file directly with\n`lake env lean SomeFile.lean` may bypass the native link setup needed\nfor the solver.\n\n## Architecture\n\nThe tactic runs three stages on a `by sos` goal:\n\n1. `SOS.Reify.parseGoalAtomic` walks the goal expression, collecting\n   atomic ℝ-typed subterms into an array and producing untyped\n   `SOS.Poly.Raw` ASTs for the conclusion and each constraint\n   hypothesis (drawn from `intro`-binders and the local context).\n2. `SOS.Search.runSearch` builds the Putinar-form SDP, calls CSDP,\n   rounds the float Gram matrix to rationals, runs LDLᵀ, and\n   reconstructs weighted-square terms — yielding a validated\n   `SOS.Certificate n`.\n3. `SOS.Tactic.closeSos` consumes the certificate and discharges the\n   real-arithmetic goal via the matching soundness lemma in\n   `SOS.Verifier`.\n\n| Module | What it provides |\n|---|---|\n| `SOS.Raw` | `Poly.Raw` and typed `Poly n` ASTs + reflection theorem. |\n| `SOS.Certificate` | `Goal n`, `SOSDecomp`, `Certificate n`, `checks` predicate. |\n| `SOS.Verifier` | `sos_sound`, `sos_strict_sound`, `sos_infeasible_sound`, plus `aeval_*` and `evalReal_eq_aeval` bridge lemmas. |\n| `SOS.LDL` | Rational LDLᵀ and Gram→weighted-square reconstruction. |\n| `SOS.Search` | Putinar-form SDP encoding, CSDP integration, rounding loop, LP-slack strict positivity. |\n| `SOS.Reify` | Atom-collecting Lean-`Expr` walker → `ParsedGoal` (atom array, untyped `SOS.Poly.Raw` for conclusion + constraints, hypothesis FVars). |\n| `SOS.Tactic` | `by sos` (search-driven) and `by sos_witness \u003Ccert>` elaborators. |\n| `SOSTest.Examples` | Worked examples invoking the tactic; serves as the `lake test` driver. |\n| `SOSTest.Showcase` | Curated launch/demo examples that are also covered by `lake test`. |\n\n## Dependencies\n\n| Package | Purpose |\n|---|---|\n| [`leanprover-community/mathlib4`](https://github.com/leanprover-community/mathlib4) | `IsSumSq.nonneg`, `ℝ`, `algebraMap ℚ ℝ`, `ring`, `push_cast`. |\n| [`Verified-zkEVM/CompPoly`](https://github.com/Verified-zkEVM/CompPoly) | Computational `CMvPolynomial n R` substrate; sorry/axiom-free. |\n| [`leanprover/csdp-ffi`](https://github.com/leanprover/csdp-ffi) | FFI wrapper around CSDP 6.2.0. Vendored CSDP source. |\n\nSystem dependencies (BLAS/LAPACK, transitively via csdp-ffi):\n\n| Platform | Packages |\n|----------|---|\n| Linux    | `liblapack-dev libblas-dev gfortran` |\n| macOS    | Apple Command Line Tools (Accelerate framework) |\n| Windows  | MSYS2 mingw-w64 with `mingw-w64-x86_64-openblas` |\n\nCI runs Linux-only.\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md) for development workflow and\ntest expectations.\n\n## Licence\n\nApache License 2.0 (see [LICENSE](LICENSE)). Transitively, CSDP is\ndistributed under the\n[Eclipse Public License 1.0](https://github.com/coin-or/Csdp/blob/master/LICENSE).\n\n## References\n\n- John Harrison, \"Verifying Nonlinear Real Formulas Via Sums of Squares\" (TPHOLs 2007).\n- Pablo Parrilo, *Structured Semidefinite Programs and Semialgebraic Geometry* (Caltech PhD, 2000).\n- Helena Peyrl & Pablo Parrilo, \"Computing sum of squares decompositions with rational coefficients\" (Theor. Comput. Sci. 2008).\n- Brian Borchers, [CSDP](https://github.com/coin-or/Csdp).\n- [Coq Micromega `psatz`](https://coq.inria.fr/refman/addendum/micromega.html) — design template.\n",1783784686942]