{"id":50568421,"url":"https://github.com/leanprover/lp","last_synced_at":"2026-06-04T17:00:24.865Z","repository":{"id":357298887,"uuid":"1236260345","full_name":"leanprover/lp","owner":"leanprover","description":"Stub: planned Lean 4 FFI bindings for SoPlex (iterative-refinement exact LP). PLAN.md only.","archived":false,"fork":false,"pushed_at":"2026-06-04T10:37:58.000Z","size":915,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-04T12:16:53.667Z","etag":null,"topics":[],"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":null,"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-12T05:00:53.000Z","updated_at":"2026-06-04T10:38:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/leanprover/lp","commit_stats":null,"previous_names":["kim-em/lean-soplex","kim-em/soplex","leanprover/lp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/leanprover/lp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Flp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Flp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Flp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Flp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leanprover","download_url":"https://codeload.github.com/leanprover/lp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover%2Flp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33914548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2026-06-04T17:00:16.993Z","updated_at":"2026-06-04T17:00:24.846Z","avatar_url":"https://github.com/leanprover.png","language":"Lean","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LP\n\n[![Lean](https://img.shields.io/badge/Lean-4.31.0--rc1-blue.svg)](./lean-toolchain)\n[![License](https://img.shields.io/github/license/leanprover/lp.svg)](./LICENSE)\n\nLinear programming in Lean 4: the `lp` and `maximize` tactics for discharging\nlinear-arithmetic goals, and a verified solver that runs\n[SoPlex](https://soplex.zib.de/) (the LP solver from the SCIP optimization\nsuite) and checks its exact certificate in Lean before returning a\nproof-carrying result. SoPlex is an untrusted oracle — every certificate is\nvalidated by a pure-Lean checker, so a solver bug can never yield an unsound\nproof.\n\nJump straight into the [Quickstart](#quickstart). LP is sliced into small\npackages (a pure checker, the tactics, and pluggable solver backends); if you\nwant only part of it or a different backend, see\n[Just the verified solver](#just-the-verified-solver-no-tactics),\n[Choosing a backend](#choosing-a-backend), and [Packages](#packages) below.\n\n## Quickstart\n\nAdd `LP` to your `lakefile.lean`:\n\n```lean\nrequire LP from git \"https://github.com/leanprover/lp\" @ \"main\"\n```\n\nThis example maximizes `3 x₀ + 5 x₁` subject to\n`x₀ ≤ 4`, `2 x₁ ≤ 12`, `3 x₀ + 2 x₁ ≤ 18`, and `x₀, x₁ ≥ 0`\n(textbook example; optimum is `x = (2, 6)` with objective `36`):\n\n```lean\nimport LP\nopen LP LP.Verify\n\n-- Proving theorems via `lp` is usually faster than Mathlib's `linarith`.\nexample (x₀ x₁ : Rat) (_ : x₀ ≤ 4) (_ : 2 * x₁ ≤ 12) (_ : 3 * x₀ + 2 * x₁ ≤ 18)\n    (_ : 0 ≤ x₀) (_ : 0 ≤ x₁) : 3 * x₀ + 5 * x₁ ≤ 36 := by lp\n\n-- The tactic also solves linear arithmetic problems involving quantifiers.\nexample : ∃ x : Rat, 0 ≤ x ∧ x ≤ 3 ∧\n    ∀ y : Rat, x ≤ y → y ≤ 5 → y ≤ 2 * x := by lp\n\n-- The library can also generate certificates for linear programming problems:\n\ndef lp : Problem 3 2 :=\n  { c         := #v[3, 5]\n    a         := #[(0, 0, 1), (1, 1, 2), (2, 0, 3), (2, 1, 2)]\n    rowBounds := #v[(none, some 4), (none, some 12), (none, some 18)]\n    colBounds := #v[(some 0, none), (some 0, none)] }\n\ndef main : IO Unit := do\n  match solveVerified (opts := { sense := .maximize }) lp with\n  | .error e  =\u003e IO.println s!\"solve failed: {repr e}\"\n  | .ok r =\u003e\n    match r.verified with\n    | .optimal x h =\u003e\n      -- `h.1 : IsFeasible r.normalized x.toArray`\n      -- `h.2 : IsOptimal  r.normalized .maximize x.toArray`\n      let _ := h\n      IO.println s!\"optimal x = {repr x.toArray}\"\n    | .infeasible _    =\u003e IO.println \"infeasible (with Lean proof)\"\n    | .unbounded _ _ _ =\u003e IO.println \"unbounded (with Lean proof)\"\n    | .unchecked s     =\u003e IO.println s!\"unchecked: {repr s}\"\n```\n\nKey shape:\n\n* `Problem m n` is indexed by `m` constraints and `n` variables, so\n  every array has its size pinned in the type. `c`, `rowBounds`,\n  `colBounds` are `Vector`s; `a` is a sparse `(row, col, value)` list.\n* `rowBounds` and `colBounds` are `(lo, hi)` pairs with `none = ±∞`,\n  covering `≤`, `=`, `≥`, ranged constraints, and boxed variables\n  uniformly.\n* `solveVerified` returns a `VerifiedSolve` whose `verified` field is\n  either a constructor carrying a real Lean soundness proof\n  (`.optimal x h`, `.infeasible h`, `.unbounded x r h`) or\n  `.unchecked status` when SoPlex was undecided or the certificate\n  failed to check.\n\nThis example is kept in [`Examples/Quickstart.lean`](./Examples/Quickstart.lean)\nand built as `lake exe quickstart-example` so it stays in sync with\nthe API. See [`Examples/`](./Examples/) for the examples index.\n\n## Tactics\n\nThe verified pipeline is exposed as two `Rat`-affine tactics that\nbuild kernel proof terms — no `Problem`/`Certificate` data reaches the\nkernel, only a weighted-sum-of-hypotheses identity discharged by an\nexplicit-proof-term constructor.\n\n### `lp` \n\n```lean\nimport LP\n\nexample : (1 : Rat) \u003c 2 := by lp\n\nexample (a b : Rat) (_ : 2 * a + b ≤ 5) (_ : a - b ≤ 1) :\n    3 * a ≤ 6 := by lp\n\nexample (a : Rat) (_ : a ≤ 0 ∧ 0 ≤ a) : a = 0 := by lp\n\nexample (x : Rat) (_ : x ≤ 0) : x \u003c 1 := by lp\n\nexample : ∃ x : Rat, 0 ≤ x ∧ x ≤ 1 := by lp\n\nexample : ∃ x : Rat, ∀ y : Rat, 0 ≤ y → y ≤ 1 → x ≥ y := by lp\n\nexample : ∃ x : Rat, 0 ≤ x ∧ x ≤ 3 ∧\n    ∀ y : Rat, x ≤ y → y ≤ 5 → y ≤ 2 * x := by lp\n```\n\nHypotheses that are not non-strict `Rat`-affine are silently ignored\n(strict hypotheses are rejected with a tactic-level diagnostic). When\nSoPlex returns infeasible, `lp` derives `False` from the dual and\ncloses any goal.\n\n`lp` handles a Π₂ fragment of linear rational arithmetic. Atoms are\n`Rat`-affine (in)equalities (`≤`, `\u003c`, `=`, `≥`, `\u003e`) in the\n`Rat`-typed locals; these combine under `∧`, under `∃ x : Rat`, and\nunder inner `∀ y : Rat, g₁ → … → gₖ → b` whose guards `gᵢ` and body\n`b` are themselves `Rat`-affine atoms — including guards that mention\nthe outer existential witness. The local context contributes\nnon-strict linear `Rat` hypotheses; SoPlex serves as an untrusted\noracle for Farkas / dual multipliers, and the kernel proof is\nreconstructed from those multipliers and the original hypothesis\nterms.\n\n### `maximize` \n\n`maximize \u003cexpr\u003e` runs a sup-LP over the local hypotheses and injects\n`hbound : \u003cexpr\u003e ≤ N` where `N` is the certified maximum. Use\n`maximize h : \u003cexpr\u003e` to choose the hypothesis name.\n\n```lean\nexample (x₀ x₁ : Rat) (_ : 0 ≤ x₀) (_ : 0 ≤ x₁) (_ : x₀ ≤ 4)\n    (_ : 2 * x₁ ≤ 12) (_ : 3 * x₀ + 2 * x₁ ≤ 18) :\n    3 * x₀ + 5 * x₁ ≤ 36 := by\n  maximize 3 * x₀ + 5 * x₁\n  exact hbound\n\nexample (x : Rat) (_ : 0 ≤ x) (_ : x ≤ 4) : 3 * x + 7 ≤ 19 := by\n  maximize h : 3 * x + 7\n  exact h\n```\n\nIf hypotheses are inconsistent, `maximize` closes the surrounding\ngoal by `False.elim`. If the LP is unbounded above, it fails without\nproducing a proof.\n\n## Just the verified solver (no tactics)\n\nIf you don't need the `lp` / `maximize` tactics and only want verified LP\nsolving — or just the checker — depend on a narrower slice instead of `LP`:\n\n- **[`leanprover/lp-backend-soplex-ffi`](https://github.com/leanprover/lp-backend-soplex-ffi)**\n  gives you `solveVerified`: run SoPlex and get back a `Solution` carrying a\n  Lean-checked certificate, without the tactic frontend.\n- **[`leanprover/lp-verify`](https://github.com/leanprover/lp-verify)** is the\n  pure-Lean certificate checker on its own — no native dependencies, no SoPlex\n  build. Use it to validate certificates your own code (or another solver)\n  produced against the\n  [`leanprover/lp-core`](https://github.com/leanprover/lp-core) `Problem` /\n  `Certificate` types.\n\n## Choosing a backend\n\n`by lp`, `solveVerifiedWith`, and the verified drivers dispatch through a\nbackend registry that lives in\n[`leanprover/lp-tactic`](https://github.com/leanprover/lp-tactic). `LP` bundles\nthe FFI backend by default; to use a different one, `require` exactly the\nbackend you want. Importing several is fine — the lowest-priority backend whose\nprobe succeeds wins:\n\n- **[`leanprover/lp-backend-soplex-ffi`](https://github.com/leanprover/lp-backend-soplex-ffi)**\n  (priority 10, the default). Production-grade native binding to the vendored\n  SoPlex build; what `import LP` resolves to.\n- **[`leanprover/lp-backend-soplex-json`](https://github.com/leanprover/lp-backend-soplex-json)**\n  (priority 50, scaffold). Will drive an externally-installed `soplex` binary on\n  `$PATH` through a JSON stdio protocol; the wire format is documented in the\n  repository's `docs/json-contract.md`, but the encoder/decoder is not yet\n  implemented — registering the package today gets the probe and the registry\n  slot, not a working solver. Aimed at the \"I've already got `brew install\n  soplex`, don't rebuild it\" case.\n- **[`leanprover/lp-backend-pure`](https://github.com/leanprover/lp-backend-pure)**\n  (priority 100, scaffold). Reserves the registry slot for a pure-Lean LP solver\n  with zero native deps and zero subprocess calls. The simplex implementation\n  has not landed yet, so registering the package today returns a structured\n  \"simplex not implemented\" error from `solveExact`. When it does land, expect\n  it to be slow on anything beyond toy LPs (exact-rational simplex pays for the\n  verifier's exact-rational input contract); the point is zero-install CI lanes\n  and demos.\n\nSee [`leanprover/lp-tactic`](https://github.com/leanprover/lp-tactic) for the\nregistry surface (`registerBackend`, `resolveBackend`, `availableBackends`).\n\n## Packages\n\n`LP` is a thin meta-package: it bundles the default FFI backend and re-exports a\nconvenient surface, so `import LP` gives you the tactics, `solveVerified`, and\nMPS / LP file I/O in one import. The actual work lives in its dependencies:\n\n- **[`leanprover/lp-core`](https://github.com/leanprover/lp-core)** — the shared\n  LP vocabulary (`Problem`, `Options`, `Solution`, `Certificate`, `SolveError`)\n  and the `LPBackend` record. Pure Lean.\n- **[`leanprover/lp-verify`](https://github.com/leanprover/lp-verify)** — the\n  pure-Lean certificate checker (`Verified`, `verifyOutcome`, soundness lemmas).\n- **[`leanprover/lp-tactic`](https://github.com/leanprover/lp-tactic)** — the\n  `lp` and `maximize` tactics, the backend registry, and the backend-pluggable\n  `solveVerifiedWith` driver.\n- **[`leanprover/lp-backend-soplex-ffi`](https://github.com/leanprover/lp-backend-soplex-ffi)**\n  — the FFI backend adapter (priority 10) and the synchronous `solveVerified`\n  driver.\n- **[`leanprover/soplex-ffi`](https://github.com/leanprover/soplex-ffi)** — the\n  vendored SoPlex build, the C++ FFI wrapper, and the direct Lean bindings.\n\n## Benchmarks\n\nPerformance comparisons of `by lp` against Mathlib's `linarith`, plus\nthe multi-carrier sweep over `Rat` / `Int` / `Dyadic` / `Nat` / `Real`,\nlive in [`leanprover/lp-benchmark`](https://github.com/leanprover/lp-benchmark).\nOn the same `ℚ` goals `lp` runs about 2x faster than `linarith`, and the\nnative computable carriers (`Int`, `Dyadic`, `Nat`) beat the `Rat`\nbaseline.\n\n## Build\n\nPinned SoPlex tag: **`v8.0.2`** (transitive via `SoplexFFI`). Pinned\nLean toolchain: see [`lean-toolchain`](./lean-toolchain).\n\nSystem dependencies:\n\n| Platform | Packages |\n|----------|----------|\n| Linux    | `build-essential cmake libgmp-dev libgmpxx4ldbl libboost-dev` |\n| macOS    | `brew install gmp boost cmake` (plus Xcode Command Line Tools) |\n| Windows  | MSYS2 `mingw-w64-x86_64-{gcc,cmake,ninja,make,gmp,boost}` |\n\nClone and build through Lake:\n\n```bash\ngit clone https://github.com/leanprover/lp\ncd soplex\nlake exe quickstart-example\nlake test\n```\n\nLake fetches `SoplexFFI` and initializes its vendored SoPlex submodule\nas part of the build — there are no submodules in this repository\nitself.\n\n`quickstart-example` runs the verified solve from the\n[Quickstart](#quickstart) above and prints `optimal x = #[2, 6]`.\n`lake test` builds and runs the full test suite under\n[`LPTest/`](./LPTest). The suite includes\n`LPTest/FFIProbe.lean`, which calls `solveVerified` from inside a\ntactic and checks the elaboration-time FFI loading path used by future\ntactics. For a lower-level FFI-only check\n(SoPlex version, throw/catch ABI, small LP sanity check via the direct\nbinding) use `lake exe ffi-check`.\n\nThe first Lake build is slow (~1–3 min) because the `SoplexFFI`\ndependency configures and compiles vendored SoPlex with CMake.\nSubsequent runs are nearly instant: CMake reuses its cache, and Lake\nonly rebuilds the FFI wrapper or extracted SoPlex objects when their\ninputs change.\n\n## Trust model\n\nSoPlex is treated as an unverified mathematical oracle. Every exact\ncertificate it produces is checked in Lean before any proof is\nconstructed. Incorrect certificates, including certificates affected by\nsolver bugs or sign-convention translation mistakes, are rejected by\nthe Lean checker and reported as `Verified.unchecked`.\n\nThe native C++ FFI remains part of the runtime trusted computing base.\nIt is trusted to run safely in-process, preserve memory safety and ABI\ncorrectness, and faithfully marshal Lean-side `Problem` and\ncertificate data. The Lean checker protects the mathematical proof\nboundary; it does not make arbitrary native memory-safety or ABI\nfailures harmless.\n\nDetailed notes on `solveVerified`, presolve, dual multipliers,\nmaximization canonicalization, and denominator budgets are maintained\nin [`docs/verification.md`](./docs/verification.md).\n\n## Layout\n\n```\nLP.lean                   # top-level import\nLP/Basic.lean             # high-level API + `solveVerified`\nLP/Core.lean              # re-exports `LPCore.Backend` + registry\nLP/Backend/SoplexFFI.lean # SoPlex FFI backend adapter\nLP/Tactic/                # `lp` and `maximize` tactics\n  LP.lean                     #   tactic frontend (elaboration + dispatch)\n  Q.lean                      #   kernel-reducible rational literals for tactic proofs\nLP/Verify.lean            # verifier re-export module\nLP/Verify/                # pure-Lean certificate checker\n  Types.lean                  #   re-exports `LPCore.Types` (`Problem`, `Certificate`, ...)\n  Validate.lean               #   re-exports `LPCore.Validate`\n  Driver.lean                 #   compose validate + solveExact + check\n  Sound.lean                  #   soundness lemmas \n  Prop.lean, Bool.lean        #   Prop/Bool views of the checker\n  Arith.lean, Budget.lean     #   rational arithmetic + denominator budget\nExamples/\n  README.md                   # examples index\n  Quickstart.lean             # quickstart example executable\nLPTest/                   # test suite (run via `lake test`)\n  FFICheck.lean               #   `ffi-check` executable\n  Common.lean                 #   shared test scaffolding (`LP.Verify` only)\n  SolveCommon.lean            #   adds `LP` for SoPlex-backed tests\n  FFIProbe.lean               #   elaboration-time FFI loading regression probe\n  LP*.lean                    #   tactic frontend and proof-term tests\n  Solve*.lean, Verify.lean    #   solver and verifier regression tests\n  AccessorGoldens.lean        #   accessor documentation golden tests\n  FileIo.lean                 #   LP/MPS file-input tests\n  Runner.lean                 #   `lake test` driver\n  fixtures/                   #   MPS / LP test inputs\ndocs/accessors.md             # row-sense × column-status accessor reference\ndocs/backend-abstraction.md   # backend split and registry notes\ndocs/verification.md          # detailed verified-solve trust model\ndocs/lp-proof-construction.md # `lp` tactic proof construction notes\nlakefile.lean                 # depends on `SoplexFFI`\nscripts/install-toolchain.sh  # elan + GitHub-fallback toolchain installer\nscripts/install-sanitizer-runtime.sh\n                              # CI sanitizer runtime installer\n.github/workflows/ci.yml      # Linux + macOS + Windows CI matrix\n```\n\n## Licence\n\n`LP` is licensed under the [Apache License 2.0](./LICENSE),\nmatching SoPlex itself. The compiled binary's GMP runtime dependency\n(LGPL) is linked dynamically by default through `SoplexFFI`. SoPlex\nitself is linked into the Lean shared library from the vendored static\narchive.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleanprover%2Flp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleanprover%2Flp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleanprover%2Flp/lists"}