challenges / spherical-codes-4d
Spherical codes in 4 dimensions, maximum minimum distance on S^3
# Spherical codes in 4 dimensions, maximum minimum distance on S^3
## Goal
`sphere.py` exposes `place(n: int, time_budget: float, seed: int) -> list[tuple[float, ...]]`:
`n` points, each a tuple of 4 coordinates, on the unit sphere S^3 in R^4. Maximise the smallest
pairwise Euclidean distance
D = min over i < j of |x_i - x_j|
Equivalently: find the best spherical code of size `n` in 4 dimensions, or pack `n` equal caps on
S^3. This is the 4-dimensional case of the Tammes problem (`tammes-problem` is the same
benchmark on S^2). Sloane's tables of putatively optimal packings cover n = 5, ..., 130 in
4 dimensions; the thirteen `n` here were chosen away from every proven case and from the regular
polytopes and their subsets, so every instance is open and a better configuration is a new record.
Proven optimality in R^4 covers n <= 8 (the simplex, then Rankin's bound: for d + 1 < n <= 2d the
cross-polytope's 90 degrees is optimal), n = 10 (Bachoc and Vallentin 2009, the Petersen code, via
semidefinite programming) and n = 120 (the 600-cell, Boroczky 1978; also universally optimal by Cohn
and Kumar). The 24-cell at n = 24 is only conjectured optimal (Cohn's 24-cell conjecture is open) and
n = 23 and n = 113..120 are subsets of the 24-cell and 600-cell, so they are excluded as well.
## Metric
metric = mean over n in NS of D(n) / record(n)
1.0 means matching every record; above 1.0 means beating at least one. The eval projects every
returned point onto the unit sphere (any finite non-zero vector with exactly 4 coordinates is
accepted; a zero vector, a non-finite coordinate, the wrong dimension or the wrong count is a
failed run; coincident points simply score 0 for that `n`) and recomputes the minimum distance
itself. Nothing your solver reports is used. `ZT_EVAL_SEED` only changes the `seed` handed to
`place`, so your method must be robust to its starting point.
## Records
Best-known configurations from N. J. A. Sloane, R. H. Hardin, W. D. Smith et al., "Tables of
Spherical Codes" (NeilSloane.com/packings/, files `dim4/pack.4.<n>.txt`, fetched 2026-09-07; every
entry credited on the site to Hardin, Sloane and Smith, 1994). The record distance below was
recomputed from those coordinates (the files are double precision, so the recomputed distance is
exact far beyond the 12 decimals kept); the angle is `2 asin(D / 2)` in degrees, quoted to the
tables' 1e-7 degree precision. Running the files themselves through `eval.py` scores exactly 1.0 on
every `n`. A distance above a record by more than 1e-8 is listed in `records_beaten`.
| n | record D | angle (deg) | source | proven optimal |
|---|---|---|---|---|
| 15 | 1.139304896784 | 69.4519870 | Hardin, Sloane, Smith 1994 | no |
| 18 | 1.074412011970 | 64.9872827 | Hardin, Sloane, Smith 1994 | no |
| 22 | 1.002113635232 | 60.1398863 | Hardin, Sloane, Smith 1994 | no |
| 26 | 0.958342717702 | 57.2625923 | Hardin, Sloane, Smith 1994 | no |
| 30 | 0.911885065192 | 54.2511897 | Hardin, Sloane, Smith 1994 | no |
| 35 | 0.870029899428 | 51.5724903 | Hardin, Sloane, Smith 1994 | no |
| 40 | 0.836064816081 | 49.4208547 | Hardin, Sloane, Smith 1994 | no |
| 48 | 0.787615150888 | 46.3832527 | Hardin, Sloane, Smith 1994 | no |
| 56 | 0.749397826979 | 44.0114102 | Hardin, Sloane, Smith 1994 | no |
| 64 | 0.721722892927 | 42.3062196 | Hardin, Sloane, Smith 1994 | no |
| 72 | 0.695669254241 | 40.7098566 | Hardin, Sloane, Smith 1994 | no |
| 84 | 0.659737516843 | 38.5216197 | Hardin, Sloane, Smith 1994 | no |
| 100 | 0.627382237223 | 36.5636318 | Hardin, Sloane, Smith 1994 | no |
## Constraints
- Standard library only. No numpy, no scipy. The eval rejects other imports.
- Respect `time_budget` (seconds, per call). The eval fails a call that runs past 1.25x + 3 s.
- Deterministic given `seed`: use `random.Random(seed)`.
## Iterating
- `ZT_EVAL_NS=15,26` runs a subset of n; `ZT_EVAL_PER_N_SECONDS=2` shortens the per-n budget. The
default is all thirteen n at 8 s each (about 110 s). Run `python eval.py` in your workspace.
- The per-n detail in the eval output shows which n are furthest from their record.
## Ideas that are known to matter (check the journal before repeating one)
- The objective is a max-min, so plain gradient methods stall. Standard tricks: minimise a soft
energy sum d^-p with p ramped up (the baseline), or iterate "find the active contact pairs, then
solve the LP that pushes them apart" (an SLP), which converges to the true local optimum.
- In 4 dimensions there is no Fibonacci-style spiral start: use many random starts, or seed from
structured sets (subsets and unions of orbits of the cross-polytope, the 24-cell, or a
product of lower-dimensional codes) and let the optimiser break the symmetry.
- Basin hopping: perturb the current best a little, re-optimise, accept if the minimum distance
did not drop. Many restarts beat one long run; the record configurations often have rigid
contact graphs that a single descent rarely finds.
- The pure-Python pair loop is the bottleneck: only the near-contact pairs matter once the
configuration is decent, so keep a neighbour list and refresh it occasionally.
Write one honest line in `NOTES.md`: the idea, and which `n` it helped.
Simpler is better: all else equal prefer the shorter solver, and treat removing code for an
equal score as a win. Log every experiment, including discards, in your results.tsv.