computo ergo sum日本語
The whole guide

Start here

  1. What Lean is
  2. Getting started
  3. Handing a finite check to decide
  4. Counting with Finset
  5. An upper bound from a single injection
  6. Series and inequalities
  7. Having Lean check a certificate
  8. It passed — but does it say what you meant?
  9. How to read a statement
  10. When Lean is too heavy
  11. Common pitfalls
  12. Glossary
  13. How Lean works

When Lean is too heavy — size, wording and stock

A proof that is written on paper sometimes does not go into Lean. There are three reasons: it is finite but too large; there is no settled way to state it; the underlying mathematics is not in mathlib. Which of the three you are facing decides what to do about it.

On this page
  1. The difficulty has three sources
  2. Finite but too large
  3. There is no form for stating "the enumeration is exhaustive"
  4. Mathematics that mathlib has no stock of
  5. How to tell the three apart

01

The difficulty has three sources

A proof that is written on paper sometimes does not go into Lean. The reasons split into three, and which one you are facing decides what to do.

SIZEFinite but too large  the way to write it is settled, but the cost of checking exceeds what is practical
FORMNo way to state it  the form for turning what you want to say into a Lean statement is not settled
STOCKNot in mathlib  the underlying mathematics has not been formalised yet

The problem of size can be measured. The problem of form is a problem of design. The problem of stock is a decision between building it yourself and leaving it on paper. None of the three is "it cannot be done"; all three are "it cannot be done at the cost that can be paid now", and the order of magnitude of the cost differs.


02

Finite but too large

A demonstration — the cost of decide is set by the search space

decide enumerates every finite case. The cost is the number of cases itself. Measure it on a small example. Take the graph on the vertices Fin k in which the first 4 points are pairwise adjacent (if 4 points are pairwise adjacent, 3 colours will not do), and have it confirmed that there is no 3-colouring at all by decide. There are 3^k colourings.

def Adj (k : ℕ) (i j : Fin k) : Bool := i.val < 4 && j.val < 4 && i.val ≠ j.val

def Proper (k : ℕ) (f : Fin k → Fin 3) : Bool :=
  decide (∀ i j : Fin k, Adj k i j = true → f i ≠ f j)

set_option maxRecDepth 100000 in
theorem noCol6 : ∀ f : Fin 6 → Fin 3, Proper 6 f = false := by decide

The checking time was measured for different k. A file with nothing but import Mathlib takes 5.01 seconds, so the difference from that is the cost of decide.

What was checkedSearch spaceCheckDifference
import Mathlib only (baseline)—5.01 s—
Exhausting Fin 4 → Fin 3815.41 s0.4 s
Exhausting Fin 6 → Fin 37299.19 s4.2 s
Exhausting Fin 8 → Fin 36,561stops (hits the heartbeat limit of 200000 and quits after 64 s)
Fin 6 → Fin 3 (with maxRecDepth left at its default)729stops (maximum recursion depth has been reached)

Three things can be read off.

When you hit a wall of this shape, the thing to do is not to raise the limit and wait, but to measure the cost per case and work out the order of magnitude of the whole.

A real instance — 1.48 million decisions come to 100–1000 CPU-hours

In the upper-bound argument for unit-distance graphs, the candidate graphs are dropped by passing them through a sieve in stages. The first stage of the sieve is a decision that looks only at the edge set and drops a candidate for "too many vertices" or "degree too large"; 86% of the candidates fall here. What happens if this decision is run inside Lean was measured.

What was measuredMeasured
Baseline (import Mathlib only)5.373 s
The decision 20 times7.092 s
Per candidate, from the difference86 ms
Number of candidates1,482,463
This stage aloneabout 35 hours

The next stage is heavier still, and the whole comes to the order of 10²–10³ CPU-hours. The number of certificates (771) is a scale already within reach; what governs the order of magnitude is the number of times the decision is run.

One point of design comes out of this estimate. The reason a decide is fired per candidate is that the number of candidates is fixed outside Lean. Bring the list of candidates into Lean as a term, and decide is run once. But holding the list as a term makes the term of order 10⁶ in size, and the cost may merely move from "the number of runs" to "the size of the term". Which is cheaper is a question that can be measured.

Existence is cheap, non-existence is expensive

There is one asymmetry of cost, and among problems of size it is the one that matters most.

Existence: hand over one witness and check it    Non-existence: exhaust everything

In the same setting as the demonstration above, measure the side that can be coloured. If only the first 3 points are pairwise adjacent, the graph can be 3-coloured. Write down one colouring and hand it over.

theorem col20 : ∃ f : Fin 20 → Fin 3, Proper3 20 f = true :=
  ⟨fun i => ⟨i.val % 3, Nat.mod_lt _ (by norm_num)⟩, by decide⟩

Even with 20 points, 5.21 seconds — 0.2 seconds above the baseline. The search space is 3^20 = 34 hundred million colourings, but hand over a witness and no enumeration happens. It is cheaper than non-existence on 6 points (729 cases).

StatementSearch spaceCheck
20 points can be 3-coloured (existence, with a witness)320 ≈ 3.4 billion5.21 s
6 points cannot be 3-coloured (non-existence, exhaustive)7299.19 s

