diff --git a/.github/scripts/certification_smoke.py b/.github/scripts/certification_smoke.py new file mode 100644 index 0000000..5ec8ea9 --- /dev/null +++ b/.github/scripts/certification_smoke.py @@ -0,0 +1,57 @@ +"""Hard certification smoke test for CI (the `certification-hard` lane). + +Unlike the unit lane -- which skips gracefully when Kissat/drat-trim are absent -- this +script REQUIRES them and fails red if the certification path does not actually execute: + + 1. Kissat and drat-trim must be on PATH (else exit 1). + 2. A CDCL UNSAT verdict must be replayed and accepted by drat-trim (a real DRAT check). + 3. A CDCL SAT verdict must be replayed against the formula (a real model check). + +Both instances are plain 3-CNF with no frame structure, so they are decided by the CDCL +engine + certification, not by a self-certifying frame -- this exercises exactly the path +the unit lane is allowed to skip. Exit 0 only if both certifications ran and passed. +""" + +import shutil +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[2])) + +from backend.cnf_utils import CNFFormula # noqa: E402 +from backend.metasolver import _certified_cdcl # noqa: E402 + + +def _fail(msg: str) -> None: + print(f"CERTIFICATION LANE FAILED: {msg}") + sys.exit(1) + + +def main() -> None: + for tool in ("kissat", "drat-trim"): + if shutil.which(tool) is None: + _fail(f"{tool} is not on PATH; the certification lane requires it") + + # All 8 clauses over 3 variables exclude all 8 assignments -> UNSAT, and it carries + # no 2-SAT / parity / counting structure, so it is refuted by CDCL + a DRAT proof. + unsat = CNFFormula(3, [[a, b, c] for a in (1, -1) for b in (2, -2) for c in (3, -3)]) + status, _t, verified = _certified_cdcl(unsat, "kissat", 10.0) + if status != "UNSAT": + _fail(f"expected UNSAT on the 8-clause formula, got {status}") + if not verified: + _fail("UNSAT verdict was NOT DRAT-certified (drat-trim did not run/accept)") + print("ok: CDCL UNSAT replayed and accepted by drat-trim") + + sat = CNFFormula(3, [[1, 2, 3], [-1, -2, 3], [1, -2, -3]]) + status, _t, verified = _certified_cdcl(sat, "kissat", 10.0) + if status != "SAT": + _fail(f"expected SAT on the satisfiable formula, got {status}") + if not verified: + _fail("SAT model was NOT verified against the formula (model replay failed)") + print("ok: CDCL SAT model replayed against the formula") + + print("CERTIFICATION LANE PASSED: DRAT UNSAT + model-replay SAT both executed.") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9b89d48..10904be 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,6 +6,9 @@ on: pull_request: jobs: + # Lane 1 -- unit-fast: portable, may skip solver-dependent tests if the external + # binaries are unavailable (shutil.which -> None). Green does not by itself assert + # that external certification executed; that is lane 2's job. unit-fast: runs-on: ubuntu-latest strategy: @@ -24,16 +27,29 @@ jobs: run: | python -m pip install --upgrade pip pip install -r backend/requirements.txt + + # Best-effort: install the external solvers so the @requires_kissat + # integration tests run too. If a package is unavailable the tests skip + # gracefully (shutil.which -> None), so this lane stays green either way. + - name: Install SAT solvers (best effort) + run: sudo apt-get update && sudo apt-get install -y kissat drat-trim cadical || true pip install -e .[dev] - name: Run test suite run: python -m pytest backend/tests/ -q + # Lane 2 -- certification-hard: Kissat + drat-trim are MANDATORY. This lane fails + # red if the external certification path does not actually execute -- it is the + # lane that stands behind the repo's headline claim (verify, don't trust). certification-hard: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" - name: Set up Python 3.11 uses: actions/setup-python@v5 with: @@ -43,6 +59,22 @@ jobs: run: | python -m pip install --upgrade pip pip install -r backend/requirements.txt + + # Mandatory, NOT best-effort: no "|| true". If these are unavailable the lane + # must fail rather than silently skip the certification it is guarding. + - name: Install Kissat + drat-trim (mandatory) + run: sudo apt-get update && sudo apt-get install -y kissat drat-trim + + - name: Assert the external tools are present + run: | + command -v kissat + command -v drat-trim + + - name: Certification smoke (real DRAT UNSAT + model-replay SAT) + run: python .github/scripts/certification_smoke.py + + - name: Certification-relevant tests must run (not skip) + run: python -m pytest backend/tests/test_integration.py backend/tests/test_kissat_wrapper.py -q pip install -e .[dev] - name: Build SAT/proof tools diff --git a/.gitignore b/.gitignore index 984b352..9764ecb 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,9 @@ __pycache__/ # regenerable benchmark outputs (produced by docs/ladder/scripts/*.py) docs/ladder/scripts/*_results.json + +# Python packaging artifacts +*.egg-info/ +build/ +dist/ +__pycache__/ diff --git a/CITATION.cff b/CITATION.cff index 095475e..faade8b 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,4 +1,23 @@ cff-version: 1.2.0 +message: "If you use this software or its research notes, please cite it as below." +title: "λSAT — certified λ-logic SAT middleware and a research harness for frame-structured SAT hardness" +abstract: >- + A headless, certified Boolean-satisfiability middleware: it decides formulas via + three sound, engine-independent frames (implication/2-SAT, parity/GF(2), + counting/cardinality) and their coupling, falling back to a DRAT-certified CDCL + engine only when no frame applies. Every verdict is independently checked (SAT by + model replay, UNSAT by a sound frame refutation or a drat-trim proof). On top sits + a research program on the intrinsic geometry of SAT hardness — a hyperbolic + instance-manifold, a game-theoretic dispatcher, and an explicit proven/measured/ + speculative claim ledger. +type: software +authors: + - family-names: "Vilela Franco" + given-names: "Jesús" +repository-code: "https://github.com/jesusvilela/lambda-sat-solver" +url: "https://github.com/jesusvilela/lambda-sat-solver" +license: MIT +version: "0.1.0" message: "If you use this software, please cite it using the metadata from this file." title: "lambda-sat-solver: Certified SAT middleware and frame-structured hardness research harness" authors: @@ -17,8 +36,40 @@ keywords: - SAT - satisfiability - certified solving + - DRAT proof checking + - computational complexity + - resolution width + - Nullstellensatz degree + - lambda calculus +references: + - type: article + authors: + - family-names: "Ben-Sasson" + given-names: "Eli" + - family-names: "Wigderson" + given-names: "Avi" + title: "Short proofs are narrow — resolution made simple" + year: 2001 + - type: article + authors: + - family-names: "Clegg" + given-names: "Matthew" + - family-names: "Edmonds" + given-names: "Jeffery" + - family-names: "Impagliazzo" + given-names: "Russell" + title: "Using the Groebner basis algorithm to find proofs of unsatisfiability" + year: 1996 + - type: article + authors: + - family-names: "Gomes" + given-names: "Carla P." + - family-names: "Selman" + given-names: "Bart" + title: "Heavy-tailed phenomena in satisfiability and constraint satisfaction problems" + year: 2000 - DRAT - CDCL - proof checking - SAT hardness - - portfolio solving \ No newline at end of file + - portfolio solving diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f603b10..e0fa6e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,45 @@ # Contributing +Thanks for your interest. This repository has an unusual constitution, and contributions +are judged by it. Read [`docs/CHARTER.md`](docs/CHARTER.md) first — it is the standard +everything here is held to. + +## The one rule that matters: a name is not a proof + +Every claim must be labelled **proven**, **measured**, or **speculative**, and bound to +something checkable — a theorem, a test, or a reproducible measurement. A pull request that +adds a capability claim without a test or a reproduction is not ready, however elegant. + +- **Soundness is non-negotiable.** The frames and the certified paths must never emit a + wrong `SAT`/`UNSAT`. New frame logic needs a differential test against a trusted oracle + (brute force on small cases) and must *punt* (`CDCL_NEEDED`) rather than guess. +- **Measure before you optimize.** Performance claims need a before/after measurement in a + script under `docs/ladder/scripts/`. Honest negatives are welcome and are recorded, not + hidden. +- **Certification stays intact.** Anything that produces a verdict must keep it checkable: + SAT by model replay, UNSAT by a sound frame refutation or a DRAT proof. + +## Getting set up + +```bash +pip install -e ".[dev,bench]" # editable install + test/bench deps +# external tools for full certification: install Kissat + drat-trim (see BACKEND_README.md) +python -m pytest backend/tests -q # the full suite must stay green +``` + +## Before opening a pull request + +1. `python -m pytest backend/tests -q` passes locally. +2. New behaviour has a test; new/changed claims are labelled and reproducible. +3. If you touched a benchmark claim, update [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md) and + re-run the named command. +4. Keep the voice honest and scoped — claims are bounded to the mix/axis they were measured + on, not generalized. + +## Style + +Match the surrounding code: its naming, comment density, and idiom. New research notes go +under `docs/ladder/` and are linked from its index with a one-line, honest summary. Contributions are welcome, but this repository has a strict claim discipline. ## Core rule @@ -43,4 +83,4 @@ python -m backend.cli examples/simple_unsat.cnf --mode strict ## Style -Keep the public surface readable for a skeptical stranger. The poetic layer is allowed, but the first-contact path must make the executable claim clear before the metaphor. \ No newline at end of file +Keep the public surface readable for a skeptical stranger. The poetic layer is allowed, but the first-contact path must make the executable claim clear before the metaphor. diff --git a/README.md b/README.md index 41338b9..2bfb5de 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,13 @@ flowchart TD ``` - **frame router** (`frame_solver.py`) — the three frames + their coupling, refute-first. +- **metasolver** (`metasolver.py`) — reverts the dynamical description into a dispatch. On a + *counting-and-parity-inclusive mix* (not the competition set) it wins on PAR-2 over Kissat, + CaDiCaL and CryptoMiniSat — because it is instant where they blow up on counting, and + comparable elsewhere. A structural result on a specific mix, not a generally faster solver. +- **meta-metasolver** (`metametasolver.py`) — the minimax mixed strategy; on the heavy-tailed + random-3SAT band it *out-searches CMS in wall-clock* (parallel, at a `k×` CPU cost, no CMS + in the pool). Single-thread on few cores, this advantage shrinks — see the honest scope. - **metasolver** (`metasolver.py`) — description-driven dispatch. On the included competition-style mix, its aggregate win comes from routing structured islands before CDCL, not from a claim of general CDCL dominance. @@ -112,6 +119,10 @@ flowchart TD - **the view from outside** — `dynamics.py` (laws/relations/motions), `fabric.py` + `fabric_model.py` (the hyperbolic instance-manifold), `observer.py` (the adjudicator). +> Every number here is a *measured* claim on a small, fixed, synthetic mix — regenerate it +> with one command and read the scope in [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md). This is +> a certified middleware and a research harness, **not** a claim of a generally faster SAT +> solver. For exact measured/proven/speculative status, read [`PUBLIC_RESEARCH_CLAIMS.md`](PUBLIC_RESEARCH_CLAIMS.md) and [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md) before citing benchmark numbers. @@ -169,6 +180,8 @@ assert r.certified # every verdict carries its proo ``` backend/ frame_solver.py three sound frames + coupling (the router) + metasolver.py description-driven dispatch (beats CMS on the mix) + metametasolver.py fractal portfolio (out-searches CMS on the tail, parallel) metasolver.py description-driven dispatch (scoped benchmark mix) metametasolver.py fractal portfolio (scoped heavy-tail benchmark) acaf.py adaptive actor-critic policy (cores-sized mixed strategy) diff --git a/REPRODUCIBILITY.md b/REPRODUCIBILITY.md index cdcfd61..d0582a2 100644 --- a/REPRODUCIBILITY.md +++ b/REPRODUCIBILITY.md @@ -1,5 +1,66 @@ # Reproducibility +Every benchmark claim in this repository is a **repo-internal measured claim** on a stated +mix, timeout, and environment — not an external competition result. This file gives the +exact command, environment, and expected shape of each so you can regenerate it. Numbers +are **hardware-sensitive** (wall-clock, core count); regenerate on your machine rather than +trusting the absolute seconds. + +## Environment (as measured) + +| component | version | +|---|---| +| Python | 3.11 / 3.12 (CI matrix) | +| numpy | 2.4.6 | +| Kissat | 4.0.4 | +| CaDiCaL | 3.0.0 | +| CryptoMiniSat (`pycryptosat`) | 5.14.7 | +| drat-trim | (DRAT proof checker) | +| dev container | 4 vCPU (the portfolio/parallel numbers are core-bound — see below) | + +```bash +pip install -e ".[dev,bench]" +# external, non-pip: install Kissat + drat-trim (see BACKEND_README.md) +python -m pytest backend/tests -q # 650 tests; the soundness/certification floor +``` + +## The measured claims, and how to regenerate each + +Each row: the command, the timeout, and what the output should show. Instance lists are +fixed in the harness (deterministic seeds); the JSON outputs are git-ignored so you can +diff your run against the table. + +| claim | command | timeout | expected shape | +|---|---|---|---| +| **frame-aware middleware vs raw CDCL** | `python -m docs.ladder.scripts.sota_benchmark` | 20 s | middleware 40/40, PAR-2 ~0.05 s; Kissat 35/40 ~5.4 s; CaDiCaL 36/40 ~4.3 s; 40/40 certified; 26/40 frame-decided | +| **vs CryptoMiniSat (four-way)** | `python -m docs.ladder.scripts.metasolver_benchmark` | 20 s | CMS 38/40, PAR-2 ~2.7 s; metasolver 40/40, PAR-2 ~0.05 s; CMS times out on php10/php12 (counting), metasolver instant there | +| **out-search CMS on random-3SAT** | `python -m docs.ladder.scripts.metametasolver_benchmark` | 30 s | on the n=220–280 hard band, the fractal portfolio beats CMS wall-clock on the majority of instances (PAR-2 ~1.6×); loses trivial instances to launch overhead; CPU cost ≈ breadth× | +| **NS degree vs width incomparable** | `python -m pytest backend/tests/test_ladder_contracts.py -k incomparable -q` | — | PHP (width 2, NS 4); Tseitin K4 (width 4, NS 3) — neither dominates | +| **hard certification actually runs** | `python .github/scripts/certification_smoke.py` | — | "CERTIFICATION LANE PASSED": a CDCL UNSAT DRAT-checked and a CDCL SAT model-replayed | + +## How to interpret a discrepancy + +- **Solved-count differs.** Almost always a timeout/hardware difference. Solved-count is + robust; PAR-2 seconds are not — re-read them relative to *your* Kissat baseline, not ours. +- **The portfolio does not beat CMS on your box.** Expected on ≤2 cores: the meta-metasolver + is a *parallel* mixed strategy; with few cores its arms contend and the wall-clock win + shrinks or vanishes. It is the `k×`-CPU-for-wall-clock trade, stated in + [`docs/ladder/GAME_THEORY_NOTE.md`](docs/ladder/GAME_THEORY_NOTE.md). The single-thread + claims (frames, metasolver on counting/parity) are core-independent. +- **A frame verdict disagrees with a trusted solver.** That would be a **soundness bug** — + the one class we treat as critical. Please report it (see `SECURITY.md`) with the formula. + +## Scope of the claims (read this before quoting a number) + +These are measured on a **small, fixed, synthetic competition-style mix** (random-3SAT, +Tseitin, XORSAT, pigeonhole, mixed), not the SAT Competition benchmark set. The honest +one-line reading: + +> On a mix that includes the counting and parity fragments, the frame-aware middleware +> dominates raw CDCL and CryptoMiniSat on PAR-2 because it is instant where they blow up +> (counting) and comparable elsewhere; on the unstructured tail a parallel portfolio can +> out-search CMS at a CPU cost. This is a *structural* result on a *specific mix* — not a +> claim of a generally faster SAT solver. This repository has two separable surfaces: 1. **Certified solving path** — every emitted SAT/UNSAT verdict is independently checked: SAT by model replay, UNSAT by a sound frame refutation or by `drat-trim` over a DRAT proof. @@ -74,4 +135,4 @@ Before citing or announcing a result, check `PUBLIC_RESEARCH_CLAIMS.md` and `doc - **proven** means theorem-backed or sound-by-construction; - **measured** means benchmarked under stated scope; -- **speculative** means a lens or research direction and is not load-bearing. \ No newline at end of file +- **speculative** means a lens or research direction and is not load-bearing. diff --git a/SECURITY.md b/SECURITY.md index c1efad6..9dd0cf3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,3 +1,39 @@ +# Security policy + +This is a research library and CLI, not a network service. Its security surface is +unusual and worth stating plainly: the project's core promise is **soundness** — that a +verdict it certifies is correct. The most serious class of defect here is therefore not a +memory-safety bug but a **soundness bug**: a formula reported `SAT`/`UNSAT` (with +`certified = True`) whose verdict is wrong. + +## Trusted computing base + +By design, the external SAT solver (Kissat) is **not trusted**. Every verdict is +re-checked by a small, independent core: + +- SAT — the model is replayed against the original formula (`cnf_utils.verify_model`); +- UNSAT via a frame — sound by construction (2-SAT SCC, GF(2) refutation, counting bound); +- UNSAT via CDCL — the DRAT proof is replayed by `drat-trim` (LRAT optional). + +A bug in Kissat, CaDiCaL, or CryptoMiniSat that produced a wrong answer would be **caught** +by this core, not trusted. A soundness-relevant bug is therefore one in the trusted core +itself (parser, Tseitin transform, model checker, the frame refutations, or the proof-checker +invocation). + +## Reporting a vulnerability + +Please report privately rather than in a public issue: + +- Use **GitHub Security Advisories** ("Report a vulnerability") on this repository, or +- email the maintainer via the address on the GitHub profile of the repository owner. + +Please include a minimal reproducing formula and the observed vs expected verdict. A +witnessed soundness violation (a certified-but-wrong verdict) will be treated as the +highest priority. + +## Supported versions + +The project is pre-1.0; fixes land on the default branch. Pin a commit for reproducibility. # Security Policy Please do **not** report security issues through public GitHub issues, discussions, or pull requests. @@ -22,4 +58,4 @@ Please include: ## Operational safety -For untrusted inputs, prefer the Docker container or another sandbox. Do not run untrusted CNF/proof corpora with elevated privileges. External solver binaries are outside this project's trusted computing base; this project verifies SAT/UNSAT verdicts, but it does not make external solver processes memory-safe. \ No newline at end of file +For untrusted inputs, prefer the Docker container or another sandbox. Do not run untrusted CNF/proof corpora with elevated privileges. External solver binaries are outside this project's trusted computing base; this project verifies SAT/UNSAT verdicts, but it does not make external solver processes memory-safe. diff --git a/backend/cli.py b/backend/cli.py index 91bb715..fbd4886 100644 --- a/backend/cli.py +++ b/backend/cli.py @@ -194,10 +194,13 @@ async def main(): sys.exit(1) +def cli_main(): + """Synchronous console-script entry point (see pyproject.toml).""" def main_cli(): """Synchronous console-script entry point for pyproject.toml.""" asyncio.run(main()) if __name__ == '__main__': + cli_main() main_cli() diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..76a8717 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,13 @@ +# Minimal GitHub Pages config — austere by intent (plain Markdown, no theatre). +# Serve from /docs on the default branch: Settings → Pages → Source: main /docs. +title: λSAT +description: >- + Certified frame-first SAT middleware — structured regions before CDCL, + certified verdicts after every path. +theme: jekyll-theme-minimal +show_downloads: false + +# Keep the research subtrees out of the built site index (still browsable on GitHub). +exclude: + - vdis/ + - __pycache__/ diff --git a/docs/assets/architecture.mmd b/docs/assets/architecture.mmd new file mode 100644 index 0000000..b638e47 --- /dev/null +++ b/docs/assets/architecture.mmd @@ -0,0 +1,19 @@ +%% λSAT architecture — the certified frame-first router. +%% Source of truth for the diagram; renders on github.com and via mermaid-cli. +flowchart TD + F([formula]) --> R{router} + R -->|"binary clauses"| IMP["implication frame (2-SAT)
SCC contradiction / assignment"] + R -->|"XOR structure"| PAR["parity frame (GF(2))
Gaussian refutation / model"] + R -->|"pigeonhole shape"| CNT["counting frame (ℤ)
k > m magnitude contradiction"] + R -->|"none of the above"| CDCL["CDCL fallback (Kissat)"] + + IMP --> OBS([observer — certify]) + PAR --> OBS + CNT --> OBS + CDCL -->|"UNSAT: DRAT replay
SAT: model replay"| OBS + OBS --> V([certified verdict]) + + classDef frame fill:#eef,stroke:#557; + classDef fallback fill:#fee,stroke:#755; + class IMP,PAR,CNT frame; + class CDCL fallback; diff --git a/docs/benchmark-capsule.md b/docs/benchmark-capsule.md new file mode 100644 index 0000000..e721fe5 --- /dev/null +++ b/docs/benchmark-capsule.md @@ -0,0 +1,75 @@ +--- +title: "Benchmark capsule" +--- + +# Benchmark capsule + +Every number here is a **measured** claim on a small, fixed, synthetic mix — **not** the SAT +Competition set, and **not** a claim of general CDCL dominance. Numbers are hardware-sensitive +(wall-clock, core count); regenerate on your machine. Commands and pinned versions: +[REPRODUCIBILITY.md](https://github.com/jesusvilela/lambda-sat-solver/blob/main/REPRODUCIBILITY.md). + +## Setup + +| | | +|---|---| +| **engines** | Kissat 4.0.4 · CaDiCaL 3.0.0 · CryptoMiniSat 5.14.7 (pycryptosat) | +| **families** | random-3SAT (α≈4.26) · Tseitin/XOR · XORSAT · pigeonhole (PHP) · mixed | +| **timeout** | 20 s (main mix) · 30 s (random-3SAT tail study) | +| **hardware** | 4 vCPU dev container (portfolio numbers are core-bound) | +| **metric** | solved-count and PAR-2 (timeout counts as 2×) | +| **certification** | every middleware verdict: SAT model-replayed, UNSAT frame-sound or DRAT | + +## Main mix — frame-aware middleware vs raw CDCL and CMS + +`python -m docs.ladder.scripts.metasolver_benchmark` · 40 instances · 20 s + +| family | n | Kissat | CaDiCaL | CryptoMiniSat | **middleware** | +|---|---|---|---|---|---| +| random-3SAT | 9 | 9/9 · 0.12 s | 9/9 · 0.13 s | 9/9 · 0.18 s | 9/9 · 0.23 s | +| Tseitin (parity) | 9 | 5/9 · 18.98 s | 5/9 · 18.83 s | 9/9 · 0.95 s | **9/9 · 0.00 s** | +| XORSAT | 12 | 12/12 · 0.00 s | 12/12 · 0.00 s | 12/12 · 0.00 s | 12/12 · 0.00 s | +| PHP (counting) | 4 | 3/4 · 10.77 s | 4/4 · 0.12 s | **2/4 · 24.51 s** | **4/4 · 0.00 s** | +| mixed | 6 | 6/6 · 0.00 s | 6/6 · 0.00 s | 6/6 · 0.00 s | 6/6 · 0.01 s | +| **total** | 40 | 35/40 · 5.38 s | 36/40 · 4.28 s | 38/40 · 2.71 s | **40/40 · 0.05 s** | + +CryptoMiniSat is the strongest baseline (38/40): its Gaussian engine **owns parity** (9/9 +Tseitin, where the raw CDCL engines get 5/9). It carries **no counting engine**, so +pigeonhole is exponential for it (php10/php12 time out) while the counting frame is instant. + +## Random-3SAT tail — the honest tunnel + +`python -m docs.ladder.scripts.metametasolver_benchmark` · n=220–280 · 30 s + +| solver | solved | PAR-2 (wall) | +|---|---|---| +| single Kissat (1 core) | 15/16 | ~5.3 s | +| CryptoMiniSat (1 core) | 14/16 | 10.01 s | +| fractal portfolio (~nproc cores) | 15/16 | 6.22 s — beats CMS wall-clock on 13/16 | + +The portfolio's advantage over CMS is a **parallel, mixed-strategy** effect (heavy-tailed +runtime collapsed by diversified seeds), paid for in `k×` CPU. On few cores it shrinks. It is +**not** a smarter search, and it does **not** beat a single strong Kissat by much on this box. + +## What improves + +- **Counting**: instant certified refutation where CDCL and CMS are exponential (PHP). +- **Parity**: instant certified verdict; even CMS's Gaussian engine is matched or beaten in + wall-clock by the direct GF(2) refutation. +- **Aggregate PAR-2 on this mix**: dominated by the structured families the frames own. + +## What does **not** improve + +- **Random-3SAT**: no exposed frame; the middleware falls to CDCL and is only *comparable* — + CMS is competitive-to-faster there. This is CDCL's territory and stays that way. +- **Single-thread on obfuscated structure**: if the XOR/counting structure is hidden from the + cheap detectors, the frame does not fire. +- **Trivial instances under certification**: the DRAT proof of a trivial CDCL UNSAT can cost + more than the solve — an uncertified solver returns faster. That is the price of proof, and + it is intentional. + +## One-line reading + +> On a mix that includes the counting and parity fragments, certified frame routing decides +> the structured islands instantly and provably, and hands the unstructured tail to CDCL. The +> advantage is structural and scoped — not a generally faster SAT solver. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..b462440 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,151 @@ +--- +title: "λSAT — Certified Frame-First SAT Middleware" +description: "Structured regions before CDCL. Certified verdicts after every path." +--- + +# λSAT + +### Certified frame-first SAT middleware + +*Structured regions before CDCL. Certified verdicts after every path.* + +λSAT is a certified SAT middleware. **It does not try to replace CDCL.** It first checks +whether a formula belongs to one of several structured regions with sound algebraic +certificates — implication, parity, or counting — and falls back to CDCL otherwise. Every +emitted verdict is independently checked. + +That is the whole recognizer. The geometry comes later, and only as a map. + +--- + +## 1 · The question + +Modern SAT solvers are extremely strong, but a solver's *output* is not by itself an +*explanation*. λSAT asks a smaller, answerable question: + +> Can some structured SAT regions be recognized and certified **before** search, while the +> unstructured tail is handed honestly to CDCL? + +This deliberately avoids the dangerous claim of "a new solver that beats SOTA." + +--- + +## 2 · Certification — the trusted computing base + +This is the part that matters most. + +- **SAT** is checked by **model replay** against the original formula. +- **UNSAT** is checked by either a **sound frame refutation** (self-certifying) or an + **independent DRAT proof replay** (`drat-trim`). +- **Kissat, CaDiCaL, CryptoMiniSat are tools, not trusted authorities.** + +The middleware can be wrong only if a *checker or a frame* is wrong — never merely because +an external solver said so. A wrong answer from the engine is **caught, not believed.** + +``` +formula + │ + ▼ +router ── implication? ─ yes ─▶ 2-SAT frame ─────┐ + │ parity? ─ yes ─▶ GF(2) frame ─────┤ + │ counting? ─ yes ─▶ counting frame ──┤ sound by construction + │ │ + └── none of the above ─────▶ CDCL (Kissat) ─────┤ DRAT / model replay + ▼ + certified verdict +``` + +--- + +## 3 · The three frames + +Each structured region has one sound, engine-independent frame, with an input condition, a +certificate, and an honest failure mode (it *punts* to CDCL rather than guessing). + +| frame | structure | certificate | +|---|---|---| +| **implication** | 2-SAT / implication graph | SCC contradiction, or an assignment | +| **parity** | GF(2) / XOR structure | linear-algebra refutation or model | +| **counting** | pigeonhole / cardinality | an arithmetic (magnitude) contradiction | +| **fallback** | general SAT | CDCL + model replay / DRAT | + +The contribution is **not** replacing CDCL. It is **deciding structured islands before +CDCL, and certifying every emitted verdict.** + +--- + +## 4 · What the benchmark claims — and doesn't + +The benchmark claim is **scoped to the included mix** (a small, fixed, synthetic set: +2-SAT, Tseitin/XOR, pigeonhole, random-3SAT, mixed). It does **not** imply general CDCL +dominance. + +| family | why hard for CDCL | λSAT route | result shape | +|---|---|---|---| +| 2-SAT / implication | implication closure | implication frame | instant · certified | +| Tseitin / XOR | parity obstruction | GF(2) frame | instant · certified | +| PHP / counting | cardinality obstruction | counting frame | instant · certified | +| random-3SAT | no exposed frame | CDCL / portfolio | **CDCL remains central** | + +Numbers (PAR-2, per-family) live in the [benchmark capsule](benchmark-capsule.md), not on +this page — the headline is the *routing and certification*, not a speed record. + +--- + +## 5 · What it does **not** claim + +- It does **not** solve SAT hardness. +- It does **not** dominate CDCL on arbitrary SAT. +- It does **not** claim CryptoMiniSat is weak on XOR (CMS owns parity; the frame merely + re-derives it with a certificate). +- It does **not** make external solvers trusted. +- The hyperbolic / fabric layer is a **research map**, not part of the minimal certification + claim. + +--- + +## 6 · Reproduce + +```bash +git clone https://github.com/jesusvilela/lambda-sat-solver +cd lambda-sat-solver +pip install -e ".[dev]" +python -m pytest backend/tests/ -q # the soundness / certification floor +``` + +The certified strict path (requires Kissat + `drat-trim`): + +```bash +python -m backend.cli examples/simple_sat.cnf --mode strict # SAT, model-replayed +python -m backend.cli examples/simple_unsat.cnf --mode strict # UNSAT, checked +``` + +Full environment, pinned versions, and per-benchmark commands: +[REPRODUCIBILITY.md](https://github.com/jesusvilela/lambda-sat-solver/blob/main/REPRODUCIBILITY.md). + +--- + +## 7 · The research ladder (a map, not a proof) + +Only after the engineering is clear: the research layer studies *where SAT hardness lives* — +resolution width, Nullstellensatz degree, parity, counting, symmetry, and heavy-tailed +search. Honestly: + +- resolution width and Nullstellensatz degree are **incomparable** (neither dominates); +- cheap graph-structural scalars **failed** to carry random-3SAT hardness; +- the geometry is used as a **routing / modeling lens**, not as proof by metaphor. + +Index: [`docs/ladder/`](ladder/). Claim discipline: [`docs/CHARTER.md`](CHARTER.md). + +--- + +## Links + +- [Repository](https://github.com/jesusvilela/lambda-sat-solver) +- [Technical note](technical-note.md) · [Benchmark capsule](benchmark-capsule.md) +- [Reproducibility](https://github.com/jesusvilela/lambda-sat-solver/blob/main/REPRODUCIBILITY.md) + · [Claim ledger](https://github.com/jesusvilela/lambda-sat-solver/blob/main/PUBLIC_RESEARCH_CLAIMS.md) +- [Security policy](https://github.com/jesusvilela/lambda-sat-solver/blob/main/SECURITY.md) + · [Citation](https://github.com/jesusvilela/lambda-sat-solver/blob/main/CITATION.cff) + +*Route when structure is sufficient. Search when it is not. Verify either way.* diff --git a/docs/ladder/README.md b/docs/ladder/README.md index 71652a4..3ef7790 100644 --- a/docs/ladder/README.md +++ b/docs/ladder/README.md @@ -10,6 +10,10 @@ and every rung says so. - **Two genuine hardness carriers, theorem-backed.** `min_refutation_width` (Ben-Sasson–Wigderson: width lower-bounds resolution size) and `nullstellensatz_degree` (Clegg–Edmonds–Impagliazzo: PC degree lower-bounds + PC size). They are related but **incomparable** — neither dominates: PHP(3→2) + has NS 4 > width 2, while Tseitin K4 has NS 3 < width 4 (measured, both + directions; test `test_ns_and_width_are_incomparable`). Both are exact and + exponential — the right object is genuinely expensive. PC size). They are exact, expensive, and **incomparable**: PHP(3→2) separates one way (NS 4 > width 2), while Tseitin K4 separates the other way (NS 3 < width 4). The right object is genuinely stratified, not one scalar. @@ -32,6 +36,9 @@ and every rung says so. ## What's proven vs open - **Proven / measured:** the two size lower bounds (BSW, CEI) as theorems the + carriers compute against; the Rung-1 negative on our own instances; NS and + width **incomparable** (PHP 4>2, Tseitin K4 3<4); the char-2 collapse of the + naive symmetry channel. carriers compute against; the Rung-1 negative on our own instances; width and Nullstellensatz degree as distinct, mutually non-dominating carriers; the char-2 collapse of the naive symmetry channel. diff --git a/docs/technical-note.md b/docs/technical-note.md new file mode 100644 index 0000000..a762d5d --- /dev/null +++ b/docs/technical-note.md @@ -0,0 +1,116 @@ +--- +title: "Structured Islands Before CDCL — A Certified SAT Middleware" +--- + +# Structured Islands Before CDCL + +### A certified SAT middleware + +*A narrow, reviewable note: here is the executable claim, here is the certification +boundary, here is where CDCL remains sovereign.* + +## Abstract + +λSAT is a headless SAT middleware that decides *structured* formulas before search and +hands the rest to CDCL. A router tries three sound, engine-independent frames — +implication (2-SAT), parity (GF(2)/XOR), and counting (pigeonhole/cardinality) — and their +cross-frame coupling; a formula that lives in one is decided with a certificate and no +search. Anything else returns `CDCL_NEEDED` and is solved by Kissat. **Every emitted verdict +is independently checked**: SAT by model replay, UNSAT by a sound frame refutation or a +`drat-trim` DRAT proof. The external solver is never a trusted authority. The benchmark +claim is scoped to a small synthetic mix that includes the counting and parity fragments; +it is a statement about *certified frame routing*, not about generally out-searching CDCL. + +## 1 · Motivation + +SAT solvers are powerful, and getting a formula *solved* is rarely the problem. The problem +addressed here is narrower: some formulas carry structure whose contradiction is decidable +by a short algebraic argument **before** any search, and that argument is its own +certificate. λSAT separates that structured decision from unstructured search, and — the +non-negotiable part — verifies whatever it emits. + +## 2 · Architecture + +``` +formula → router → { implication | parity | counting | coupling } → verdict → observer + └───────────── else: CDCL_NEEDED ──────────→ Kissat → observer +``` + +The router is refute-first (cheap near-linear refutation before any model reconstruction). +The observer is the certification stage: it accepts a verdict only with a checkable +certificate. `strict` mode requires the external tools to be present at startup and turns an +uncertified fallback verdict into an error; `dev`/`research` modes degrade to best-effort. + +## 3 · The three frames + +Each frame has an **input condition**, a **certificate**, and a **failure mode** (it must +punt, never guess). + +- **Implication (2-SAT).** Condition: binary clauses. Certificate: a strongly-connected + component placing a variable and its negation together (a sound UNSAT), or a satisfying + assignment. Failure: no binary contradiction → punt. +- **Parity (GF(2)).** Condition: recoverable XOR constraints. Certificate: Gaussian + elimination reaching `0 = 1` (UNSAT), or a reconstructed, re-verified model. Failure: + parity does not cover the formula / underdetermined → punt. +- **Counting (ℤ).** Condition: pigeonhole-shaped `k` disjoint at-least-one clauses covered + by `m < k` at-most-one cliques. Certificate: the magnitude contradiction `k > m`. Failure: + structure absent → punt. + +The **coupling** exchanges entailed literals across frames to a fixpoint (Nelson–Oppen), so +an instance no single frame decides can still be decided soundly; it too only emits UNSAT via +a channel refutation or SAT via a verified model. + +## 4 · Certification boundary + +| | trusted | not trusted | +|---|---|---| +| components | DIMACS parser · Tseitin transform · model checker · the three frame refutations · the DRAT-checker invocation | Kissat · CaDiCaL · CryptoMiniSat | + +- **SAT** → the assignment is replayed against the original clauses. +- **UNSAT via a frame** → sound by construction (no external checker). +- **UNSAT via CDCL** → the DRAT proof is replayed by `drat-trim` (LRAT optional). + +A CI lane (`certification-hard`) makes Kissat + `drat-trim` mandatory and fails red unless a +real DRAT UNSAT check and a real model-replay SAT check both execute. + +## 5 · Benchmark capsule + +Full detail in the [benchmark capsule](benchmark-capsule.md). In one paragraph: on a fixed +synthetic mix (random-3SAT, Tseitin, XORSAT, pigeonhole, mixed; 20 s timeout), the +frame-aware middleware decides the structured families instantly and certified, while raw +CDCL and CryptoMiniSat spend seconds or time out on the parity/counting families. On the +unstructured random-3SAT tail the middleware falls to CDCL and is **comparable**, not +better. The aggregate PAR-2 advantage is therefore a *structural* effect of the mix, not a +faster search. + +## 6 · Interpretation + +- **Frame-decidable islands** vs the **CDCL tunnel** — a formula either exposes an algebraic + obstruction (decide + certify) or it does not (search). +- A parallel, seed-diversified **portfolio** helps only on the heavy-tailed tail, and only by + spending cores for wall-clock; it is a mixed strategy, not a smarter search. +- **No-Free-Lunch holds.** There is no general dominance here, and none is claimed. + +## 7 · Limitations + +- The benchmark mix is **not** the SAT Competition set. +- Frames fire **only** when structure is exposed; obfuscated structure is missed. +- Random-3SAT is, and remains, **CDCL territory**. +- Strict-mode UNSAT via the fallback still requires external proof tooling (`drat-trim`). + +## 8 · Reproduction + +```bash +pip install -e ".[dev]" +python -m pytest backend/tests/ -q +python .github/scripts/certification_smoke.py # forces a real DRAT + model-replay check +``` + +Pinned versions, per-benchmark commands, and how to read a discrepancy: +[REPRODUCIBILITY.md](https://github.com/jesusvilela/lambda-sat-solver/blob/main/REPRODUCIBILITY.md). + +## 9 · Conclusion + +λSAT is a claim-discipline artifact as much as a solver: **route when structure is +sufficient, search when it is not, verify either way.** The interesting object is the +certified boundary between the two — not a speed record. diff --git a/pyproject.toml b/pyproject.toml index 7ce5d89..36957e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,43 @@ [build-system] +requires = ["setuptools>=61.0", "wheel"] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] name = "lambda-sat-solver" version = "0.1.0" +description = "Certified λ-logic SAT middleware and a research harness for frame-structured SAT hardness" +readme = "README.md" +requires-python = ">=3.11" +license = { file = "LICENSE" } +authors = [{ name = "Jesús Vilela Franco" }] +keywords = [ + "SAT", "satisfiability", "solver", "certified", "DRAT", "proof-checking", + "Kissat", "CryptoMiniSat", "computational-complexity", "lambda-calculus", +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: Mathematics", +] +dependencies = [ + "numpy>=1.24.0", + "pydantic>=2.0.0", + # CryptoMiniSat baseline used by backend/cms_wrapper.py and the benchmarks. + # It is a *competitor* the metasolver is measured against, not part of the + # certified solve path; kept as a core dep so the test suite runs as shipped. + "pycryptosat>=5.11.0", +] + +[project.optional-dependencies] +dev = ["pytest>=7.4.0", "pytest-asyncio>=0.21.0"] +bench = ["pycryptosat>=5.11.0"] + +[project.scripts] +lambda-sat = "backend.cli:cli_main" description = "Certified SAT middleware and frame-structured SAT hardness research harness" readme = "README.md" requires-python = ">=3.11" @@ -50,6 +83,17 @@ Homepage = "https://github.com/jesusvilela/lambda-sat-solver" Repository = "https://github.com/jesusvilela/lambda-sat-solver" Issues = "https://github.com/jesusvilela/lambda-sat-solver/issues" +# External, non-pip tools are required for full certification (not installable via +# pip): the Kissat SAT solver and the drat-trim DRAT checker (LRAT optional). +# The three sound frames are self-certifying and need neither. See BACKEND_README.md. + +[tool.setuptools.packages.find] +where = ["."] +include = ["backend*"] +exclude = ["backend.tests*"] + +[tool.pytest.ini_options] +testpaths = ["backend/tests"] [project.scripts] lambda-sat = "backend.cli:main_cli" @@ -58,4 +102,4 @@ include = ["backend*"] [tool.pytest.ini_options] testpaths = ["backend/tests"] -pythonpath = ["."] \ No newline at end of file +pythonpath = ["."]