Square Packing Atlas
Discrete geometry · Lean 4 proofs

Squares in Rectangles

Which rectangles hold three, four or five unit squares, if the squares may be turned to any angle? The boundaries have been on record since 2010, as constructions in a problem posed by Erich Friedman. Here they are proved: the constructions cannot be beaten. All three theorems are checked in Lean 4 with no hypotheses.

Lean 4, no hypothesis, standard axioms boundaries: Friedman's Math Magic, June 2010 not peer reviewed Lean sources on GitHub →
01 · The question and the answer

Which rectangles hold n unit squares?

Call the rectangle's sides s ≤ ℓ (short and long). The squares are closed unit squares at any positions and angles, inside the rectangle, with disjoint interiors. Every square needs s ≥ 1, and two squares need ℓ ≥ 2, since otherwise every unit square in the box contains the box's centre in its interior. For three squares or more, tilting starts to pay.

Theorem (rect3_iff, rect4_iff, rect5_iff). With 1 ≤ s ≤ ℓ:

  • Three unit squares fit iff s ≥ 2, or ℓ ≥ 3, or ℓ + 2s ≥ 4 + 2√2.
  • Four fit iff s ≥ 2, or ℓ ≥ 4, or ℓ ≥ L(t, s) for some angle 0° < t < 90°, where
    L(t, s) = 2 + (1 − 2(s − k − 1) sin t)/cos t
             + (1 − (s − 2k) cos t)/sin t,
    k = (cos t + sin t)/2.
  • Five fit iff ℓ ≥ 5; or s ≥ 2 and (ℓ ≥ 3 or s + ℓ ≥ 4 + √2); or s < 2 and ℓ + 4s ≥ 4 + 6√2.

At s = ℓ the five-square case is s(5) = 2 + 1/√2 (Göbel 1979). The tilted pieces live in thin slivers: 1.9142 ≤ s < 2 for three squares ((1 + 2√2)/2 ≤ s), 1.8816489 ≤ s < 2 for four, 1.8713 ≤ s < 2 ((6√2 − 1)/4 ≤ s) and 1 + √2 ≤ s ≤ 2 + 1/√2 for five.

In the plot, a point is a rectangle: short side across, long side up. The shaded region is the set of rectangles that hold n squares; its lower edge is the boundary, with the tilted pieces in gold. Click or drag along the boundary, or use the slider, to see the packing that sits exactly on it. Every packing is drawn from the construction proved in Lean.

boundary, upright packingboundary, tilted packingfitsleft open by Yang (2026)

Each boundary point is attained: the packings drawn are in the closed rectangle, touching where they look as if they touch. Inside the shaded region more room is to spare; below the boundary, the theorem says no packing exists at all, at any angles. The vertical pieces at s = 2 are where the short side reaches 2 and the squares can be stacked two high.

02 · Who found what

The boundaries are Friedman's; the proofs are new

All three boundaries, and every packing on them, are in Erich Friedman's Math Magic problem of the month for June 2010. Friedman asks for the region Sn of rectangles that hold at most n unit squares, so the boundary of Sn−1 is the boundary we want for n; his x is our long side ℓ and his y our short side s. The page names that month's solvers as Maurizio Morandi, Evert Stenlund, David W. Cantrell and Hiroaki Hosono, and gives an author for some of the pieces in its table:

n hereFriedmanpieces of the boundaryauthor column
3S₂x = 3; x + 2y = 4 + 2√2 (the 45° wedge); y = 2empty for all three
4S₃x = 4; a parametric curve (the tilted pair); y = 2MM for the curve, empty for the other two
5S₄x = 5; x + 4y = 4 + 6√2 (the zigzag); y = 2; x = 3; x + y = 4 + √2MM for all five

The table gives authors by initials only. MM matches Maurizio Morandi, the only named solver with those initials. The page was last updated in February 2019 and gives constructions, not proofs.

Other earlier work bears on these three cases:

Our part. We came to the three-square case by a numerical search, found the 45° wedge, and took it for new; a day later we learned it was in Friedman's table (posted in 2010, last updated in 2019). We then used his tables as the target for four and five. What is new here is the other direction: the proof that nothing below the boundary can be packed. As far as we know these are the first proofs of these lower bounds, for n = 3, 4 and 5, and the first theorems about squares in non-square rectangles in any proof assistant.

03 · Strips lower than 2

The chain: three and four squares

