← All experiments

Field notes / Experiment guide

Does the edge-entry law survive a different lattice?

The square-lattice opening-run law leaves its constants unexplained. Do changing loop length and neighbour count distinguish what sets them?

New to these ants? Start here.

An ant moves on a grid of coloured squares. Each colour tells it to turn left (L) or right (R). It advances that square to the next colour, then steps forward. A rule such as RLR is the list of turns, starting at colour zero. On a blank grid the same rule always makes the same trajectory.

Territory means every cell visited so far. Its boundary consists of visited cells with an unvisited neighbour. A highway is a repeating pattern of motion that carries the ant away. A tether means repeated returns to a small home region.

Growing like the cube root of time means taking eight times as many steps to double a linear size. The rotor walker is a comparison model that follows and rotates arrows stored on cells. A seed makes a random starting pattern reproducible; the ant itself can still move deterministically.

We distinguish c, the chance of discovering a cell per boundary step, from kappa (κ), time at the boundary normalized by perimeter divided by area. Explaining their values is harder than using them to account for growth.

The idea under test

Registered hexagonal and triangular-cell comparisons test loop-length scaling and occupation against a lattice-specific uniform reference.

What we learned

Registered plan only; no lattice measurements have been run at registration.

What this leaves open

The predictions are prospective. Growth, support and calibration gates must pass before interpreting the proposed comparisons.

Read the evidence and reproduction recipe ↗

Inside the experiment

Methods, registered predictions, exact commands and saved analysis. These are the working research documents; expand them for the detail behind the introduction.

Methods and original experiment record

