[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"uZTXffFkrd":3},"# Hardness Reductions in Lean\n\n[![CI](https://github.com/DominikPeters/HardnessReductionsLean/actions/workflows/lean_action_ci.yml/badge.svg)](https://github.com/DominikPeters/HardnessReductionsLean/actions/workflows/lean_action_ci.yml)\n\nA [Lean 4](https://lean-lang.org/) / [mathlib](https://github.com/leanprover-community/mathlib4)\nlibrary of NP-hardness reductions, organized as a Garey–Johnson-style catalog\nof hard problems: machine-checked proofs of the classical reduction\nconstructions — SAT → 3SAT, SAT → CLIQUE, VERTEX COVER → SUBSET SUM, … —\ntogether with a certificate layer that pins down, syntactically, that the\nreduction maps are polynomial-time.\n\nThere is no Turing machine in this library, and no formalization of P or NP.\nThat is the design, not a shortcut, and it is what keeps the library light\nenough to grow the way the informal catalog literature does.\n\n## The idea\n\nA textbook NP-hardness proof has two parts of very different character. The\nheart is combinatorial: a gadget construction, and an argument that\nyes-instances map to yes-instances and back. The other part is resource\naccounting — \"the construction is clearly polynomial\" — which the literature\nsettles by inspection, because for honest constructions it is visibly true,\nand writing it out against a machine model would add nothing to the\nmathematics.\n\nA formalization that starts from a machine model must pay for the routine part\nfirst, and pay dearly: structured instances become strings, gadget\nconstructions become machine programs, and resource bookkeeping runs through\nevery proof. This library decouples the two parts instead, so that each can be\ndone in the style appropriate to it.\n\n**The mathematical layer.** A problem is a predicate on structured instances,\nand a reduction is a map together with a correctness proof:\n\n```lean\ndef Problem (α : Type u) := α → Prop\n\nstructure Reduction (P : Problem α) (Q : Problem β) where  -- notation: P ⟶ᵣ Q\n  map : α → β\n  correct : ∀ x, P x ↔ Q (map x)\n```\n\nInstances are bundled structures over mathlib types (`SimpleGraph`, CNF\nformulas, lists of numbers), so the correctness arguments — the actual\nmathematics — are carried out with mathlib's ordinary APIs, at the level of\nabstraction the informal proofs use. No resource bounds appear anywhere in\nthis layer.\n\n**The certificate layer.** Separately,\n[`Cert/Language.lean`](HardnessReductions/Cert/Language.lean) defines a small\ndeep-embedded combinator language `Code σ τ` over a closed universe of\nfirst-order types (numbers, booleans, pairs, lists), with an explicit cost\nmodel that charges numbers by bit length. The language is designed so that a\nsingle theorem, proven once for all programs, gives the resource bound:\n\n```lean\ntheorem Code.cost_size_le_polyBound (c : Code σ τ) :\n    ∃ C d, ∀ x, c.cost x + τ.size (c.eval x) ≤ C * (σ.size x + 1) ^ d\n```\n\nA reduction is *certified* by exhibiting its instance map as a `Code` program\nand proving that program correct on concrete instances\n([`Cert/Bridge.lean`](HardnessReductions/Cert/Bridge.lean)). The polynomial\nbound then comes for free: there are no per-reduction cost proofs anywhere in\nthe library, just as there are none in the literature. Certified reductions\ncompose, and the certificate of a composite is the composite program. The\nrecurring proof obligation of an adequacy file — realizing a gadget's tagged\nvertex or element names as positions of the emitted list — is served by a\nblock-numbering layer\n([`Cert/Numbering.lean`](HardnessReductions/Cert/Numbering.lean)): a layout is\ncomposed from digit and block combinators, and its bound, injectivity, and\nbijection onto the positions are read off rather than re-proved.\n\n**The representation layer.** The two layers meet at concrete instances: each\nabstract problem has a concrete counterpart, defined by pulling the predicate\nback along a total decoder (`Concrete.CLIQUE x = CLIQUE (decodeGraph x)`),\nand certificates speak about the concrete problems. That the concrete problem\nfaithfully *represents* the abstract one is itself a theorem, once per\nproblem: encoding any bundled instance and decoding the result reproduces it\nup to isomorphism, giving a reduction pair `CLIQUE ⟶ᵣ Concrete.CLIQUE` and\nback ([`Graph/Representation.lean`](HardnessReductions/Graph/Representation.lean)).\nComposing through such a pair turns a certified reduction between concrete\nproblems into the reduction between the abstract ones, so a degenerate\ndecoder cannot hide: what the certified pipeline proves about the abstract\nproblems is a theorem, not a reading of the decoder. **Every problem in the\ncatalog carries its representation pair**, one `Representation.lean` per\ndomain, and the pairs of different domains compose — VERTEX COVER → SET COVER\nis recovered abstract-to-abstract with nothing but certificates in between.\n\n**Unary avatars, and strong hardness.** A number problem has two concrete\ncounterparts: the numbers written in binary, and the numbers written in unary\n(a unary `n` is a list of length `n`, so the existing size model *is* the\nunary model — no second size function). Hardness proved against the unary\navatar is the formal content of \"strongly NP-hard\", and the two avatars are\nnot symmetric. Unary → binary is a program, so hardness transfers along it;\nbinary → unary is not a program at all, and that is a theorem here rather\nthan a convention — `no_binary_to_unary`\n([`Numbers/Representation.lean`](HardnessReductions/Numbers/Representation.lean))\nreads the blanket cost bound as a lower bound, with an explicit input size at\nwhich any monomial bound is exceeded.\n\n**The deferred bridge.** What this library does not contain is a theorem\nconnecting the cost model to a machine model of polynomial time — mathlib does\nnot yet have one to connect to. The interface is deliberately a single point:\nwhen a machine model of FP lands in mathlib, one theorem (\"the `Code`\ninterpreter runs in polynomial time\") turns every certificate in this catalog\ninto a machine-model Karp reduction, with no per-reduction work. Until then,\nthe precise claim of a certificate is: *the map is expressed in a language in\nwhich only polynomial-cost, polynomial-size transformations can be written*,\nfor a cost model designed to be honest (see the size discipline below).\n\n## The catalog\n\nReductions are filed under their **target** problem — each is a proof that the\ntarget is hard, and every reduction in the catalog is certified in the `Code`\nlayer. The picture keeps one arrow per construction; twenty\nfurther edges\nexist in the library as one-line derivations — composites, and the weakening\n3SAT → SAT (an instance of `CertifiedReduction.ofRestrict`, whose width test\nis a program) — and are omitted to keep it readable.\n\n```mermaid\nflowchart LR\n  subgraph Logic\n    SAT\n    SAT3[\"3SAT\"]\n    OCC3[\"3SAT, clauses of length 2–3,\u003Cbr>≤3 occurrences per variable\"]\n    NAE3[\"NOT-ALL-EQUAL 3SAT\"]\n    O13[\"ONE-IN-THREE 3SAT\"]\n    MO13[\"MONOTONE\u003Cbr>ONE-IN-THREE 3SAT\"]\n    M2SAT[\"MAX 2SAT\"]\n  end\n  subgraph Graphs\n    CLIQUE\n    IS[\"INDEPENDENT SET\"]\n    VC[\"VERTEX COVER\"]\n    VCD3[\"VERTEX COVER,\u003Cbr>maximum degree ≤ 3\"]\n    DS[\"DOMINATING SET\"]\n    COL[\"K-COLORABILITY\"]\n    COL3[\"3-COLORABILITY\"]\n    CC[\"CLIQUE COVER\"]\n    SMC[\"SIMPLE MAX CUT\"]\n    HC[\"HAMILTONIAN CIRCUIT\"]\n    HP[\"HAMILTONIAN PATH\"]\n    SGI[\"SUBGRAPH ISOMORPHISM\"]\n  end\n  subgraph Digraphs\n    FVS[\"FEEDBACK VERTEX SET\"]\n    FAS[\"FEEDBACK ARC SET\"]\n  end\n  subgraph Networks\n    TSP[\"TRAVELING SALESMAN\"]\n    ST[\"STEINER TREE\"]\n  end\n  subgraph Scheduling\n    MPS[\"MULTIPROCESSOR SCHEDULING\"]\n    SS1[\"SEQUENCING WITH RELEASE\u003Cbr>TIMES AND DEADLINES\"]\n  end\n  subgraph Sets\n    SC[\"SET COVER\"]\n    HS[\"HITTING SET\"]\n    SP[\"SET PACKING\"]\n    M3D[\"3-DIMENSIONAL MATCHING\"]\n    X3C[\"EXACT COVER BY 3-SETS\"]\n    SPL[\"SET SPLITTING\"]\n  end\n  subgraph Ordering\n    BTW[\"BETWEENNESS\"]\n  end\n  subgraph Numbers\n    SS[\"SUBSET SUM\"]\n    PART[\"PARTITION\"]\n    KNAP[\"KNAPSACK\"]\n    BP[\"BIN PACKING\"]\n    P4[\"4-PARTITION\"]\n    P3[\"3-PARTITION\"]\n  end\n  SAT --> SAT3\n  SAT --> OCC3\n  SAT --> M3D\n  M3D --> X3C\n  X3C --> ST\n  SAT --> CLIQUE\n  CLIQUE --> IS\n  IS --> CLIQUE\n  IS --> VC\n  VC --> IS\n  VC --> DS\n  VC --> SC\n  VC --> HS\n  IS --> SP\n  VC --> SS\n  VC --> FVS\n  VC --> FAS\n  VC --> HC\n  HC --> HP\n  HC --> TSP\n  SS --> PART\n  SS --> KNAP\n  PART --> BP\n  P3 --> BP\n  BP --> MPS\n  BP --> SS1\n  M3D --> P4\n  P4 --> P3\n  SAT3 --> NAE3\n  SAT3 --> O13\n  O13 --> MO13\n  NAE3 --> SPL\n  NAE3 --> BTW\n  CLIQUE --> SGI\n  SAT3 --> M2SAT\n  M2SAT --> SMC\n  SAT3 --> VCD3\n  SAT --> COL3\n  COL3 --> COL\n  COL --> CC\n```\n\n- **SAT** ([`Logic/Sat.lean`](HardnessReductions/Logic/Sat.lean)) — the root\n  of the catalog: satisfiability of CNF formulas over an explicit variable\n  list. No reduction lands here; every hardness claim below traces back to it.\n- **3SAT** ([`Logic/Sat3.lean`](HardnessReductions/Logic/Sat3.lean)) — hard\n  from SAT (clause splitting: each long clause becomes a chain of width-3\n  clauses linked by fresh chain variables; short clauses, including the empty\n  clause, are kept as they are).\n- **3SAT with clauses of length 2 or 3 and at most 3 occurrences per\n  variable** ([`Logic/Sat3/BoundedOcc.lean`](HardnessReductions/Logic/Sat3/BoundedOcc.lean))\n  — hard from SAT and from 3SAT (one fresh variable per occurrence,\n  linked by an implication cycle). Length-2 clauses are essential: by\n  Tovey's theorem, the exactly-length-3 variant is always satisfiable.\n- **NOT-ALL-EQUAL 3SAT** ([`Logic/Nae3Sat.lean`](HardnessReductions/Logic/Nae3Sat.lean))\n  — hard from 3SAT (one fresh variable per clause plus one global variable\n  standing in for the constant `false`). Its restriction is clause width\n  *exactly* three, where 3SAT's is at most three: each entry states the\n  sharpest restriction its own construction delivers.\n- **ONE-IN-THREE 3SAT** ([`Logic/OneInThree3Sat.lean`](HardnessReductions/Logic/OneInThree3Sat.lean))\n  — hard from 3SAT (each clause becomes a three-clause chain over four fresh\n  variables, under a block of clauses forcing one global variable false). The\n  third question the catalog asks of a width-3 formula: *exactly* one literal\n  true per clause, beside 3SAT's *some* and NOT-ALL-EQUAL 3SAT's *some but not\n  all*. Exactly-one satisfaction is not invariant under complementing the\n  assignment, so a variable to be held false is forced by clauses rather than\n  assumed.\n- **MONOTONE ONE-IN-THREE 3SAT** ([`Logic/OneInThree3Sat/Monotone.lean`](HardnessReductions/Logic/OneInThree3Sat/Monotone.lean))\n  — hard from ONE-IN-THREE 3SAT (one companion variable per variable, pinned to\n  its complement, replacing every negated literal). No negated literal occurs\n  anywhere, so a clause is a three-element set and a satisfying assignment an\n  exact cover. Distinct from MONOTONE 3SAT, which asks ordinary satisfaction of\n  a formula whose clauses are each all-positive or all-negative.\n- **MAX 2SAT** ([`Logic/MaxSat.lean`](HardnessReductions/Logic/MaxSat.lean))\n  — hard from 3SAT (ten clauses of width at most two per source clause, over\n  one fresh variable; threshold seven per clause). A *counting* predicate —\n  the question is how many clauses an assignment satisfies — which is what\n  makes width two hard: asking whether *all* clauses of a 2CNF hold is 2SAT.\n- **CLIQUE** ([`Graph/Clique.lean`](HardnessReductions/Graph/Clique.lean)) —\n  hard from SAT (the occurrence graph: a vertex per literal occurrence,\n  adjacency between non-conflicting occurrences in distinct clauses,\n  threshold the number of clauses), from INDEPENDENT SET (complementation),\n  and from VERTEX COVER.\n- **INDEPENDENT SET** ([`Graph/IndepSet.lean`](HardnessReductions/Graph/IndepSet.lean))\n  — hard from CLIQUE (complementation), from VERTEX COVER (a set is\n  independent iff its complement is a cover), and from SAT.\n- **VERTEX COVER** ([`Graph/VertexCover.lean`](HardnessReductions/Graph/VertexCover.lean))\n  — hard from INDEPENDENT SET (the same complementation, read the other way)\n  and from SAT.\n- **VERTEX COVER on graphs of maximum degree at most three**\n  ([`Graph/VertexCover/BoundedDegree.lean`](HardnessReductions/Graph/VertexCover/BoundedDegree.lean))\n  — hard from 3SAT (a cyclic `T`/`F` circuit per variable, a triangle per\n  clause, one connection edge per literal). Stated as `≤ 3` rather than\n  `= 3`: the construction is not cubic, and degree `≤ 2` is polynomial, so\n  this is the sharpest of the `≤`-bounds.\n- **DOMINATING SET** ([`Graph/DominatingSet.lean`](HardnessReductions/Graph/DominatingSet.lean))\n  — hard from VERTEX COVER (the edge-vertex gadget: one fresh vertex per\n  edge, joined to both endpoints, so every edge becomes a triangle; the\n  threshold `k + #isolated` absorbs the textbook's \"WLOG no isolated\n  vertices\").\n- **GRAPH K-COLORABILITY** and **GRAPH 3-COLORABILITY**\n  ([`Graph/Colorability.lean`](HardnessReductions/Graph/Colorability.lean),\n  [`Graph/Colorability3/FromSat.lean`](HardnessReductions/Graph/Colorability3/FromSat.lean))\n  — the two problems ask different questions of one Garey–Johnson instance —\n  a graph and a number, read as the palette size — so they share an instance\n  type, with 3-COLORABILITY the `k = 3` restriction, promoted to its own\n  entry as 3SAT is. 3-COLORABILITY is hard from *unrestricted* SAT (the\n  palette gadget: a `T`/`F`/`B` triangle names the colours, a polarity pair\n  per variable is the assignment, a chain of OR components per clause checks\n  it; seeding each chain at a vertex forced to `F`'s colour handles clauses\n  of every width uniformly). K-COLORABILITY is hard from 3-COLORABILITY by\n  weakening (a program tests the palette size, as the 3SAT → SAT weakening\n  tests clause width).\n- **CLIQUE COVER** ([`Graph/CliqueCover.lean`](HardnessReductions/Graph/CliqueCover.lean))\n  — hard from K-COLORABILITY (complementation: a clique of `Gᶜ` is an\n  independent set of `G`, so splitting `Gᶜ` into `k` cliques is colouring `G`\n  with `k` colours); Garey–Johnson's PARTITION INTO CLIQUES [GT15]. The\n  predicate is *defined* as a partition into cliques rather than as\n  `Gᶜ.Colorable k` — the second definition would make the reduction true by\n  definition and prove nothing.\n- **SIMPLE MAX CUT** ([`Graph/MaxCut.lean`](HardnessReductions/Graph/MaxCut.lean))\n  — hard from MAX 2SAT (Garey–Johnson–Stockmeyer's Theorem 1.2: a splitting\n  pass first makes every clause a distinct two-literal pair over one fresh\n  variable per clause; then the GJS framework — two rails joined completely\n  bipartitely, a ladder of `3q + 1` disjoint 3-edge paths per variable, a\n  pair edge plus two rail attachments per clause — makes an aligned\n  bipartition cut exactly `|A₁| + 2·(satisfied pairs)`, while misalignment\n  costs more than the clause edges can repay). Unit weights only: the weighted\n  MAX CUT [ND16] belongs to the network domain, and this entry will become its\n  restriction.\n- **HAMILTONIAN CIRCUIT** ([`Graph/HamiltonianCircuit.lean`](HardnessReductions/Graph/HamiltonianCircuit.lean))\n  — hard from VERTEX COVER (Garey–Johnson's Theorem 3.4: a twelve-node\n  cover-testing component per edge, the components at a vertex strung into a\n  chain, and `k` selector nodes joined to both ends of every chain, so that a\n  circuit may enter exactly `k` chains). The predicate is deliberately not\n  mathlib's `SimpleGraph.IsHamiltonian`, whose one-vertex convention would\n  leak into every gadget proof.\n- **HAMILTONIAN PATH** ([`Graph/HamiltonianPath.lean`](HardnessReductions/Graph/HamiltonianPath.lean))\n  — hard from HAMILTONIAN CIRCUIT (Garey–Johnson [GT39]: duplicate a\n  distinguished vertex and hang a pendant off each copy; a pendant has one\n  neighbour, so it must be an *end* of any Hamiltonian path, and the path\n  between the pendants glues back into a circuit). The gluing is sound only\n  with three or more vertices, so the reduction branches, the degenerate side\n  answering with the empty graph.\n- **SUBGRAPH ISOMORPHISM** ([`Graph/SubgraphIsomorphism.lean`](HardnessReductions/Graph/SubgraphIsomorphism.lean))\n  — hard from CLIQUE (ask for the complete graph on `k` vertices; an injective\n  edge-preserving map out of it is exactly a `k`-clique). The subgraph is not\n  required to be induced. Its instance names two graphs rather than a graph and\n  a number, so the entry carries its own instance type and encoding, and its\n  invariance lemma transports along one bijection per graph.\n- **FEEDBACK VERTEX SET** ([`Digraph/FeedbackVertexSet.lean`](HardnessReductions/Digraph/FeedbackVertexSet.lean))\n  — hard from VERTEX COVER (Karp: orient every edge of the graph both ways,\n  keeping the vertex set and the threshold; a bidirected edge is a two-cycle,\n  so removing a set of vertices leaves an acyclic digraph exactly when that\n  set covers every edge). Acyclicity is irreflexivity of the arc relation's\n  transitive closure, which is what lets the domain state and prove both\n  feedback problems without a directed walk API: a cycle is refuted by\n  exhibiting one short closed chain, and ruled out by exhibiting a rank\n  function that every arc increases.\n- **FEEDBACK ARC SET** ([`Digraph/FeedbackArcSet.lean`](HardnessReductions/Digraph/FeedbackArcSet.lean))\n  — hard from VERTEX COVER (Karp: split each vertex into an in-node and an\n  out-node joined by an internal arc, and route each edge from out-node to\n  in-node in both orientations, so that cutting a vertex's internal arc is\n  what covering that vertex costs). Garey–Johnson's [GT8] and [GT7] ask\n  different questions of one instance — a digraph and a bound — so the two\n  entries share an instance type and an encoding.\n- **TRAVELING SALESMAN** ([`Networks/TravelingSalesman.lean`](HardnessReductions/Networks/TravelingSalesman.lean))\n  — hard from HAMILTONIAN CIRCUIT (Garey–Johnson [ND22], and Karp's: distance\n  `1` along an edge, `2` across a non-edge, budget the number of cities, so a\n  tour comes in on budget exactly when every step is an edge). The entry\n  states the symmetric problem GJ states — distances are `ℕ` with symmetry\n  carried as a field — and its real content is a change of representation:\n  TSP quantifies over *orderings* of the cities where HAMILTONIAN CIRCUIT\n  quantifies over walks, bridged once by\n  `exists_isHamiltonianCycle_iff_exists_equiv`\n  ([`Hamiltonicity.lean`](HardnessReductions/Hamiltonicity.lean)).\n- **STEINER TREE IN GRAPHS** ([`Networks/SteinerTree.lean`](HardnessReductions/Networks/SteinerTree.lean))\n  — hard from EXACT COVER BY 3-SETS (Garey–Johnson [ND12]: a root joined to a\n  vertex per available 3-set, each 3-set joined to its three elements, all\n  weights `1`, the root and the ground elements required, budget `4q` for\n  `|Z| = 3q`). Unit weights make a subtree cost one less than the number of\n  vertices it spans, so the budget bounds how many 3-set vertices a subtree can\n  touch, while covering the elements bounds it from below; the two bounds meet\n  exactly at an exact cover. A subtree is presented as its own carrier\n  (`W : Finset V`) with a tree on it, which is what lets mathlib's `IsTree`\n  state a predicate about spanning `R` rather than spanning `V`.\n- **SET COVER** ([`Sets/SetCover.lean`](HardnessReductions/Sets/SetCover.lean))\n  — hard from VERTEX COVER (cover the edges by vertex stars: a vertex's set\n  is its incident edges, and `k` stars cover the ground set iff the `k`\n  vertices cover the graph).\n- **HITTING SET** ([`Sets/HittingSet.lean`](HardnessReductions/Sets/HittingSet.lean))\n  — hard from VERTEX COVER (a vertex cover *is* a hitting set of the edge\n  system). SET COVER's dual, over the same instance type: the two problem\n  statements are each other's with the roles of positions and elements\n  exchanged.\n- **SET PACKING** ([`Sets/SetPacking.lean`](HardnessReductions/Sets/SetPacking.lean))\n  — hard from INDEPENDENT SET and from CLIQUE (the *same* vertex-star system\n  that SET COVER uses, read the other way round: two distinct vertices are\n  non-adjacent exactly when their stars are disjoint). Composed with\n  complementation, CLIQUE → SET PACKING is Karp's original reduction, whose\n  ground elements are the non-edges.\n- **3-DIMENSIONAL MATCHING** ([`Sets/Matching3D.lean`](HardnessReductions/Sets/Matching3D.lean))\n  — hard from SAT and from 3SAT (Garey–Johnson's three-part construction:\n  truth-setting cycles per variable whose two perfect matchings are \"all\n  true\" and \"all false\", satisfaction-testing triples per clause, and a\n  garbage-collection component absorbing the released elements).\n- **EXACT COVER BY 3-SETS** ([`Sets/ExactCover3.lean`](HardnessReductions/Sets/ExactCover3.lean))\n  — hard from 3-DIMENSIONAL MATCHING, and hence from SAT and 3SAT (merge\n  the three coordinate sets into a disjoint union; the sets are automatically\n  3-element because the three coordinates land in three different summands).\n- **SET SPLITTING** ([`Sets/SetSplitting.lean`](HardnessReductions/Sets/SetSplitting.lean))\n  — hard from NOT-ALL-EQUAL SAT, and so from NOT-ALL-EQUAL 3SAT (the ground set\n  is the literals, the family the complementary pairs together with the\n  clauses). Also known as HYPERGRAPH 2-COLORABILITY: the family is a hypergraph\n  and the two parts are the colours, no hyperedge monochromatic. Garey–Johnson\n  give it no bound, so its instance is a set system minus the threshold; the\n  gadget reads clauses of any width, which is why the source is the unrestricted\n  problem and the width-3 restriction is weakened away in front.\n- **SUBSET SUM** ([`Numbers/SubsetSum.lean`](HardnessReductions/Numbers/SubsetSum.lean))\n  — hard from VERTEX COVER (Karp's base-4 digit construction: one digit\n  position per edge plus a high vertex-counting digit; an edge has only two\n  endpoints, so no digit exceeds `3` and no carries occur).\n- **PARTITION** ([`Numbers/Partition.lean`](HardnessReductions/Numbers/Partition.lean))\n  — hard from SUBSET SUM (adjoin two padding elements, `sum + 1 − t` and\n  `t + 1`: an even split must separate them, and the side of the first one,\n  minus the padding, sums to the target).\n- **KNAPSACK** ([`Numbers/Knapsack.lean`](HardnessReductions/Numbers/Knapsack.lean))\n  — hard from SUBSET SUM (sizes and values both the given numbers, so the\n  capacity bounds from above exactly what the goal bounds from below).\n- **BIN PACKING** ([`Numbers/BinPacking.lean`](HardnessReductions/Numbers/BinPacking.lean))\n  — hard from PARTITION (double every number and ask for two bins of capacity\n  the undoubled total: the doubled sizes total exactly twice the capacity, so\n  both bins are exactly full and one bin's items are an even split), and in the\n  **strong** sense from 3-PARTITION inside its window (the numbers and the bound\n  cross over untouched, with `n/3` bins). Doubling is how the first reduction\n  halves a total in a language with no division, and it dissolves the odd-total\n  case rather than excluding it; in the second, the window is what forces a bin\n  to hold exactly three items, since a bin is exactly full and `k` numbers each\n  between `B/4` and `B/2` summing to `B` leave `2 \u003C k \u003C 4`.\n- **4-PARTITION** ([`Numbers/Partition4.lean`](HardnessReductions/Numbers/Partition4.lean))\n  — hard from 3-DIMENSIONAL MATCHING, even inside the Garey–Johnson window\n  (every size strictly between `B/5` and `B/3`, sizes totalling `m·B`): four\n  base-`r` numbers per triple, the triple itself and one copy for each of its\n  three members, a copy being \"actual\" or \"dummy\" according to whether the\n  triple is that member's designated occurrence. The leading digits are\n  chosen so that `10 + 10 + 10 = 11 + 11 + 8` is the only alternative\n  available to a part, which forces its three copies to be all actual or all\n  dummy. The certificate targets the *unary* encoding of numbers, so the\n  generic cost bound is a bound in the emitted numbers' values.\n- **3-PARTITION** ([`Numbers/Partition3.lean`](HardnessReductions/Numbers/Partition3.lean))\n  — hard from 4-PARTITION inside its window, and inside a window of its own\n  (sizes strictly between `B'/4` and `B'/2`, totalling `m·B'`): one \"regular\"\n  element per number, two \"pairing\" elements of complementary size per ordered\n  pair of numbers, and enough \"filler\" elements to absorb the pairs no part\n  claims. Residues mod `4` force every part to be two regular elements with a\n  pairing element, or two pairing elements with a filler. Where Garey–Johnson\n  finish by repeatedly *exchanging* equal-sized pairing elements, the backward\n  direction here counts value multiplicities instead\n  (`exists_pairs_of_card_symm`), which needs no termination argument. The\n  certificate is unary at both ends, so the hardness it carries is strong.\n- **MULTIPROCESSOR SCHEDULING** ([`Scheduling/MultiprocessorScheduling.lean`](HardnessReductions/Scheduling/MultiprocessorScheduling.lean))\n  — hard from BIN PACKING, and hence from PARTITION (sizes become task lengths,\n  bins processors, the capacity the deadline; a packing becomes a schedule by\n  running each bin's items back to back, and a schedule becomes a packing by\n  interval colouring — paint the last-starting task last, and everything it\n  conflicts with is running at its own start instant, so at most `m − 1` colours\n  are blocked). The problem is stated as Garey–Johnson state it, with start\n  times and a load bound and no mention of which processor runs what; stating it\n  as a partition into groups would have been stating BIN PACKING, and would have\n  made the reduction true by `rfl`.\n- **SEQUENCING WITH RELEASE TIMES AND DEADLINES** ([`Scheduling/Sequencing.lean`](HardnessReductions/Scheduling/Sequencing.lean))\n  — hard from BIN PACKING, and hence in the **strong** sense from 3-PARTITION\n  inside its window, which is Garey–Johnson's own statement (the bins become\n  blocks of the time line: `m − 1` unit *enforcer* tasks, each released one\n  instant before its deadline, can only run in the single instant separating two\n  consecutive blocks, and the item tasks share the deadline where the last block\n  ends, so an item task can neither straddle two blocks nor overrun the horizon).\n  Garey–Johnson reduce from 3-PARTITION directly; nothing in the construction\n  uses the window, so the catalog reduces from BIN PACKING and recovers their\n  statement by composition.\n- **BETWEENNESS** ([`Ordering/Betweenness.lean`](HardnessReductions/Ordering/Betweenness.lean))\n  — hard from NOT-ALL-EQUAL 3SAT (one element is a centre, and an element's\n  truth value is which side of the centre it falls on, so that a triple\n  `(u, centre, v)` says \"`u` and `v` disagree\"; three occurrence elements per\n  clause and one fresh element between them force the clause not to be all\n  equal). Given a finite set and a collection of ordered triples, is there an\n  arrangement placing the middle element of each triple strictly between the\n  other two, in either direction? Garey–Johnson's [MS1] reduce from SET\n  SPLITTING; their gadget reads exactly three elements of a set, so it needs\n  that problem restricted to 3-sets, and the catalog reduces from NOT-ALL-EQUAL\n  3SAT instead, whose clauses carry the condition three literals at a time.\n\nThirty-eight problems and sixty reductions, every one certified end to\nend. Keeping the correctness catalog and the certified catalog equal is the\nstanding milestone — the library's thesis is that certification is cheap\nenough to be universal — so a new entry lands with its certificate or\nacquires one before the next entry starts. Certified reductions compose (the\ncertificate of a composite is the composite program), and every entry carries\nits representation theorems (`\u003CDomain>/Representation.lean`, all eight\ndomains): each abstract problem reduces to its concrete encoding and back, so\nthe certified pipeline's conclusions transfer to the abstract problems by\ncomposition.\n\n## What exactly is proven\n\nFor every reduction in the catalog:\n\n- a machine-checked equivalence `P x ↔ Q (map x)` for **every** instance `x` —\n  including degenerate ones (empty formulas, empty clauses, isolated vertices,\n  thresholds exceeding the vertex count). There are no well-formedness side\n  conditions and no \"WLOG\".\n\nFor every certified reduction — today, all of them — additionally:\n\n- the instance map is a program of the `Code` language, correct with respect\n  to total decoding of concrete instances, and therefore of polynomially\n  bounded cost and output size by the generic theorem.\n\nNot proven, by design:\n\n- anything about Turing machines, P, NP, or NP-completeness — there is no\n  formal statement \"SAT is NP-complete\" here, and no claim of membership in\n  NP for any problem;\n- the connection between the `Code` cost model and a machine model (the\n  deferred bridge above);\n- the adequacy of the cost model, which is a design judgment enforced by\n  discipline rather than by a theorem. The discipline is spelled out below,\n  so it can be audited. (The adequacy of the *encodings* is deliberately not\n  on this list: for every problem in the catalog it is the theorem pair of its\n  domain's `Representation.lean`.)\n\n## Size discipline\n\nThe certificates are only as honest as the size model, so the library follows\nstrict rules, chosen to make the eventual bridge theorem true rather than\nconvenient:\n\n- **Explicit element lists.** Graph instances carry an explicit vertex list\n  (isolated vertices are represented); SUBSET SUM instances carry a list of\n  numbers (duplicates are distinct items). Instance size is never measured by\n  a succinct proxy.\n- **Numbers cost their bit length**, and no `Code` combinator can iterate a\n  number of times given by a number's *value* — only list lengths drive\n  iteration. Exponentiation is the sharp case: `natPowLen` takes its exponent\n  from a list, never from a number, so a program wanting `b ^ j` must exhibit\n  a list of length `j`. Base-4 place values are therefore exponentially large\n  numbers of only linearly many bits.\n- **Fresh names are tagged tuples.** Gadget constructions never generate\n  fresh objects from a counter; a fresh vertex or variable is a tagged tuple\n  of input objects (an occurrence is \"clause × position within it\"), so\n  instance maps stay structural. A concrete instance has only `ℕ` labels, so\n  a certificate has to *realize* those tags as numbers; it does so with an\n  injective pairing (`Code.natPair`), and the reduction proof asks nothing of\n  the realization but injectivity (`CNF.satisfiable_relabel`).\n- **Junk-tolerant decoding.** Concrete instances decode *totally*: a graph's\n  vertices are the positions of its vertex list, its edges are the in-range\n  index pairs, everything else is ignored. Every value means something, so no\n  well-formedness predicates infect the statements.\n\nThe discipline has visible mathematical consequences. For instance, the\nDOMINATING SET reduction has threshold `k + (number of isolated vertices)`\nwhere the textbook says \"WLOG assume no isolated vertices\": the WLOG is a\npreprocessing pass that a formal reduction has to either implement or, as\nhere, absorb into the construction.\n\n## Restrictions: \"hard even if\"\n\nGarey and Johnson's \"remains NP-complete even if …\" is first-class and\npromise-free: `P.restrict R` conjoins the side condition into the predicate\n(`fun x ↦ R x ∧ P x`), so a reduction *into* a restriction is exactly a\nhardness-even-if proof, and no promise infects the instance types.\n`Reduction.codRestrict` builds such a reduction from one whose gadgets satisfy\n`R` by construction; weakening in the other direction (`Reduction.ofRestrict`)\nrequires the restriction to be decidable — the classical requirement that\npromises be checkable falls out of the formalization by itself. The\nbounded-occurrence 3SAT entry is the model instance of the pattern.\n\n## Building\n\nRequires the Lean toolchain pinned in [`lean-toolchain`](lean-toolchain)\n(elan installs it automatically) and mathlib's build cache:\n\n```\nlake exe cache get\nlake build\n```\n\nCI builds every push. API documentation is generated with doc-gen4 and\npublished at \u003Chttps://dominikpeters.github.io/HardnessReductionsLean/>.\n\nThree documents carry the working conventions:\n[`CLAUDE.md`](CLAUDE.md) for the architecture and file layout,\n[`STYLE.md`](STYLE.md) for how to state a reduction, build a gadget, write a\ncertificate annex, and get past the tactic failures that recur here, and\n[`ROADMAP.md`](ROADMAP.md) for what is next.\n\n## Roadmap\n\nThe library is a growing prototype; [`ROADMAP.md`](ROADMAP.md) keeps the\nprioritized queue. The standing themes:\n\n- **Aggregation in `Code`.** The language deliberately has no general fold —\n  an unrestricted fold would break the once-and-for-all polynomial theorem,\n  since accumulators can grow exponentially. Instead, bounded aggregates are\n  added one at a time, each paying for its own case of the polynomial theorem\n  (the admitted ones are `listSum` and the length-indexed exponentiation\n  `natPowLen`). An operation is eligible exactly when its output size is\n  bounded by the input's bit content, and it must carry its own case of the\n  blanket theorem.\n- **More catalog entries and restrictions.** Garey–Johnson's \"six basic\n  problems\" (3SAT, 3DM, VERTEX COVER, PARTITION, HAMILTONIAN CIRCUIT, CLIQUE)\n  are all present; the queue now favours entries that stress something new —\n  a new instance shape, domain folder, combinator, or proof pattern.\n- **The machine-model bridge**, once mathlib has a formalization of\n  polynomial-time computation to bridge to.\n",1794686174468]