When the short side is 2 or more, all three answers are easy for n = 3 and 4: two rows fit. The work is in strips [0, L] × [0, H] with H < 2. There the squares cannot be stacked: each centre lies between heights ½ and H − ½, so any two centres differ in height by less than H − 1 < 1. That makes the squares a chain, left to right.

  1. Sort and separate. Sort the squares by the x-coordinate of their centres. Two squares with disjoint interiors are separated by a line (in Lean: Hahn–Banach, from Mathlib). Because neighbours are less than one unit apart in height, the line between them always has the left square on its left.
  2. The shelf. Take the first square a and its line. Replace a by an upright unit square pushed against the left wall, level with the top or the bottom of a. The upright square is still on a's side of the line. (This is one elementary trigonometric inequality, upright_repl.) So the second square b, on the other side, cannot reach left of x = 1 anywhere within that unit band of heights. That is a shelf. The last square gives a shelf at x = L − 1 on the other side.
a b c 0 1 L − 1 L
Three squares in a strip of height 1.8. The red dashed lines separate neighbours. The dashed outlines are the upright stand-ins for a and c; they lie on the same side of the lines as the squares they replace, so in the stand-ins' bands of heights, b stays between the green shelves at x = 1 and x = L − 1. (The shelves constrain only b; a and c themselves may cross them.)

Three squares. Now b sits alone between two shelves, and the whole question is how short L can be. Which point of b a shelf stops is one of three: the corner of b that points at the shelf, if it is at a height inside the band, or else the point of an adjacent edge at the band's top or bottom. That gives 3 × 3 cases, each a real inequality in b's angle. Seven give L ≥ 3 outright. The two where b stands on the floor or hangs from the ceiling with an edge on each shelf give L + 2H ≥ 4 + 2√2, with equality only at 45°: Friedman's wedge.

b a c L = 4 + 2√2 − 2H
The equality case for three squares: the shelves are the two upright squares themselves, and b at 45° touches the ceiling and the two inner corners.

The step that makes this short is the shelf: once the neighbours may be taken upright, a single square against two shelves carries the whole boundary. The Lean proof of rect3_iff is 171 lines, on top of 418 lines of chain tools reused below.

Four squares. Sort a, b, c, d. Square b has a shelf on its left (from a), c a shelf on its right (from d), and a line at some angle t separates b from c. Two more steps:

a b c d L = L(t, H)
Friedman's four-square packing at H = 1.93, t ≈ 40.5°. The middle pair lie edge to edge, and their common edge is the separating line. A half turn about the red centre maps the packing to itself, which is why the two one-square bounds are tight together. The angle of Friedman's tilted squares is the angle of that separating line.

So the minimum of L(t, H) over t is exactly the boundary, and rect4_friedman shows that the packing exists for every t with L(t, H) < 4. The tilted piece runs from H = 1.8816489, where it meets the row of four, up to H = 2, where t = 45° and L = 4√2 − 2 ≈ 3.657. Lean: 592 lines.

04 · Both sides at least 2

Weighted points: five squares and s(5)

With both sides at least 2 the chain breaks: squares can stack. For five squares this part of the boundary contains the square 2 + 1/√2, and we use the method that proves s(5): unavoidable points, here with weights.

The principle. Put points with weights in the a × b box so that every closed unit square inside the box contains points of total weight at least 1. Five closed unit squares that do not even touch contain disjoint sets of points, so if the total weight is less than 5, they cannot all be in the box.

Packed squares may touch, and a point on a shared edge would be counted twice. But the covers have to count points on a square's edge: at the boundary they are tight. Scaling resolves both. A packing in a box below the boundary is ruled out by scaling it up: enlarge the box onto the boundary line a + b = 4 + √2 by a factor λ > 1, together with the squares. The enlarged squares have disjoint interiors, so the unit squares at their centres are disjoint even as closed sets, and each contains weight at least 1. Boxes with a ≤ 1 + √2 and b < 3 are first widened to a = 1 + √2, which handles the flat piece ℓ = 3.