Does the c law (and kappa's deficit) survive a change of lattice? Hexagonal and triangular ants

Registered 2026-10-20 00:25 (+13:00), base commit 0de4d38. Nothing in this folder has been run; no lattice c, kappa or lead slope has been computed on hex or triangular ants before this file was committed. (Disclosure: the old experiments/2026-10-13-ext-other-lattices-turmites-noise screens measured area and extent exponents only, never c or kappa.)

Question

experiments/2026-10-19-c-law-mechanism found that c (births per boundary step) obeys 1/c = a + b * lead on the square lattice (a ~ 1.36-1.40, b ~ 0.68-0.70), that 78% of circulating boundary reads return after exactly 4 steps (2x2 loops), and that the constants a, b are not derived. The kappa deficit (ants at 0.81x the uniform reference) is also unexplained. The square lattice has one loop length (4) and one coordination number (4), so it cannot say which lattice property sets b. Hexagonal (z = 6) and triangular-cell (z = 3) ants change both, and hex offers two loop lengths on one lattice.

Definitions (frozen)

  • Generic probe: src/probe.rs's octave windows (2^(k-1), 2^k], with the neighbour set per lattice: square 4, hex 6 (HEX_DIRS axial offsets), triangular 3 (tri_step, parity dependent). boundary step = step starting on a visited cell with

    = 1 unvisited neighbour; birth = step onto a never-visited cell; c = births / boundary steps; P = visited cells with = 1 unvisited neighbour; kappa = (B/S) / (P_end/A_end).

  • Lead = length of the opening run of identical letters. On hex the alphabet is {r, l, R, L} (60/60/120/120 degrees, hex_turns); a run of r (or l) closes a loop of 6 cells around a centre cell, a run of R (or L) closes a loop of 3 cells around a vertex (checked in gate G3 by stepping, not assumed). Triangular L/R is +-2 edges: loop of 6 around a vertex. Square: loop of 4. Mirror-canonical: s_0 = R (square, tri), s_0 in {r, R} (hex). Hex strata are r-lead and R-lead.
  • kappa_unif(a, beta) = 2 * integral_{1/2}^{1} x^(-a(1-beta)) dx (experiments/2026-10-16-kappa-uniform-baseline), with a and beta fitted per run over k = 20..26 exactly as experiments/_lib/analyse_probe.py. It is an analytic formula in the run's own (a, beta), so it ports to any lattice; what is untested is that its premise (P/A tracks the window) holds there: gate G4. kappa ratio = kappa(k=26) / kappa_unif.
  • Window and board: census convention, kappa and c from the last window k = 26 (2^26 steps), board 8192 x 8192, blank background.
  • Filter (stationary blob, frozen): not escaped (never within 2 cells of the board edge), births > 0 in every window k = 20..26, c > 0, |g_k| < 0.05 (slope of kappa on t over k = 20..26, as c_law.py), and width exponent alpha_w in [0.28, 0.40] as a proxy for cls == blob (the census cls is not reproduced by committed analysis code; this proxy is new and is a documented deviation from the census definition).
  • Retention (kept / run) is reported per lattice, stratum and lead. Cells with < 8 kept rules are reported as underpowered and are not topped up silently (a top-up is a logged deviation).

Rule lists (frozen, scripts/make_lists.py, seed 20261020)

Primitive rules, length uniform in 10..14, first letter canonical, opening run exactly m (letter m differs from s_0, uniform among the other letters on hex), remaining letters uniform. 48 candidates per (lattice, stratum, lead m = 1..5): square 240, triangular 240, hex 480 (240 r-lead + 240 R-lead). Every rule runs once (blank background is deterministic, so there is no seed). Controls: random walk, 32 seeds per lattice (uniform neighbour step, seeds 1..32); mean-field walker (resample uniformly over visited cells, then uniform neighbour), 8 seeds per lattice. Both use the generic probe windows.

Gates (instrument; fail = no claim on that lattice)

  • G1 the generic probe reproduces src/probe.rs windows exactly (all fields) on the square lattice, >= 20 rules.
  • G2 hex and triangular generic probes equal a naive HashMap re-implementation (all window fields) on >= 20 rules each, plus HexSim/TriSim area sequences, and a one-line mutation is caught.
  • G3 single-letter loop periods by stepping: square R 4; hex r 6, R 3; triangular R 6. A different value revises Definitions before any data is aggregated (logged deviation, not a failure of the science).
  • G4 mean-field walker, each lattice: kappa ratio within 0.05 of 1.00 (square was 1.118 against 1.107 measured). If it fails on a lattice, kappa is reported raw there and no ratio claim is made.
  • G5 square ants from this pipeline: median 1/c lead slope in [0.55, 0.85] and intercept in [1.20, 1.60] (census 0.70/1.36).

Derivation of what the loop length can and cannot do

Little's law (confirmed to 1.6% on the square lattice): 1/c = mean boundary reads per born cell. Take lead m. A cell on the circulating loop has been read once per lap, its colour advances by one per read, so the loop is "spent" after m reads of every loop cell: reads per episode = m * l_b where l_b is the number of loop cells that are boundary cells. Hence b = d(1/c)/dm = l_b / N_b, N_b = births per episode. The loop length l itself cancels per cell. What the derivation does not fix is how N_b scales with l: if births per episode are set by a chain after the kill (about fixed), b ~ l_b ~ l; if a larger loop wraps proportionally more fresh ground, N_b ~ l_b and b is lattice-independent. So the mechanism allows both limits and the data must choose. A third, weaker idea ties b to coordination through the fresh fraction of a loop's neighbours. The square b = 0.70 is the anchor for all three.

Predictions

Fitted 1/c = a + b * lead, leads 1..5, OLS over kept rules; b per stratum with a 2000-draw rule bootstrap, seed 20261020.

Signature vector of b = (triangular, hex R-lead, hex r-lead):

  • H-A (b scales with loop length): b = 0.70 * l/4 -> (1.05, 0.52, 1.05). Within hex, b_r / b_R = 2.
  • H-B (b lattice-independent): (0.70, 0.70, 0.70). b_r / b_R = 1.
  • H-C (b ~ 4/z): (0.93, 0.47, 0.47). b_r / b_R = 1.

Decision rule: a hypothesis is supported if all three measured strata are within 0.15 of its vector and every other hypothesis misses at least one stratum by > 0.20; otherwise undecided (reported with the measured vector, no hypothesis forced). My odds: H-A 25%, H-B 40%, H-C 10%, none/undecided 25%. Independently of the vector:

  • L1 within hex, the b_r / b_R bootstrap CI excludes 1 (H-A's signature alone): 30%.
  • L2 the intercept a is positive and within 0.5 of 1.36 on every lattice: 50% (no mechanism predicts it).

Kappa:

  • K1 kappa ratio median < 1 on hex and triangular (as on square, 0.81): 55%. Each median in [0.65, 0.97]: 40%.
  • K2 random-walk kappa ratio >= 1.10 on each lattice (square rw 1.24-1.32): 70%. A ratio < 1 for the memoryless control means the formula or probe fails on that lattice and K1 is void for it.
  • K3 |slope of ln kappa on lead| < 0.08 per step in every stratum (square marginal -0.022): 60%.
  • K4 rw c on each lattice is below the ant median c (square rw 0.448, ants higher): 60%.

Order of work and commands (filled in as built)

This file and NOTEBOOK.md are committed first. Then src/lattice_probe.rs and tests/lattice_probe.rs (G1-G3; these use hex and triangular rules but aggregate no c; any peek at c before the instrument is final is disclosed in the notebook), then scripts/make_lists.py, the run, and scripts/analyse.py writing to results/.

Results (run 2026-10-20; commit adf6677 for the instrument and lists, results committed after)

Command: bash experiments/2026-10-20-lattice-c-law/scripts/run.sh (fresh target dir, binary sha256 d135514050596c44078a9635582a4837faea55858d8004c4be0ab612e0f8a74e in results/run.log; 120 controls 106 s, 960 ants 488 s wall on 6 threads), then uv run .../scripts/analyse.py -> results/analysis.{txt,json}; post hoc uv run .../scripts/explore.py -> results/explore.txt. Raw windows: results/{ants,controls}.csv. Deviations: runs go to 2^27 steps (windows k = 12..26, the census octave), the lattice probe does not produce the gyration/ant-spread fields (G1 compares the seven it does), the random walk uses windows k = 16..22 because it leaves the 8192 board before 2^27 (so the rw rows use a different window from the ants).

Gates. G1-G3 pass (cargo test --release --test lattice_probe; a deliberate mutation was caught). G4 passes: mean-field kappa ratio 0.994 (sd 0.021, square), 1.005 (0.013, triangular), 1.004 (0.014, hex), 8 seeds each, so the analytic kappa_unif(a, beta) is a valid reference on all three lattices. G5 passes: square b = 0.696 [0.666, 0.724], a = 1.286 [1.188, 1.386] (census 0.70, 1.36).

Retention (kept / 48 per lead): square 31 18 29 27 28; triangular 36 47 47 47 46; hex r-lead 38 41 47 47 47; hex R-lead 33 28 37 42 34. No cell is underpowered, but square lead 2 (kept 18, alive 36) and hex R lead 2 (28) lose more than half, so survivor selection is not negligible there.

Registered fits of 1/c = a + b * lead (rule bootstrap, 95%):

stratum n a b R^2
square 133 1.29 [1.19, 1.39] 0.696 [0.666, 0.724] 0.954
triangular 223 1.28 [1.22, 1.33] 0.355 [0.340, 0.371] 0.936
hex R-lead 174 2.80 [2.49, 3.09] 0.876 [0.782, 0.983] 0.689
hex r-lead 220 -1.18 [-9.5, 2.5] 1.98 [0.23, 5.82] 0.011

The hex r-lead OLS is destroyed by a single rule that passed the frozen filters with 1/c = 390 (lead 5); it is reported as it came out.

Hypotheses. Measured vector (triangular, hex R, hex r) = (0.355, 0.876, 1.980) versus H-A (1.05, 0.52, 1.05), H-B (0.70, 0.70, 0.70), H-C (0.93, 0.47, 0.47). The frozen decision rule returns undecided (no vector within 0.15). L1 as registered: FAILED (b_r/b_R = 2.26 [0.25, 6.76], dominated by the outlier). Without relying on the outlier-corrupted fit, the triangular stratum alone refutes all three: its bootstrap CI [0.340, 0.371] is at least 0.33, 0.56 and 0.68 below B, C and A, and the hex R stratum (0.876, CI [0.78, 0.98]) is 0.18, 0.41 and 0.36 above B, C and A. So H-A, H-B and H-C are all disproven as stated (each predicted a triangular slope of 0.70 or more; observed 0.355, and b falls as the loop gets longer).

Post hoc, unregistered (results/explore.txt): slopes of per-lead medians of 1/c, which are insensitive to the outlier: square 0.68 (OLS on medians 0.70), triangular 0.335, hex R-lead 0.86, hex r-lead 0.27-0.28 (per-lead medians 2.63, 2.77, 3.04, 3.39, 3.72). Against loop length l = 3, 4, 6, 6 (hex R, square, triangular, hex r) b = 0.86, 0.70, 0.34, 0.28. Within hex, b_r / b_R ~ 0.32, the opposite direction to H-A's 2. A straight line b ~ 1.5 - 0.2 l fits the four points, but that is two parameters for four points, chosen after seeing them, and is a description, not a model. The intercept is 1.3 on square and triangular but ~2.4-2.8 on hex (hex r from the lead-1 median 2.63 minus b).

Kappa. Ratio kappa/kappa_unif(a, beta), own (a, beta) per run, last window k = 26, kept ants: square median 0.770 (IQR 0.62-0.90, census 0.81), triangular 0.744 (0.66-0.82), hex 0.860 (0.75-1.01). K1 held on both new lattices (medians < 1 and inside [0.65, 0.97]). Random walks (k = 16..22): 1.33 (square), 1.44 (triangular), 1.28 (hex) (K2 held). K3 held (|slope of ln kappa on lead| 0.007, 0.079, 0.059, 0.075; the triangular one only just). K4 FAILED as registered: random-walk c (0.44 / 0.46 / 0.42) is above the ant median c (0.29 / 0.41 / 0.27) on every lattice. The pooled median is a design artefact (leads 1-5 sampled uniformly, so it sits near lead 3). By lead-1 medians (results/explore.txt, 1/c = 2.09, 1.60, 2.63, 3.59) ant c is 0.48 (square) and 0.63 (triangular), above the random walk, but 0.38 (hex r-lead) and 0.28 (hex R-lead), below it: whether ants out-enter fresh ground than a random walk depends on lead and lattice. (An earlier version of this paragraph blamed my memory of the square comparison; see the NOTEBOOK correction.) L2 FAILED (hex intercept 2.8).

Reading. The kappa deficit (ants at 0.74-0.86 of uniform) is not a square-lattice artefact: it appears on all three lattices with a validated reference. The c law form (1/c linear in lead, R^2 0.94-0.95 on square and triangular, 0.69 on hex R-lead) survives, but its slope and intercept are lattice- and loop-dependent, falling with loop length rather than rising. The 2x2-loop picture of the square slope therefore carries no information about the number 0.70 by itself; whatever sets b depends on the loop it circulates. Not tested: why hex fits are worse (four-letter alphabet, letters after the lead are not separated into types), any mechanism for b(l), more loop lengths, mixed-letter leads.

Outlier and provenance notes. The hex r-lead outlier is ant:rrrrrLrrrLrrLL (lead 5, 1/c = 390): its perimeter equals its area at every window (perimeter exponent 1.0, a lacy territory) while its area and width exponents look blob-like, so the alpha_w proxy and |g_k| < 0.05 both let it through; the proxy leaks on hex (results/outlier.txt). The next largest hex 1/c (12.9, 9.7, 8.8) are genuine blobs with beta 0.59-0.62. run.log says "dirty: 88 files"; those are stat and line-ending noise (git diff --ignore-cr-at-eol --stat adf6677 -- src examples: 0 insertions, 0 deletions, appended to run.log). The refutation of A, B and C rests on the triangular stratum alone, where none of the listed confounds can rescue any of them: retention 0.75-0.98 (highest of the three lattices), R^2 0.94, and the OLS slope 0.355 matches the per-lead-median slope 0.335.

Follow-up A: letter-typed hex lead with a beta filter (registered 2026-10-20 00:50 (+13:00), base commit 7df6d35)

Re-analysis of the existing results/ants.csv (no new runs). Nothing below has been computed; the only things seen so far are the pooled fits above, the outlier's beta = 1.0, and the beta of the next three largest 1/c (0.59-0.62). It addresses ACTIVE's "do the hex letter types after the lead matter?".

Definitions (frozen). Hex rules only. Filter F2 = the registered filter plus per-run perimeter exponent beta < 0.8 (beta as in analyse.py, k = 20..26). f_big = fraction of letters in {R, L} among the letters after the lead. Hex strata as before (r-lead, R-lead). Fit M0: 1/c = a + b*lead; M1: 1/c = a + b*lead + d*f_big. Bootstrap as before (rule resampling, 2000 draws, seed 20261020). Compare M1 to M0 by 5-fold CV R^2 (folds by rule index mod 5).

Predictions.

  • T1 F2 removes only the outlier-type rules: <= 5 rules per stratum drop from the kept sets (80% confident), and the r-lead fit becomes usable: R^2 >= 0.5 and b in [0.15, 0.45] (the per-lead-median slope was 0.28). 55%.
  • T2 the R-lead b is unchanged by F2: within 0.1 of 0.876. 75%.
  • T3 letter type matters: M1 beats M0 in CV R^2 by >= 0.05 in the R-lead stratum, and d has a bootstrap CI excluding 0 in at least one stratum. 40%.
  • T4 the hex intercept is partly composition: in M1 evaluated at f_big = 0 the intercept a falls below 2.0 in the r-lead stratum. 25%.
  • T5 the b_r / b_R ratio (F2 fits) has a bootstrap CI below 1 (the opposite of H-A, as in the medians, ~0.3). 60%.

Null/negative outcomes are reported as such. Script scripts/hex_letters.py -> results/hex_letters.txt.

Follow-up A results (run 2026-10-20, scripts/hex_letters.py -> results/hex_letters.txt, ants.csv unchanged)

F2 dropped exactly one rule (rrrrrLrrrLrrLL, r-lead; none in R-lead). Fits (rule bootstrap 95%): r-lead M0 a = 2.41 [2.23, 2.60], b = 0.262 [0.210, 0.310], R^2 0.42 (n = 219); R-lead M0 a = 2.80, b = 0.876 [0.788, 0.987], R^2 0.69 (n = 174). R-lead M1 adds d = 0.99 [0.37, 1.66] on f_big; r-lead d = 0.08 [-0.27, 0.41].

  • T1 PARTLY FAILED: the one-rule drop and b in [0.15, 0.45] held (b = 0.262), but R^2 = 0.42 < 0.5. The clean r-lead slope matches the per-lead-median slope 0.28.
  • T2 held (R-lead b unchanged, 0.876). T5 held: b_r / b_R = 0.30 [0.24, 0.37], the opposite of H-A's 2 and now with a bootstrap CI free of the outlier.
  • T3 FAILED as registered (both conjuncts were required): the R-lead CV gain is only +0.014 although d's CI excludes 0 there; so tail letter type is real but tiny in R-lead (+0.1 in 1/c per 0.1 of f_big) and absent in r-lead. T4 FAILED: r-lead intercept at f_big = 0 stays 2.37; R-lead falls to 2.33 (not registered).
  • Reading: the hex slope/intercept difference from square and triangular is not a mixed-letter artefact or an outlier artefact. The hex lead fits remain noisy (R^2 0.42 and 0.69 against 0.94-0.95), with most of the scatter unexplained by lead, composition or letter type. Not tested: other tail features (second run length, letters 6-8 as in the square law).

Follow-up B: a new loop length on the Moore lattice (registered 2026-10-20 01:30 (+13:00), base commit after lattice_probe: add Moore)

Nothing has been run on Moore ants. Instrument: Lattice::Moore in src/lattice_probe.rs (8 neighbours, headings N,NE,E,SE,S,SW,W,NW; r/l turn 45 degrees, R/L 90 degrees); G2 (naive HashMap oracle, ant and random movers) and G3 (loops: r, l -> 8, R, L -> 4) pass in tests/lattice_probe.rs, and a mutation of the l turn was caught. Rule lists: scripts/make_lists_moore.py (seed 20261021): 48 per lead 1..5 in two strata, r-lead (loop 8) and R-lead (loop 4, but z = 8 not 4); 480 ants; controls rw 32 and mf 8. Run and filters exactly as the main experiment (2^27 steps, board 8192, windows 12..26, F2 = registered filter plus beta < 0.8, fit 1/c = a + b*lead, 2000-draw rule bootstrap seed 20261020).

Models for b(loop length l) fixed from the four existing strata (l, b) = (3, 0.86), (4, 0.70), (6, 0.34), (6, 0.28) (the hex values use the F2 fits where relevant):

  • M-lin b = 1.5 - 0.2 l (the post hoc line): l = 4 -> 0.70, l = 8 -> -0.10 (so b ~ 0).
  • M-inv b = 2.47 / l (least squares through the origin on b vs 1/l): l = 4 -> 0.62, l = 8 -> 0.31.
  • M-z b depends on coordination as well as l, which neither M-lin nor M-inv covers; it is the residual hypothesis if both miss.

Predictions (odds in brackets).

  • B1 Moore R-lead (l = 4, z = 8): b within 0.15 of the square value 0.70, i.e. [0.55, 0.85] (loop length, not z, sets b): 40%.
  • B2 Moore r-lead (l = 8): M-lin is supported if b < 0.12 and the bootstrap CI excludes 0.31; M-inv is supported if b in [0.20, 0.42]; otherwise neither. Odds: M-lin 15%, M-inv 35%, neither 50%.
  • B3 within Moore, b(r-lead) < b(R-lead), bootstrap CI of the ratio b_r/b_R below 1: 80%.
  • B4 both Moore fits have R^2 >= 0.5 and retention >= 8 kept rules per (stratum, lead): 55%.
  • B5 the Moore intercepts a lie within 0.5 of 1.3 (the square/triangular value): 30% (hex was 2.4-2.8, which scales with nothing I have).
  • B6 random-walk kappa ratio >= 1.10 and mean-field ratio within 0.05 of 1 (gate G4) on Moore: 85%. If G4 fails, no kappa claim there.

Decision: M-lin and M-inv are scored on B2 only; a supported model must also not miss B1 by more than 0.15 of its own l = 4 prediction (0.70 / 0.62). Results will be appended below, not edited above. Script scripts/analyse_moore.py -> results/analysis_moore.txt.

Follow-up B results (run 2026-10-20; scripts/run_moore.sh, commit 02f5d13, binary sha256 ae948ed0...8049d6a in results/run_moore.log; scripts/analyse_moore.py -> results/analysis_moore.txt)

Controls 103 s, 480 ants 303 s. Retention high (kept 39-48 of 48 in every cell). Fits (rule bootstrap 95%): r-lead (loop 8) a = 2.39, b = 0.260 [0.235, 0.284], R^2 0.69 (n = 234); R-lead (loop 4, z = 8) a = 2.41, b = 0.775 [0.711, 0.857], R^2 0.74 (n = 207); b_r/b_R = 0.335 [0.291, 0.380].

  • B1 held (0.775 in [0.55, 0.85]; the 0.075 excess over the square 0.70 is outside the Moore CI, so z has a small effect or none beyond it). B3 held. B4 held. B6 held (mean-field 0.999, random walk 1.19).
  • B2: M-lin not supported (b = 0.26, not ~0): the linear description is refuted at l = 8. M-inv's number was met (b in [0.20, 0.42]) but it fails its own consistency clause (R-lead deviation from its l = 4 prediction 0.62 is 0.155 > 0.15), so by the frozen rule neither model is supported. Marginal and I do not round it up.
  • B5 FAILED: Moore intercepts 2.39 and 2.41, like hex (2.4-2.8) and unlike square/triangular (1.3). Intercepts: z = 3: 1.3, z = 4: 1.3, z = 6: 2.4-2.8, z = 8: 2.4 (post hoc; not monotone in z, and equal for both Moore loops).
  • Post hoc, unregistered: within a lattice, doubling the loop length from 3 to 6 (hex) and 4 to 8 (Moore) multiplies b by 0.30 and 0.335, i.e. b ~ l^-1.6 locally, steeper than both 1/l and the cross-lattice triangular/square ratio (0.49). A model must say why the within-lattice drop is steeper than the across-lattice one. Ant kappa ratio median 0.96 on Moore (higher than 0.74-0.86 elsewhere), so the kappa deficit weakens with z; also post hoc.
  • Conclusion: the registered test of the b(l) models on a new loop length falls to "neither", but constrains the answer: b(8) = 0.26 is far from zero, b is flat at ~0.26-0.28 for l = 6 and 8 in different lattices, and the intercept looks set by the lattice (hex-like on Moore), not the loop. No mechanism yet.
Analysis notebook: notebook.ipynb

5 saved outputs · 4 code cells. Cells are not executed during publication. Download notebook

Does the c law survive a change of lattice? Hexagonal and triangular ants

Question

On the square lattice 1/c = 1.36 + 0.70 lead (c = births per boundary step, lead = opening same-letter run). Is the slope a property of the 2x2 loop, of the lattice coordination, or of neither? Three hypotheses were registered before any lattice c existed (README): A b scales with loop length, B b is lattice-independent, C b follows 4/z. Secondary: is the kappa deficit (ants at ~0.8 of the uniform reference) square-specific?

Assumptions and definitions

Generic octave-window probe on square / hex / triangular lattices (src/lattice_probe.rs); boundary step, birth, perimeter as src/probe.rs; kappa ratio = kappa / kappa_unif(a, beta) with the run's own a, beta (k = 20..26). Instrument gates G1-G3 (cargo test --release --test lattice_probe) passed; G4 (mean-field walker) and G5 (square c law) are checked below.

Code
In [1]:
import hashlib, json, subprocess
from pathlib import Path
ROOT = next(p for p in [Path.cwd(), *Path.cwd().parents] if (p / "AGENTS.md").exists())
R = ROOT / "experiments/2026-10-20-lattice-c-law/results"
for n in ["ants.csv", "controls.csv", "analysis.json", "analysis.txt", "explore.txt", "run.log"]:
    print(hashlib.sha256((R / n).read_bytes()).hexdigest()[:16], n)
print("git", subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=ROOT, capture_output=True, text=True).stdout.strip() or "unresolvable here; see README (instrument adf6677)")
A = json.loads((R / "analysis.json").read_text())
27a19e9fed4225ef ants.csv
4e3d71e477998e66 controls.csv
c9c5c924e719b9f5 analysis.json
337a65fa781e2513 analysis.txt
1eb3e0cf6002d873 explore.txt
ac17e37c160bc507 run.log
git 7339dc9

Results

Gates and the c law per stratum (registered fit)

Code
In [2]:
k = A["kappa"]
print("G4 mean-field kappa ratio:", {l: round(k[l]["mf"]["ratio_mean"], 3) for l in k})
for key, f in A["fits"].items():
    print(f"{key:9s} n={f['n']:3d}  1/c = {f['a']:6.2f} + {f['b']:5.2f} lead   b 95% CI [{f['b_ci'][0]:.2f}, {f['b_ci'][1]:.2f}]  R2 {f['r2']:.2f}")
print("retention (kept per lead 1..5):", {key: v["kept"] for key, v in A["retention"].items()})
print("decision rule verdict:", A["verdict"])
G4 mean-field kappa ratio: {'square': 0.994, 'tri': 1.005, 'hex': 1.004}
square/R  n=133  1/c =   1.29 +  0.70 lead   b 95% CI [0.67, 0.72]  R2 0.95
tri/R     n=223  1/c =   1.28 +  0.36 lead   b 95% CI [0.34, 0.37]  R2 0.94
hex/r     n=220  1/c =  -1.18 +  1.98 lead   b 95% CI [0.23, 5.82]  R2 0.01
hex/R     n=174  1/c =   2.80 +  0.88 lead   b 95% CI [0.78, 0.98]  R2 0.69
retention (kept per lead 1..5): {'square/R': [31, 18, 29, 27, 28], 'tri/R': [36, 47, 47, 47, 46], 'hex/r': [38, 41, 47, 47, 47], 'hex/R': [33, 28, 37, 42, 34]}
decision rule verdict: undecided

Square reproduces the census (G5 passes). Triangular b is half the square's, with a tight interval. The hex r-lead fit is corrupted by one rule with 1/c = 390 that passed the frozen filters; the registered decision rule returns undecided. It does not show a mechanism for b. The next cell is post hoc and unregistered.

Code
In [3]:
print((R / "explore.txt").read_text())
Reading inline script metadata from `experiments/2026-10-20-lattice-c-law/scripts/explore.py`
== square/R
 lead 1: n=31 median 1/c 2.09  q10/q90 1.51/2.24  max 2.4
 lead 2: n=18 median 1/c 2.62  q10/q90 2.45/2.90  max 2.9
 lead 3: n=29 median 1/c 3.36  q10/q90 3.04/3.61  max 3.8
 lead 4: n=27 median 1/c 4.10  q10/q90 3.89/4.29  max 4.4
 lead 5: n=28 median 1/c 4.82  q10/q90 4.40/4.97  max 5.2
 slope of per-lead medians (lead 1->5)/4: 0.682  OLS on medians: 0.695
== tri/R
 lead 1: n=36 median 1/c 1.60  q10/q90 1.34/1.82  max 2.0
 lead 2: n=47 median 1/c 1.97  q10/q90 1.92/2.04  max 2.1
 lead 3: n=47 median 1/c 2.38  q10/q90 2.32/2.49  max 2.5
 lead 4: n=47 median 1/c 2.65  q10/q90 2.58/2.83  max 3.0
 lead 5: n=46 median 1/c 2.94  q10/q90 2.88/3.27  max 3.3
 slope of per-lead medians (lead 1->5)/4: 0.335  OLS on medians: 0.335
== hex/r
 lead 1: n=38 median 1/c 2.63  q10/q90 2.25/3.72  max 4.7
 lead 2: n=41 median 1/c 2.77  q10/q90 2.40/3.33  max 3.9
 lead 3: n=47 median 1/c 3.04  q10/q90 2.74/3.27  max 4.0
 lead 4: n=47 median 1/c 3.39  q10/q90 3.12/3.81  max 4.7
 lead 5: n=47 median 1/c 3.72  q10/q90 3.52/4.36  max 390.2
 slope of per-lead medians (lead 1->5)/4: 0.272  OLS on medians: 0.28
== hex/R
 lead 1: n=33 median 1/c 3.59  q10/q90 3.18/4.58  max 5.6
 lead 2: n=28 median 1/c 4.25  q10/q90 3.76/5.34  max 7.7
 lead 3: n=37 median 1/c 5.41  q10/q90 4.80/6.19  max 7.3
 lead 4: n=42 median 1/c 6.09  q10/q90 5.54/6.98  max 7.4
 lead 5: n=34 median 1/c 7.04  q10/q90 6.29/8.42  max 12.9
 slope of per-lead medians (lead 1->5)/4: 0.862  OLS on medians: 0.875

Per-lead medians give b of about 0.86 (hex R, loop 3), 0.70 (square, loop 4), 0.34 (triangular, loop 6) and 0.27 (hex r, loop 6): b falls as the loop gets longer, opposite to H-A. All three registered hypotheses are disproven as stated: triangular alone is at least 0.33 away from each vector. A line b ~ 1.5 - 0.2 l fits but has two parameters for four points chosen after the fact.

Kappa

Code
In [4]:
for l, v in k.items():
    print(f"{l:6s} ants median ratio {v['ants_median']:.3f} (n={v['ants_n']}, IQR {v['ants_q'][1]:.2f}-{v['ants_q'][2]:.2f})   random walk {v['rw']['ratio_mean']:.2f}   mean-field {v['mf']['ratio_mean']:.3f}")
print("K3 slopes of ln kappa on lead:", {a: round(b, 3) for a, b in A["k3"].items()})
square ants median ratio 0.770 (n=133, IQR 0.62-0.90)   random walk 1.33   mean-field 0.994
tri    ants median ratio 0.744 (n=223, IQR 0.66-0.82)   random walk 1.44   mean-field 1.005
hex    ants median ratio 0.860 (n=394, IQR 0.75-1.01)   random walk 1.28   mean-field 1.004
K3 slopes of ln kappa on lead: {'square/R': -0.007, 'tri/R': -0.079, 'hex/r': -0.059, 'hex/R': -0.075}

The deficit is not square-specific: all three lattices have ant medians of 0.74-0.86 with a mean-field reference at 1.00 and memoryless walkers at 1.3-1.4 (random-walk window k = 16..22). It does not explain the deficit.

Caveats

  • Single deterministic run per rule; survivor selection (e.g. square lead 2 keeps 18 of 36 alive); alpha_w is a proxy for the census blob class.
  • Hex has four letters; letters after the lead are not separated by type. Triangular loops enclose a vertex, so "loop length" may not be the variable that matters.
  • Failed registered predictions: L1 (outlier), L2, K4. Deviations: 2^27 steps, no gyration fields, random walk window.

Next

Register b(l) and a letter-typed hex lead before using a new loop length; derive why b falls with l; check whether the intercept (1.3 square/triangular, ~2.5 hex) tracks coordination.

Read the dated lab log

Lab notebook: lattice c law (hex and triangular ants)

Append-only. Newest entry last. Never edit an old entry; correct it with a new one (corrects: <timestamp>). Tags: intent, assumption, observation, interpretation, surprise, decision, dead-end, question, deviation. See experiments/README.md.

2026-10-20 00:25 (+13:00) · 0de4d38 · intent

Start lattice-c-law: test whether the square-lattice c law (1/c = 1.36 + 0.70 lead) and the kappa deficit hold on hex and triangular ants. Registered the three loop-length hypotheses (A: b ~ loop length, B: lattice-independent, C: ~ 4/z) with numeric signature vectors before any lattice c exists. Decision it informs: whether the 2x2-loop picture of c is specific to square geometry.

2026-10-20 00:25 (+13:00) · 0de4d38 · assumption

kappa_unif(a, beta) ports to hex and triangular because it is analytic in the run's own (a, beta); its premise (a uniform walker has P/A tracking the window) is untested there. Falsified by gate G4 (mean-field walker ratio within 0.05 of 1). Status: untested.

2026-10-20 00:25 (+13:00) · 0de4d38 · question

My derivation says loop length cancels per loop cell (b = l_b / N_b) and the data must decide how N_b scales with the loop; I do not know which limit is right, so the H-A vs H-B odds (25/40) are a guess. The census cls == blob is not reproducible from committed code, so I use an alpha_w proxy (deviation from the census definition, stated in the README).

2026-10-20 01:10 (+13:00) · adf6677 · observation

Gates G1-G3 pass (cargo test --release --test lattice_probe, 7 tests): square windows equal probe.rs on the fields the lattice probe produces; hex/triangular/square ants and both random movers equal a HashMap re-implementation; ant areas equal HexSim/TriSim at every octave; one-letter loop cells are square 4, hex r 6, hex R 3, triangular 6 (the periods predicted from geometry). A deliberate mutation (fresh_nbrs += unv + (t & 1)) failed 5 of 7 tests, then reverted. No c was aggregated on any lattice yet. A timing pilot ran 3 rules not in the frozen lists (output discarded).

2026-10-20 01:10 (+13:00) · adf6677 · deviation

(1) The README said "all fields" for G1 and "2^26 steps": the lattice probe omits the radius-of-gyration and ant-spread fields (not needed here), so G1 compares the seven fields it produces; and the census kappa window k = 26 is the octave (2^26, 2^27], so runs go to 2^27 steps (windows k = 12..26), as the census. Neither changes any prediction. (2) The kappa-ratio and width-exponent analyses use the window set k = 20..26 as analyse_probe.py.

2026-10-20 01:45 (+13:00) · adf6677 · observation

Ran controls (106 s) and 960 ants (488 s). Gates G4 (mean-field ratio 0.994 / 1.005 / 1.004) and G5 (square b 0.696, a 1.286) pass. Registered fits: b = 0.696 square, 0.355 triangular [0.340, 0.371], 0.876 hex R-lead; hex r-lead OLS is garbage (b 1.98, R^2 0.01) because one rule has 1/c = 390. Decision rule: undecided. L1, L2, K4 failed; K1, K2, K3 held. Files: results/analysis.txt.

2026-10-20 01:50 (+13:00) · adf6677 · surprise

b falls with loop length; none of A, B, C (all predicted b flat or rising with loop length / coordination) is close. Triangular is half the square. Per-lead medians (post hoc, results/explore.txt) give hex r-lead b ~ 0.27, so the within-hex ratio is ~0.32, not 2.

2026-10-20 01:55 (+13:00) · adf6677 · interpretation

All three registered hypotheses are disproven as stated (triangular alone excludes each by >0.3). I do not have a replacement: b(l) = 0.86, 0.70, 0.34, 0.28 for l = 3, 4, 6, 6 is a post hoc description on four points. Alternatives not excluded: the hex fits mix letter types after the lead; the "loop around a vertex" lengths I used may not be the loops that matter on triangles (they enclose a vertex, not a cell); survivor selection (retention 0.4-0.98 by cell). Confidence in "b depends on lattice": high (CI-level). In "b falls with l": moderate (4 strata, 3 distinct l).

2026-10-20 01:55 (+13:00) · adf6677 · decision

Not extending the registered analysis (no outlier trimming added after the fact). Next experiment, if any, must register a b(l) prediction before using a new loop length or a letter-type-separated hex lead.

2026-10-20 03:10 (+13:00) · 3117e1b · interpretation

corrects: 01:45 observation and the README K4 sentence. K4 still failed as registered, but the explanation "I misremembered the square comparison" was wrong: the pooled ant median c reflects my uniform sampling of leads 1-5. Lead-1 medians of 1/c (explore.txt) give ant c = 0.48 square, 0.63 triangular (above rw 0.44, 0.46) and 0.38 hex r-lead, 0.28 hex R-lead (below rw 0.42).

2026-10-20 03:10 (+13:00) · 3117e1b · observation

The hex r-lead outlier is rrrrrLrrrLrrLL (lead 5): 1/c = 390, c = 0.0026 at k = 26, but perimeter = area at every window (perimeter exponent beta = 1.0: every visited cell has an unvisited neighbour, a lacy territory) while the area exponent (0.65) and width exponent (0.34) look blob-like, so the alpha_w proxy and |g_k| < 0.05 (g_k = 0.0 because P/A = 1) both let it through. The proxy therefore leaks on hex; a beta filter (e.g. beta < 0.8) would have excluded it. The next three largest 1/c on hex (12.9, 9.7, 8.8) have beta 0.59-0.62 and are genuine. results/outlier.txt, scripts/outlier.py. Not re-filtering the registered analysis.

2026-10-20 03:10 (+13:00) · 3117e1b · observation

Provenance: the 88 "dirty" files in run.log are stat/line-ending noise: git diff --ignore-cr-at-eol --stat adf6677 -- src examples reports 0 insertions and 0 deletions. The triangular stratum carries the refutation alone and none of the listed confounds can rescue A, B or C there: retention 0.75-0.98 (the highest of the three lattices), R^2 0.94, OLS slope 0.355 agrees with the per-lead-median slope 0.335.

2026-10-20 03:25 (+13:00) · 3117e1b · observation

Full cargo test --release (WSL, after adding src/lattice_probe.rs): every test binary reports ok, no failures. Registered result and post hoc reading are kept separate in README, notes and blog; the outlier was not trimmed from the registered fit.

2026-10-20 00:50 (+13:00) · 7df6d35 · intent

Registered follow-up A in README (letter-typed hex lead, beta < 0.8 filter, T1-T5) before running anything on it. Also added ipykernel/nbformat/nbclient to pyproject.toml (user chose uv add). The b(l) model on a new loop length is not started: it needs a lattice with a new loop length and a registered model; see next entry.

2026-10-20 01:05 (+13:00) · 78122d9 · observation

Follow-up A ran as registered (results/hex_letters.txt). T2 and T5 held; T1 partly failed (r-lead R^2 0.42, b 0.262 clean); T3 and T4 failed. The r-lead slope was never an outlier-driven artefact: b_r/b_R = 0.30 [0.24, 0.37].

2026-10-20 01:05 (+13:00) · 78122d9 · interpretation

Letter type after the lead has a small detectable effect in R-lead only (d ~ 1.0, CV gain 0.014); it does not explain the hex intercept or the poor fit. The open items "hex intercept" and "hex letter types" shrink to: why the hex scatter is large and why a ~ 2.4-2.8. The b(l) model on a new loop length is not attempted this session: it needs a new lattice with a new loop length (implementation plus oracle tests per AGENTS rule 4) and a model registered first; no model with a mechanism exists yet beyond the post hoc line.

2026-10-20 01:30 (+13:00) · plan

user selected the b(l) item. Added the Moore lattice (new loop length 8, plus a loop-4 control at z = 8) to lattice_probe with oracle tests; registered M-lin / M-inv and B1-B6 in README before any Moore ant was run. Reason for Moore: hex offers only loops 3 and 6, triangular 6; any new loop length needs a new lattice.

2026-10-20 02:05 (+13:00) · 02f5d13 · observation

Follow-up B ran as registered (results/analysis_moore.txt). B1, B3, B4, B6 held; B5 failed; B2 gave M-lin refuted, M-inv number met but its own consistency clause missed by 0.005, so by the frozen rule neither is supported. b = 0.260 (l=8), 0.775 (l=4, z=8); intercept 2.4 on both.

2026-10-20 02:05 (+13:00) · 02f5d13 · interpretation

b looks like ~0.26-0.28 for l = 6 and 8, so a floor-like or slowly falling dependence, not linear to zero. Intercept tracks the lattice (z >= 6 gives 2.4+), not the loop. Both remain without mechanism; the b(l) item is narrowed, not closed.

2026-10-20-lattice-c-law · Source revision ba38590b33e3

Original source ↗ · Input hashes

Introductions summarize the evidence; the expandable record preserves the original predictions, methods and caveats. Figures and notebooks are published as saved. Publication runs no simulations or notebook cells.