run 023Settled
../lab/runs/023-ks-attractor-dimension-sweep.mdPrediction|lam2| converges at L=22 and L=28, and stops converging by L=34 as the attractor outgrows a 2D section
Falsifierclean convergence at every L (branch 1 strengthens), or breakdown already at L=28 (the L=22 result was the special case)
L=28 terms of the prediction and falsifier withdrawn (L=28 is a travelling-wave window, no resonance to converge or break down).
the L=34 term scored as a miss: L=34 converges at 3 and 5 modes; outcome unanticipated by codifier ruling (see verdict).
an unrecorded instrument choice identified: the PCA section's orientation is arbitrary (numpy's SVD sign is unpinned, and the crossing test is directional), so each L received one of its two legitimate sections at random, and the choice moves |lam2| by more than the 0.01 tolerance L=34's PASS was declared at. At the arguments this run used, the svd_flip convention holds at L=22, 28 and 34 and is VIOLATED at L=26 and L=30 — so the two non-converging L sit on the opposite section from the three converging ones, which is exactly the partition this verdict turns on. The 3-vs-5-mode agreement is NOT affected (both slice Vt[0] from one SVD), and L=30's collapse diagnosis is about trajectories, not orientation. The systematic's SIZE is not determined: two reproductions differ by 3-4x and it moves with v0, so it is somewhere in 0.01-0.05 and needs an error bar of its own. No filed number is shown to be wrong; the comparison across L is shown to carry an uncontrolled per-L perturbation larger than the effects compared. See notes/pca-section-orientation.md (N-029), including its same-day correction withdrawing the first magnitude. The prediction and falsifier above stay as sealed.
VerdictUNANTICIPATED — the prediction missed: "stops converging by L=34", but L=34 converges and is partition-independent at 3 and 5 modes (|lam2| ~ 0.155). The falsifier did not fire: "clean convergence at every L" fails because L=26 never converges at any reachable resolution (its breakdown-at-L=28 clause is withdrawn). The observed behaviour is non-monotonic in L (26 and 30 fail, 34 passes), which neither clause anticipated, so the outcome is unanticipated rather than falsified (run 024 was falsified because its falsifier fired). Branch 3 as stated is not supported. L=30 is a chaotic transient collapsing onto a stable state. L=26 non-convergence is a resolution limit of the 4-D partition (~10 bins/axis at 10,000 cells), not evidence the resonance is absent.
Confidence0.55
The branch neither 018 nor 022 touches. CASE-18's branch 3 holds that a space exists for the model problem and not the full one, with attractor dimension the parameter. That is directly testable and needs no new code — the same script at --L 28 and --L 34.
Now meaningful, because the base case is settled. Run 022 established branch 1 for KS at L = 22, both halves (convergence and partition-independence, the latter to a 0.002 floor). So a convergence failure at L = 28 or L = 34 is now a fact about dimension rather than about the method — which is exactly what makes this sweep worth the compute. It could not be read that way while L = 22 itself was unresolved.
Why the prediction sits at 0.55. Two things pull in opposite directions. Kaplan–Yorke dimension for Kuramoto–Sivashinsky grows roughly linearly with L, so by L = 34 the attractor needs appreciably more than the three modes the Poincaré section projects onto — and at L = 22 the three-mode PCA already captures only 61% of the variance. Against that, the convergence at L = 22 was clean enough (drift 0.0080 over an elevenfold range in cells) that a nearby L failing outright would be surprising.
The diagnostic to watch is the PCA variance, not just |λ₂|. It is printed at phase 1 and costs nothing. If it falls markedly below 0.61 at larger L, the section is losing the attractor and any convergence failure is about the embedding rather than about the resonance — which is a different finding and needs saying separately.
Amendment (2026-09-14): the null is uninterpretable at fixed mode count — gate before claiming branch 3. The phase-1 figure is now in for L = 28, and it confirms the worry rather than allaying it: the 3-mode PCA variance is 0.614 at L = 22 and 0.538 at L = 28. The section is losing the attractor as L grows, on schedule with the roughly linear Kaplan–Yorke estimate. So a convergence failure at larger L reads two ways and the run as designed cannot separate them: either the resonance genuinely degrades with attractor dimension (branch 3), or the resonance is fine and the fixed 3-mode section stopped representing the attractor (an embedding failure — a statement about the instrument, not the dynamics). At a fixed mode count the two are indistinguishable, so a null here is not a result.
This is the controller fault House named in PN-001: when a hypothesis says the target is parameter-indexed, existence tests must be run parameterised or not at all. There the hidden parameter was the archimedean spectral parameter; here it is embedding quality — the number of PCA modes the section keeps. An uninterpretable null is not a result.
The gating fix: sweep the mode count alongside L. Run each L at two section dimensions — 3 modes and 5 — so the readings separate. Two runs at the same L: if convergence recovers at 5 modes, the failure was the embedding; if it fails at both 3 and 5, branch 3 is live. The branch-3 verdict cannot be claimed from the fixed-3-mode sweep alone, however clean or dirty its |λ₂| numbers look.
Sizing. 1.42×10⁻⁴ crossings per step at L = 22; the rate at other L is unmeasured and phase 1 reports it. 3×10⁸ steps ≈ 41 minutes each, so both runs in an evening. Save the crossings (--save) so the offset test runs against each for free.
python R18c.py --L 28 --steps 300000000 --save ks28_pts.npy --grids 12 16 20 26 --out ks28.json python R18c.py --L 34 --steps 300000000 --save ks34_pts.npy --grids 12 16 20 26 --out ks34.json python offset_test.py ks28_pts.npy --grids 12 16 20 python offset_test.py ks34_pts.npy --grids 12 16 20
Read the coarse grids. At ~43,000 crossings, grid 12 gives ~300 points per cell and grid 26 only ~63, so a wider spread at fine grids is thin statistics rather than partition dependence.
Amendment (2026-09-14): the L = 34 leg is loop-bound — vectorise R18c.py first. The measured throughput, 1.22×10⁵ steps/s, is ~8 µs per step — for 64-point FFTs that cost ~1 µs. The other ~7 µs is Python call overhead, paid over three billion iterations, so the run is loop-bound, not compute-bound, and a faster machine buys almost nothing. The fix is to vectorise across realisations: run 30 independent trajectories with different seeds as one 2D array, so each FFT call does all thirty at once. That directly answers L = 28's 30× lower crossing rate — same wall time, thirty times the crossings — and cuts the L = 34 leg from twenty hours to roughly one (arithmetic below). It is a change to R18c.py, not to the experiment (the --L sweep is unchanged), and it is the first TODO item under Runs; the L = 34 leg is gated on it (blocked_on).
Sizing, shown (2026-09-14). At L = 28 the crossing rate is 4.8×10⁻⁶ per step per realisation. R = 1, the run in flight: 8×10⁹ steps × 4.8×10⁻⁶ ≈ 3.8×10⁴ crossings in ~20 h. For the same 3.8×10⁴ at R = 30: 3.8×10⁴ ÷ (30 × 4.8×10⁻⁶) ≈ 2.7×10⁸ steps — a thirtieth of the R = 1 run, because thirty trajectories cross in parallel. At the same per-step cost that is ~20 h ÷ 30 ≈ 40 min; the batched 30-wide step runs about twice a scalar one, so ≈ 40–80 min — an evening, not twenty hours. The 'under an hour' figure recorded above was the author's and was reached the wrong way: a ~2.1× crossing-rate ratio applied across unequal step counts, never written out — right ballpark, wrong derivation. The multiplication here is the correction.
Amendment (2026-09-14): sizing after vectorisation — R18c.py --realisations R, committed at ebed7ce. Measured on one machine at L = 22, 6×10⁶ steps: R = 1 streamed in 72 s, R = 30 in 151 s — thirty times the trajectory for 2.1× the wall time, not the same wall time the amendment above expected. Carried to L = 28's measured rate of 4.8×10⁻⁶ crossings/step/realisation:
So vectorisation turns an ~18 h run into a ~1.3–1.9 h one — roughly ten times faster, but not under an hour. That is what makes the L = 34 leg practical. Its own rate is lower still and unmeasured; RATE is printed per realisation, so size L = 34 from a short R = 30 run. With R > 1, --save also writes a _rows.npy sidecar, and offset_test.py uses it to skip transitions between trajectories.
Baseline (R = 1, recorded 2026-09-14). python R18c.py --L 22 --steps 6000000 --calib 1000000 gives 832 crossings and a 3-mode PCA variance of 0.6186 — the single-trajectory reference the vectorised run must reproduce. None of the three parameters was in the repo before now, which is why reproducing it took a round trip (see the reproduction-spec instance in OPS.md).
Amendment (2026-09-15): the L = 28 3-mode point is in — a NaN, which is the gated outcome, not a failure. The single-trajectory L = 28 run completed at 3-mode PCA (variance 0.538, against 0.614 at L = 22), and offset_test returns NaN at every grid: the Ulam operator cannot resolve a second eigenvalue because the 2-D section no longer separates the dynamics. This is the embedding failing, demonstrably — not branch 3. It is exactly what the gating above anticipated: at a fixed 3-mode count a null is uninterpretable, and here the null is not even a convergence failure but an outright non-computation. So the single 3-mode L = 28 point is uninterpretable for branch 3 by construction, and the mode sweep — the same L at 3 and 5 PCA modes — is now the only route to a number, not an optional refinement. If 5 modes restore a computable λ₂, the failure was the embedding; if a NaN or a convergence failure persists at 5 modes, branch 3 is live.
Bugs surfaced (2026-09-15), to fix in the scripts — not fixed here. - R18c.py line 103 crashed with IndexError on the eigenvalue print when u had fewer than two elements. The crossings are saved before the print, so nothing was lost — but the run exits non-zero and appears to fail when it had in fact completed. Check for a saved --save file before rerunning a "failed" L = 28 / 34 run. - offset_test.py labels a NaN spread "FAIL — partition-dependent" when it should read "operator ill-defined / λ₂ not computed." It asserts a specific failure mode (partition dependence — branch 3) that it has no basis to diagnose from a non-finite result. See the OPS instance a NaN is not a verdict.
Amendment (2026-09-20): L = 28 is a travelling-wave window — not an embedding failure, not branch 3. This overturns the 2026-09-15 amendment's reading. The L = 28 trajectory is not chaotic at all: it sits on a stable travelling wave with dominant wavenumber k = 2. Its Fourier moduli |u_k| are constant to 1e-13. In the Poincaré section a wave shows up as an exact 2-cycle: in the original R = 1 set (~/mapofmath/ks28_pts.npy, 38,359 crossings), the median |x[k+2] − x[k]| is 0.00000, consecutive crossings are one full diameter apart (1.56422 both), and the crossings arrive like a clock, exactly 96 per 2×10⁷ steps from the start. Only 2 cells are ever occupied, so the Ulam operator is 2×2 and eigs cannot return a second eigenvalue. The NaN was a 2×2 operator on a wave. It was not a section failing to separate chaotic dynamics, and it says nothing about a resonance, because there is no chaos for a resonance to belong to. The rerun at R = 30 lands every realisation on the same wave family at a different position along it, which gives 30 closed classes and |λ₂| = 1.0000 at both 3 and 5 modes.
The 0.538-vs-0.614 variance comparison was never meaningful. The seed-0 run locks onto the wave by t ≈ 2000 (max relative std of |u_k|: 1.6 at t = 1000, 9×10⁻⁷ at t = 2000, 3×10⁻¹⁴ from t = 4000). calibrate() starts sampling at step calib//10, which is t = 2000 at the default --calib. So the L = 28 PCA basis was fitted to the wave itself. The comparison set a wave's variance against a chaotic attractor's, and could not measure an attractor outgrowing its section. The earlier reading that variance falls with L on the Kaplan–Yorke schedule does not survive either: in chaotic windows the 3-mode variance is 0.5241 at L = 30 and 0.6019 at L = 34.
Where the chaos is: a Lyapunov sweep. This is the largest Lyapunov exponent λ_max, measured with the renormalised-twin method: 6 seeds per L, t = 4000 of transient, then t = 4000 of measurement. It is calibrated against L = 22, where it gives 0.047–0.055 against the published ~0.048 (Cvitanović, Davidchack & Siminos).
| L | λ_max over the 6 seeds | attractor | ||||
|---|---|---|---|---|---|---|
| 22 | 0.047–0.055 | chaotic | ||||
| 23 | 0.013–0.016 in 5 seeds; ≈ 0 in 1 | weakly chaotic, with a coexisting non-chaotic attractor | ||||
| 24–25 | ≈ 0 | not chaotic: k = 3, | u_k | modulated by ~0.1% | ||
| 26 | 0.044–0.062 | chaotic | ||||
| 27–29 | ≈ 0 | not chaotic: 27–28 a pure k = 2 wave ( | u_k | constant to 1e-13); 29 strongly modulated ( | u_k | varies ~40%) |
| 30 | 0.053–0.067 | chaotic | ||||
| 31–33 | ≈ 0 | not chaotic: k = 4, | u_k | modulated by 0.7–1% | ||
| 34 | 0.044–0.060 | chaotic |
The 30-realisation Ulam sweep at 10⁷ steps (--grids 8) agrees. At L = 26, 30 and 34 the operator is irreducible, λ₂ resolves, and no realisation shows return-map recurrence over t = 10⁵. At L = 24 and 32 it is reducible, like L = 28. The literature confirms KS has windows of steady, travelling-wave and time-periodic attractors interspersed with chaos as L grows (Papageorgiou & Smyrlis; Hyman, Nicolaenko & Zaleski). No source found names L = 28 specifically, so the window edges above are this computation's, not a citation's.
Caveats. (1) The "≈ 0" entries share a floor of 0.001–0.002, and the per-seed values are identical to three digits at every non-chaotic L. This is a finite-time artefact of the measurement: the neutral translation direction of a wave does not relax to exactly zero in t = 4000. The cause of the identical digits is not explained. It does not affect the classification, since the floor is an order of magnitude below the weakest chaotic value (0.013 at L = 23). (2) Six seeds out to t ≈ 8000 cannot rule out a rare chaotic basin, or a long chaotic transient, inside a non-chaotic window. L = 23 shows that chaotic and non-chaotic attractors do coexist in this range.
What this does to the run. The prediction's middle term, "converges at L = 28", tested a property of a chaotic attractor at an L that has none. It cannot pass or fail and is withdrawn. The falsifier "breakdown already at L = 28" is withdrawn with it: a wave has no resonance to break down. The 3-vs-5-mode check moves to L = 26, 30 and 34. These are the chaotic L values that bracket the dimension sweep, and L = 34 is still chaotic, so the prediction's last term ("stops converging by L = 34") can still be tested. The 2026-09-15 gating logic stands, applied to these L. Before any λ₂ at a new L is read, check that λ_max > 0 there.
The two script bugs listed above are fixed. They landed in 86e9256 (under an unrelated commit message) along with R18c.py --modes N / --cells and a third guard. A reducible operator now reports "NOT RESOLVED — operator reducible, k closed classes" instead of |λ₂| = 1.0000, which offset_test.py would otherwise have scored PASS on a zero spread.
Outcome, 2026-09-21 — the field is held open until the mode amendment lands. Runs now carry an outcome: field (confirmed · falsified · unanticipated · withdrawn, docs/GLOSSARY.md), set by the codifier when the run is scored. The L = 34 leg has now been tested: the 3-vs-5-mode check finished at L = 34, which converged cleanly at both mode counts — |λ₂| ≈ 0.155–0.166, PASS at every grid (data in ~/mapofmath/run023/, outside this repo). L = 26 is still running, and the amendment will be written from the full data by the session doing the mode sweep. outcome: is set from that record, not from this paragraph — one field, one writing, from the complete set.
The expected token is unanticipated, and the reasoning belongs here rather than in the token. The sealed prediction said convergence stops by L = 34. The sealed falsifier said breakdown already at L = 28 — withdrawn 2026-09-20, because L = 28 is a travelling-wave window with no resonance to break down. What was observed is no breakdown at any chaotic L tested. That is neither the predicted result nor the refuting one: the prediction and the falsifier both assumed a breakdown and disagreed only about when, so between them they never covered the outcome space, and the actual answer fell through the gap. falsified would be wrong — the falsifier's condition did not occur, and it is withdrawn besides. confirmed would be wrong twice over.
That gap is the finding, not a defect in the bookkeeping. A sealed pair that partitions "when" but not "whether" cannot be scored against a result that answers "whether". Worth a line in OPS.md if it happens a second time.
Amendment (2026-09-21): the 3-vs-5-mode check at L = 26, 30, 34 — scored, and both failures diagnosed. Run on the M5 from commit f07ed9c with R = 30, --calib 1000000. The main runs are 2×10⁷ steps (100–126k crossings); L = 26 was rerun at 10⁸ steps (500,641 crossings). Data are in ~/mapofmath/run023/. For the 5-mode runs the offset test reseeds the k-means partition, a coarser perturbation that the 0.0080 threshold was not calibrated for.
| L | modes (variance) | \ | λ₂\ | as cells refine | offset test | reading |
|---|---|---|---|---|---|---|
| 34 | 3 (0.6019) | 0.1537 / 0.1556 / 0.1578 / 0.1568 (grids 12–26) | PASS at 12, 16, 20 (spread ≤ 0.0044) | converged | ||
| 34 | 5 (0.7536) | 0.1522 / 0.1547 / 0.1657 / 0.1636 | PASS at 12, 16, 20 (reseed) | converged; agrees with 3 modes within ~0.01 | ||
| 30 | 3 (0.5241) | 0.8881 / 0.9867 / 0.9790 / 0.9920 | FAIL | λ₂ → 1 (diagnosed below) | ||
| 30 | 5 (0.7361) | 0.8189 / 0.9039 / 0.9414 / 0.9606 | FAIL | λ₂ → 1 | ||
| 26 | 3 (0.7374) | 0.160 / 0.180 / 0.191 / 0.183 / 0.211 / 0.204 (grids 12–40, 500k) | FAIL (0.011–0.025) | wanders, no plateau | ||
| 26 | 5 (0.8378) | 0.230 → 0.407 (grids 12–40), then 0.423 / 0.450 / 0.479 at 2,500 / 4,900 / 10,000 cells | — | climbs, no plateau |
Scored: the live term is a miss. At L = 34 the resonance converges: |λ₂| ≈ 0.155. It drifts by 0.004 over a 4.7× range in cell count at 3 modes, passes the offset test at every grid, and agrees with 5 modes within ~0.01, so even 3 modes embed it adequately. The prediction's one live term, "stops converging by L = 34", missed. It stays as sealed. (This paragraph first recorded outcome: falsified; the codifier ruling below corrects it to unanticipated.) Branch 3 as stated is not supported. Failure is not monotone in L: 26 and 30 fail and 34 passes, so it is not governed by attractor dimension. The two failures have different causes.
Codifier ruling (2026-09-21): outcome: unanticipated, not falsified. The prediction ("stops converging by L = 34") missed: L = 34 converges. The falsifier ("clean convergence at every L") did not fire: L = 26 never converges at any reachable resolution. Its other clause, breakdown already at L = 28, was withdrawn on 2026-09-20. The observed behaviour is non-monotonic in L (26 and 30 fail, 34 passes), which neither clause anticipated. Run 024 was falsified because its falsifier fired; this one's did not. This agrees with the token pre-registered in the outcome paragraph above. It corrects that paragraph's premise, though: the observation was not "no breakdown at any chaotic L tested" (L = 26 never converges), and it is the unfired convergence clause, not only the withdrawn L = 28 clause, that makes falsified wrong.
L = 30: a chaotic transient collapsing onto a stable state, not reflection switching. The hypothesis tested first was slow switching between the two reflection-symmetric halves of the attractor (u(x) → −u(−x)). It is rejected, on three counts: - The λ₂ almost-invariant sets, read from the left eigenvector (a function on cells), split the crossings about 0.4–4% against the rest at every grid and both mode counts. Mirror halves would split about 50/50. - Q = ⟨u³⟩ is invariant under translation and odd under the reflection. It was recorded at every crossing by replaying the run's own trajectories (the replay matches the first 43k saved crossings bit for bit). Q is symmetric overall (49.6% positive) and flips sign every ~2 crossings (median dwell 2, maximum 50). - Since the symmetry is not the slow mode, quotienting by it would not recover λ₂. That was not pursued.
The slow mode is instead escape from chaos. By t = 2×10⁵, 11 of 30 realisations have collapsed onto an exactly period-1 state in the section (\|x[k+p] − x[k]\| = 0 for all p) and stay there, the earliest 74% of the way through its run. With no returns, the chaotic set at L = 30 is a long-lived chaotic transient (a rough escape rate of 2×10⁻⁶ per time unit, from 11 events). It is not an attractor. This corrects the 2026-09-20 Lyapunov table, whose "chaotic" at L = 30 was measured at t ≲ 8000 and could not see a lifetime of order 10⁵. Excising each collapsing realisation from where it comes within 1% of the section diameter of its final state (1,048 crossings) leaves the pre-collapse set: - At 3 modes, λ₂ = 0.352 / 0.358 / 0.369 / 0.369 at grids 12–26. The offset spread narrows with refinement (0.052 → 0.015 → 0.011 → 0.0045), passing only at grid 26. - At 5 modes it still climbs (0.517 → 0.675).
So L = 30's asymptotic regime is not chaotic. A resonance of its chaotic transient, conditioned on not having escaped, is ≈ 0.37 at 3 modes, but that is a different quantity from the one this run asks about. Earlier readings of L = 30 as "intermittent" (laminar near-period-1 phases, recorded only in conversation) are not supported: laminar crossings are enriched in the slow set (24.5% against 6.6%), but only 0.8% of them lie in it.
L = 26: unresolved, and not for lack of samples. - No collapses: none of the 30 realisations collapse over t = 10⁶. - Not a sampling problem: at fixed grid, λ₂ is almost independent of sample size (25%, 50% and 100% of each realisation agree within ~0.02, with a slight downward drift that is ordinary finite-sample bias). Five times more crossings left the 2-D offset spreads essentially unchanged (0.021–0.029 → 0.011–0.025). - The 2-D number is stuck: a 2-D k-means partition agrees with the lattice (0.21–0.22 against 0.20–0.21 at fine grids), so the 3-vs-5 gap is the section's dimension, not the partition method. The 2-D value stays at 0.18–0.21, partition-dependent at 2–3× the threshold, with no plateau. - The 4-D value climbs: it rises monotonically through 10,000 cells (~10 bins per axis) and was still gaining ~0.03 per doubling of the cell count at the end.
Read together: the 2-D section smooths away structure the 4-D section keeps, and the 4-D Ulam operator has not reached a plateau at any reachable resolution. L = 26 has no resolved λ₂ by this method, and that is a resolution limit, not an absence. The 4-D partition reaches only ~10 bins per axis at 10,000 cells, and λ₂ was still rising there. Its non-convergence is a limit of the partition, not evidence that the resonance is absent. Nor is it evidence for branch 3, which the pattern across L already rules out as stated.
A caveat on the 3-vs-5 gate itself. n² cells in 4-D is only about √n bins per axis (≈ 5 at grid 26), against n per axis in 2-D. So a 5-mode λ₂ that climbs with refinement may simply be under-resolved, and "5 modes disagree with 3" is not by itself evidence about the embedding. It did not matter at L = 22 or L = 34, where both plateau early. It does at L = 26 and L = 30.
generated 2026-10-25the lab index