Four points (for 4 − √2 ≤ a ≤ 2 + 1/√2 on the line). The points (1, 1), (a − 1, 1), (1, b − 1), (a − 1, b − 1), weight 1 each. Split the possible centres into nine cells: near a corner the corner point is caught; along a wall, one of the two points on that wall (the side-strip lemma of Friedman's survey, which needs the gap between them at most 2√2 − 2); in the middle, a new lemma: a unit square whose centre lies in an X × Y rectangle with X, Y ≤ 1 and X + Y ≤ √2 contains one of the rectangle's corners. At a = b this gives s(5) = 2 + 1/√2, by essentially the classical argument with the centre handled by the rectangle lemma.

Cover C (for 1 + √2 ≤ a ≤ 4 − √2). Here the side-strip lemma fails: a square at 45° sitting against a long wall slips between the two points on it, and a numerical search found no set of four points that works. A linear program over fractional weights found covers, and one simplifies to ten points:

Total 14/3 < 5. Every closed unit square in the box contains a whole block of weight exactly 1: a row pair {(0.91, 1), (1, 1)}, a wall pair {(0.91, 1 or b − 1), (1, b/2)}, or a centre triple {(1, 1 or b − 1), (1, b/2), (a − 1, b/2)}, up to mirror images. The Lean proof splits the centres into three cells, each closed by short lemmas of the same kinds as above (corner, side strip, and a variant of the centre lemma).

weight caught
—
no room at this anglebelow 1exactly 14/35/3 or more

Drag the square, turn it with the slider (or the mouse wheel), and try to catch less than weight 1. The small map shows the weight caught for every centre at the current angle; gold is exactly 1, where the cover is tight. The box follows the boundary line a + b = 4 + √2 (for cover C and the four points) or the strip 5 × H (§05). The page samples; the Lean proof covers every position and angle.

05 · Five squares in a strip

Midline points, then certificates

Low strips, H < 2√2 − 1 ≈ 1.828. Four points on the midline, (1, H/2), …, (4, H/2), in the 5 × H box: every unit square in it contains one (select "low strip" above). Between two midline points this is the side-strip lemma again, with gap 1 at height H/2, and its condition 1/2 + H/2 ≤ √2 is exactly H ≤ 2√2 − 1. So in low strips five squares need length 5. Lean: 98 lines.

High strips, 2√2 − 1 ≤ H < 2. This contains the zigzag, Friedman's piece ℓ + 4s = 4 + 6√2 for s ≥ (6√2 − 1)/4 ≈ 1.8713.

a b c d e L = 4 + 6√2 − 4H
The zigzag at H = 1.95: two uprights, three squares at 45°, edge to edge. Unlike the four-square packing, the two separating lines are different lines.

The chain applies as before: shelves on b and d, lines between b and c and between c and d. A concavity argument (in Lean) shows that the middle square is narrowest between the two lines when it is upright or parallel to one of them. What is left is one real inequality in the two lines' angles and the height. But the two halves now see different lines, coupled through the middle square, and the natural ways to decouple them lose (numerically, by 0.1 or more); one split that loses nothing has not been turned into a proof yet. We proved the remaining inequality by machine:

That is 14,411 lines of generated Lean, about 5 minutes to build on 16 cores (70 CPU-minutes). It was not a surprise to need certificates at n = 5, though we had hoped to put them off to larger n. A structured proof of this step is open.

06 · Check it

Building the proofs

git clone https://github.com/evand/square-packing && cd square-packing/lean
lake exe cache get              # Mathlib
lake build Sqpack.Rect3         # rect3_iff     ~15 s
lake build Sqpack.Rect4         # rect4_iff     ~15 s
lake build Sqpack.Rect5Thm      # rect5_iff     ~5 min on 16 cores, mostly the generated files
lake build && lake env lean Axioms.lean

Axioms.lean prints the axioms of every theorem in the library (it imports all of it; the rectangle theorems are near the end) and must show only propext, Classical.choice and Quot.sound: no sorry, no native_decide. To check only these three, put import Sqpack.Rect5Thm and #print axioms SquarePacking.rect5_iff (and the same for rect3_iff, rect4_iff) in a file and run lake env lean on it. The build times are wall times on a 16-core machine; the generated files build one at a time, each Lean process using about 5 cores. A full lake build also builds unrelated parts of the library, one of which needs about 23 GB of memory.

The statements use one definition, RectPacks n w h: n closed unit squares, at any centres and angles, each inside [0, w] × [0, h], with pairwise disjoint interiors.

file (lean/Sqpack/)what
Rect.leanRectPacks; two squares (rect2_iff); the wedge
RectChain.leanthe chain: separation, upright replacement, shelves, witnesses
Rect3.leanrect3_iff
Rect4.lean, Rect4Core.leanone-square lemma, half turn, Friedman's packing; rect4_iff
Rect5Pack.leanthe five-square constructions: row, grid, zigzag, stretched s(5)
Rect5Pts.lean, Rect5Line.leanthe four points and cover C; both sides ≥ 2
Rect5Low.leanmidline points, low strips
Rect5.lean, Rect5Mid.lean, Rect5Final.lean, Rect5Hi*.leanhigh strips: the chain for five squares and the generated certificates
Rect5Iff.lean, Rect5Thm.leanFits5; rect5_iff

Research notes: search/rectfront/RECTFRONT.md (the log), LESSONS.md (techniques, what failed), r5pts/R5PTS.md (point covers, with paper proofs), r5strip/FINAL5.md (the certificates).

07 · Caveats

What to keep in mind