So when designing a stage of the sieve, look first at which direction that stage is used in. A sieve is a tool for dropping candidates, so every stage is used in the direction of non-existence. "Drop it because it cannot be 3-coloured", written as it stands, is an exhaustive search.

In the real instance, among the stages of the sieve above, the one mark that rests on colouring is the one that cannot be run in Lean. With 15 points and 3 colours it is an exhaustive search over 3^15 = 1,434 ten-thousands of colourings, and it fails on the recursion-depth limit (measured). The statement itself is elementary, and on the lattice it closes in ten lines. The heaviness comes not from the difficulty of the statement but from the direction it is used in.

Take this stage out of the sieve and the whole still closes, but 4.8 times as many candidates flow downstream. Keep, as a variable in the estimate, how many times the downstream count multiplies when one stage is dropped.


03

There is no form for stating "the enumeration is exhaustive"

An argument that lines up candidates and knocks them down one by one has two parts.

StatementIts form in Lean
(i)None of the candidates lined up satisfies the conditionExists. Hand over a certificate per candidate and decide (07)
(ii)The candidates lined up are all of them (completeness of the enumeration)Not settled

What makes (ii) hard is not a problem of size. The form for setting up the statement is not settled. To write it, at the least the following are needed.

The third is the substance. The outside search prunes branches for speed, and the reason for pruning exists only inside the code of the search. Moving that into Lean is the same work as rewriting the search in Lean. The division of labour in 07 Having Lean check certificates (search outside, confirm in Lean) does not work here. There is nothing that plays the part of a certificate.

What is in Lean is only the length of the list.

theorem cands_card : cands.length = 117 := by decide

This is "the list has 117 entries", not "the candidates are exactly 117". The difference between the two is Type 2 of 08 Does it say what you meant?.

So the grades are written separately. (i) is Lean, (ii) is computation. The upper-bound claim rests on both (i) and (ii), so the grade of the claim as a whole is computation. Only (i) carries a theorem name, so unless a table is made, this one step gets dropped.


04

Mathematics that mathlib has no stock of

The third source is that the underlying mathematics has not been formalised yet. In this case the cost is the cost of "building it yourself".

Whether the stock exists can be found with grep. These are the results of searching the mathlib source.

Word searchedFiles hitMeaning
Bakry0No Bakry–Émery theory
Ricci0No curvature from Riemannian geometry
logSobolev, log_sobolev0No logarithmic Sobolev inequality
bessel4The name appears, but there are no inequalities for modified Bessel functions
toSphere1The measure on the sphere is there (MeasureTheory/Constructions/HaarToSphere.lean)

This table decides what is left on paper. Where the stock is partly there, as in the fourth and fifth rows, connecting to the part that exists is sometimes the cheaper course. The measure on the sphere was there, so a single theorem was put in showing that the measure defined by its properties agrees with mathlib's definition, and the connection was made (08 §04 (c)).

The criteria for deciding to leave it on paper

When the following three all hold, the decision is to leave it on paper.

Criteria

  1. The mathematics is a textbook theorem. It is not the new part of your own argument but a part brought in from outside
  2. It is not in mathlib. Confirm with grep. Even if a similar name comes up, if the statement in the form you need is not there, it is "not there"
  3. Building it yourself would be larger than the main body. Building Riemannian geometry from scratch is a job many times larger than the original argument

Conversely, if any of the following applies, it is not left on paper. It is the new part of your own argument (not something brought in) / it connects if a part of the stock is used / it is a problem of size, not of form.

How to write down that it was left on paper

The part left on paper is placed as a row in the table of results. Three things are written.

What to writeExample
What is on paper (the statement in one line)That the second derivative along a geodesic equals the Riemannian Hessian; Ric = 2 on the sphere
Why it is on paperStandard facts, but mathlib has almost no stock of Riemannian geometry
Where the seam isFrom hess_gauge on the Lean side (the lower bound on the second derivative) to the lower bound on curvature on the paper side

The third is what does the work. Write where the seam is, and the reader can inspect just that spot. Write only "part of it is on paper", and there is no telling where to look.

And if the paper row comes right before the conclusion, the grade of the conclusion is paper. However many Lean rows are lined up, that does not change. The procedure for the receiving end to confirm this is ⑦ of 09 How to read a statement.


05

How to tell the three apart

SourceHow to tellWhat to do
SizeThe way to write it is settled, and running it hits a limitMeasure the cost per case and work out the order of magnitude of the whole. See whether it can be rewritten in the direction of existence. If a stage is dropped, count how many times the downstream multiplies
FormWhen you try to write the statement, what should be a type is not settledList the parts that are needed. See whether there is anything that plays the part of a certificate. If not, split the grades and say so
Stockgrep finds nothingDecide by the three criteria whether to leave it on paper. If it is left, write where the seam is

In all three, the conclusion is not "it does not go into Lean" but "this part is of a different grade". Write the grades separately and the result is usable. Write them without separating, and the Lean rows read as if they guaranteed the paper rows.


Next: 11 Common pitfalls — the messages you see when you hit the limits above, and how to read them. Terms are in the 12 Glossary.

Revised 2026-09-20: first version.