Circle packing in a square

How large can \(n\) equal circles be when they must fit into a unit square without overlapping? The question is old and hard. The best packings are proven optimal for every \(n\) up to 33, and beyond that the best known ones are collected, as on Eckard Specht’s Packomania. For two circles, the answer lies on the diagonal, \(r = 1/(2 + \sqrt{2})\), four sit in a grid of \(r = 1/4\), and five put the fifth in the middle, \(r = (\sqrt{2} - 1)/2\).

Here, SciPy searches for the packings, and planex2d checks them with exact discs: the discs must lie inside the square, and their union must have the area of \(n\) separate discs, so none of them overlaps another. Their radii are compared with the proven ones.

The best packings of 5 to 10 equal circles in a square

[1]:
import math

import numpy as np
import planex as px
from scipy.optimize import minimize

The checks

For each \(n\), the discs are drawn exactly, a hair smaller than the radius found so that circles that touch stay apart. Nothing of them may lie outside the square, and their union must have the area \(n\pi r^2\). The radii agree with the proven optimal ones, as Packomania lists them, to the twelve digits printed:

[4]:
proven = {2: 0.292893218813, 3: 0.254333095030, 4: 0.25, 5: 0.207106781187, 6: 0.187680601147,
          7: 0.174457630187, 8: 0.170540688701, 9: 0.166666666667, 10: 0.148204322565}
square = px.QuickSketch().Rectangle(1, 1).Face()
packings = {}
for n, best in proven.items():
    r, centers = spread(n)
    discs = px.Unify([px.Circle(tuple(c), r * (1 - 1e-12)).Face() for c in centers])
    packings[n] = discs
    print("n", n, "| radius", round(r, 12), "| proven", best, "| outside", (discs - square).mass,
          "| union against n π r²", discs.mass / (n * math.pi * (r * (1 - 1e-12)) ** 2) - 1)
n 2 | radius 0.292893218813 | proven 0.292893218813 | outside 0.0 | union against n π r² 2.220446049250313e-16
n 3 | radius 0.25433309503 | proven 0.25433309503 | outside 0.0 | union against n π r² -2.220446049250313e-16
n 4 | radius 0.25 | proven 0.25 | outside 0.0 | union against n π r² 0.0
n 5 | radius 0.207106781187 | proven 0.207106781187 | outside 0.0 | union against n π r² 0.0
n 6 | radius 0.187680601147 | proven 0.187680601147 | outside 0.0 | union against n π r² -3.3306690738754696e-16
n 7 | radius 0.174457630187 | proven 0.174457630187 | outside 0.0 | union against n π r² 0.0
n 8 | radius 0.170540688701 | proven 0.170540688701 | outside 0.0 | union against n π r² 0.0
n 9 | radius 0.166666666667 | proven 0.166666666667 | outside 0.0 | union against n π r² 4.440892098500626e-16
n 10 | radius 0.148204322565 | proven 0.148204322565 | outside 0.0 | union against n π r² -4.440892098500626e-16
5 circles
(a) 5 circles
7 circles
(b) 7 circles
10 circles
(c) 10 circles
Figure 1: The best packings of 5, 7 and 10 circles