{"id":49915517,"url":"https://github.com/leanprover/sos","last_synced_at":"2026-05-16T16:01:44.240Z","repository":{"id":356549674,"uuid":"1232997943","full_name":"leanprover/sos","owner":"leanprover","description":"Harrison's sum-of-squares decision procedure for nonlinear real arithmetic in Lean 4","archived":false,"fork":false,"pushed_at":"2026-05-15T02:44:23.000Z","size":405,"stargazers_count":1,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T04:39:08.685Z","etag":null,"topics":["formal-verification","lean4","nonlinear-real-arithmetic","semidefinite-programming","sum-of-squares","theorem-proving"],"latest_commit_sha":null,"homepage":null,"language":"Lean","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leanprover.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T13:36:52.000Z","updated_at":"2026-05-15T02:44:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/leanprover/sos","commit_stats":null,"previous_names":["kim-em/sos","leanprover/sos"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/leanprover/sos","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Fsos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Fsos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Fsos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Fsos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leanprover","download_url":"https://codeload.github.com/leanprover/sos/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Fsos/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33109461,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formal-verification","lean4","nonlinear-real-arithmetic","semidefinite-programming","sum-of-squares","theorem-proving"],"created_at":"2026-05-16T16:00:56.687Z","updated_at":"2026-05-16T16:01:44.234Z","avatar_url":"https://github.com/leanprover.png","language":"Lean","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 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--     { sigma0 := { squares := [CMvPolynomial.C (1 : ℚ), CMvPolynomial.X 0] }, sigmas := [] }\n```\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); `by sos`\ncorrectly fails to find a certificate, 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\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 (small ints, then powers of two up to\n  `2^20`) and decompose via rational LDLᵀ + Lagrange four-square.\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.** Multiplier basis sizes are set\n  once from a degree bound `D = max(deg(target), maxᵢ deg(gᵢ))`: the\n  σ₀ basis is monomials up to `⌈D/2⌉`, and each σᵢ basis is monomials\n  up to `⌈max(0, D − deg(gᵢ))/2⌉`. There is no hierarchy walk that\n  bumps the relaxation order on failure. Failures cover both\n  genuinely non-SOS non-negative polynomials (Motzkin\n  `x⁴y² + x²y⁴ + 1 − 3x²y²` is the canonical example) and goals that\n  would only succeed at a larger relaxation order than this fixed\n  search uses.\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ᵀ / four-square reconstruction can't close the certificate,\n  `by sos` reports \"no certificate found\" and leaves the goal open.\n  The `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- **The four-squares cap is the practical floor on `ε`.** Strict\n  positivity bounds smaller than `1/2^20 ≈ 10^-6` are out of reach\n  because `fourSquaresNat` brute-forces a Lagrange decomposition with\n  a cap at `n ≤ 2^20`. Lifting this requires a smarter four-squares\n  algorithm (e.g. Cornacchia / Pollard-style randomised search),\n  which is independent work.\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 \u0026\u0026 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 squares — yielding a validated `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ᵀ, Lagrange 4-square, Gram→SOS 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\u003e` 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 \u0026 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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleanprover%2Fsos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleanprover%2Fsos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleanprover%2Fsos/lists"}