Books · The Fiddler: Solutions
Chapter 75
Can You Squeeze the Particles Into the Box?
Three particles sit inside a unit square. Every pair repels, with energy for a pair a distance apart, and the total energy of the system is the sum over all three pairs. The particles may be anywhere in the square or on its boundary. What is the least total energy, and which arrangement achieves it?
The Fiddler, Zach Wissner-Gross, December 6, 2024(original post)
Solution
Since a pair’s energy falls as they separate, low total energy means large separations. Three corners of the square form a right isosceles triangle: two pairs are a unit side apart and the third pair sits at opposite corners, a distance , giving Nothing does better. Spreading the three apart any other way shortens at least one gap faster than it lengthens the others; the largest equilateral triangle fitting the square, for instance, has side and energy , distinctly worse than the corners.
The computation
Minimise the actual energy: from many random starts, let an optimiser slide the three points anywhere in the square and keep the best total. It settles on , the corners.
import numpy as np
from scipy.optimize import minimize
from itertools import combinations
def energy(x):
p = x.reshape(-1, 2)
return sum(1.0 / np.hypot(*(p[i] - p[j])) for i, j in combinations(range(len(p)), 2))
best = min(minimize(energy, np.random.default_rng(s).random(6),
method='L-BFGS-B', bounds=[(0, 1)] * 6).fun for s in range(200))
print(best, 2 + 1 / np.sqrt(2)) # 2.70711 2.70711
Extra Credit
Now there are nine particles, and the total is the sum over all pairs. What is the least energy, and the arrangement?
Solution
The repulsion is the two-dimensional analogue of Coulomb’s law, and as with charges on a conductor the particles all flee to the boundary: the minimum keeps none in the interior. A numerical search settles on energy with all nine on the perimeter, the four corners plus five more along the edges (symmetric about one midline rather than fully four-fold). The tidy grid one might guess is worse, at , precisely because it wastes a particle in the middle.
The computation
The same energy, now over nine points with many restarts; compare the optimum against the grid.
def search(n, restarts, seed):
rng = np.random.default_rng(seed); best = 1e18; bx = None
for _ in range(restarts):
r = minimize(energy, rng.random(2 * n), method='L-BFGS-B',
bounds=[(0, 1)] * (2 * n), options={'maxiter': 2000})
if r.fun < best: best, bx = r.fun, r.x
return best, bx.reshape(-1, 2)
grid = np.array([[i / 2, j / 2] for i in range(3) for j in range(3)], float)
e9, _ = search(9, 1500, 123)
print(round(e9, 3), round(energy(grid.ravel()), 3)) # 49.759 49.883