OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb commits / 4e48f53

basal-agent: stress-sharing NULL, dimension-addition NEGATIVE, and the law of #7 corrected
Two experiments testing whether recent Levin work suggests a new trajectory. Both negative. The session's one durable result came from re-reading #7 against its own evidence, not from either experiment. Filed as atomspace #8. THE CORRECTION. #7 §4 says a fitness valley "cannot be crossed by search" and the resolution is "always a SUPPLIED boundary". Contradicted inside #7 twice: rung34.c has compartmentalization — a boundary — evolving UN-FORCED (0.1→0.94, frozen control collapsed, SYNTHESIS.md:92), and evoworld.c crosses the valley with population+selection, which §2 states explicitly. It also does not fit reality: multicellularity arose independently ~25 times with nobody supplying the vesicle, and valley-crossing is a RATE question, not a possibility question. Defensible restatement: a LOCAL, ONLINE, GREEDY, SINGLE-LINEAGE, FIXED-DIMENSION search cannot cross a coordination valley. stress.c — error-sourced leaked temperature field. run 1 VOID. All four arms agreed at +0.25 INCLUDING the prior-art control. poscheck.c showed the harness drifts away from an answer it is handed (+0.0000 → +0.0096, 50% uphill acceptance). run 2 NULL, six guards passed. Leaking did not help; A is the worst of the three local arms on the primary endpoint. dscale.c — the calibration that explains run 1, and generalizes: signal per single-entry step 2e-5; window-to-window noise 380x that, and still 114x at a 20x larger window. COMMON RANDOM NUMBERS IS MANDATORY, not a refinement — window size cannot buy you out. The whole Part A arc wanted this number before concluding what local mechanisms can do. dup.c — dimension-addition (Ohno duplication-divergence), the one of reality's four coordination resources the substrate structurally forbade. NEGATIVE: growing into N=3 is reliably worse than starting there. 5/5 seeds, both endpoints, scoring budget matched to ratio 1.000. The pre-registered null was wrong and is not claimed. Likely mechanism: duplication makes an EXACT copy, so breaking that symmetry is itself a valley — manufactured one level down by the move meant to avoid it. Design flaw named: 16 restarts reported as a max is not population+ selection, so this supplied the missing resource while omitting the one known to cross this valley here. Lesson for #7's error table: "did the test run?" and "can the test succeed?" are different guards. A search that cannot hold an answer it is HANDED will confidently null any hypothesis put through it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4e48f531f07515d7473ed81ac133c3f2f08282be
by plankatron <fleeky@gmail.com> · 2026-09-11T22:51:37.000Z

Changed files (10) +1179 -0

basal-agent/.gitignore +5 -0
……@@ -57,3 +57,8 @@ ladder35
5757chain12
5858threecarrier
5959fluctuate
60stress
61poscheck
62poscheck_t
63dscale
64dup
basal-agent/TRAJECTORY.md +412 -0
……@@ -0,0 +1,412 @@
1# Trajectory — 2026-09-11
2
3Written after reading two Levin papers (filed at `opencog-kb/papers/`) against
4`PAPER.md`, `SYNTHESIS.md` and `POSTMORTEM-2026-07-31.md`. This file is the
5**pre-registration**: what is being claimed, what would falsify it, and what is
6explicitly *not* being imported.
7
8---
9
10## The queue is unchanged at #1
11
12`POSTMORTEM-2026-07-31.md` ranked **re-run the fluctuating-environment test scored on
13function, not template count** as next step #1: cheapest, highest value, design already
14correct, only the metric wrong (reading raised working fraction 0.294 → 0.478 and function
151.27 → 1.47). Nothing below displaces it. A new idea must not push out a nearly-finished
16one — that is the exact failure mode the postmortem documents.
17
18---
19
20## What is new
21
22### 1. A *local* fitness-valley crosser exists in the literature, and we concluded none did
23
24Our law (`PAPER.md` §4): *a fitness valley cannot be crossed by search; only by a directed
25structural move plus non-greedy drift* — and Part A's wall: **nothing local / online /
26greedy / self-organized crosses it** (nine mechanisms, `learn.c` through `wakesleep2.c`).
27
28Shreesha & Levin 2024 (BBRC 731:150396), Fig. 1 A1/A2, is a fitness valley crossed by a
29local distributed mechanism:
30
31- a cell is stuck; its neighbours are **at their setpoints** — a local optimum
32- nobody moves, because every individual move is worse for the mover
33- stress **leaks** from the stuck cell → neighbours' plasticity (their word: *temperature*,
34 from annealing) rises → they accept a temporarily worse configuration → a channel opens
35
36Why this is not one of our nine: every annealing mechanism we tried used a **global scalar
37schedule**. `da-em.c` (3 schedules) broke onto a wrong branch or re-symmetrized at β_c.
38`soc.c` found β_c (β→0.98) but online averaging washed it out. `critical.c`'s homeostat was
39**blind — washout *is* max usage-entropy**, so its thermostat steered into the attractor.
40
41Levin's is a **temperature field sourced from local error and leaked with its provenance
42destroyed**. Never tried here. And it does not share `critical.c`'s failure mode: it is
43driven by distance-from-setpoint, and washout has *high* error, so the field holds
44temperature up rather than declaring victory.
45
46→ **`stress.c`**, below.
47
48### 2. Anonymity, not messaging, is the collective mechanism
49
50The load-bearing sentence in the stress paper is not about signalling:
51
52> *"A given cell cannot tell if its high stress sensation is due to a problem it has or a
53> problem its neighbors have."*
54
55Addressed messages give you a **society**. Destroyed provenance gives you an **individual** —
56a cell cannot locate where its own self ends. Cooperation with **zero altruism**: every cell
57only ever minimizes its own stress.
58
59Our law says individuality must be **supplied** (*"an isolated collective cannot bootstrap
60its own individuality"*), so `belief_field_agent.c` supplies it. Anonymized error-leak is the
61first concrete candidate mechanism for *what the supplied thing could be*, rather than "draw
62a box".
63
64### 3. `deferred vs instantaneous selection` has independent cross-domain support
65
66Our fifth 1→2 constraint, found on the last night: **memory cannot pay under instantaneous
67selection** — *"anything scored on current state cannot afford storage."*
68
69The stress paper's flagged negative result: **anatomical goal states could not be inferred
70from observation of stress states**, *"revealing the limitations of knowledge of goals by an
71extern observer outside the system itself."*
72
73Same claim, opposite direction: **the instantaneous error signal underdetermines the deferred
74goal.** Two groups, different substrates. By this repo's own standard — `chain12` earned its
75weight by being the one *replicated* effect — this is the strongest thing in the folder and it
76is currently a bullet under "Research ideas".
77
78### 4. A metric we are missing, and already measure the shadow of
79
80The stress paper measures **radius of influence** (persists to stage ~85 with sharing, ~10
81without) and names it the **cognitive light cone** — the spatio-temporal radius of goal states
82a homeostat can pursue. It has a pathology: **cancer is that radius collapsing to one cell**.
83
84`belief_field_agent.c` measures inter-unit agreement 0.999 and calls the field's extent a
85*coherence domain* — but never **varies** it. There is no sweep.
86
87*"Small compartments correct but forget"* appeared **four independent times** in our ladder.
88That is a result waiting for an axis.
89
90### 5. Their methodology is ours, with a number attached
91
92Levin §5.5: *"in systems where every component is known, there is nowhere to hide... quantify
93the effort put in and the competencies that emerge; the delta between them."*
94
95Our razor: *"never encode the answer in the update rule — did I encode the outcome, or did it
96arise?"* Same discipline; ours is **binary**, theirs is **graded**. Adopting the delta framing
97turns ~20 pass/fail ladder verdicts into a measure.
98
99---
100
101## What is explicitly NOT imported
102
103- **Levin's ingression metaphysics.** *Philosophies* 11:161 is explicitly **non-physicalist
104 and dualistic** (his words, in the abstract; the reference list opens with four Stapp papers
105 and Popper–Eccles interactionism). "The pattern was in Platonic space and the pointer
106 accessed it" is not codeable. `evoworld.c` already states the useful half testably: with
107 selection off the population drifts — **the direction comes from the world, never the dice.**
108- **Linas Vepstas' here-and-now physics.** No-cloning, light-cone thickness, wavefunction
109 collapse: none of it touches a C program learning an HMM. The parts of his work that do
110 apply — jigsaws, connector-mating, staged batch MI learning — are already cited in `README.md`
111 as the reason his pipeline is batch and not online.
112- **Reopening the origin-of-life ladder.** The postmortem's stopping signal stands: *"three
113 voids in a row, each fix exposing a deeper flaw, means the model of the problem is behind the
114 model of the code."* Neither paper moves rung 1→2.
115
116---
117
118## Ranked
119
120| # | item | status |
121|---|---|---|
122| 1 | fluctuating environment, **scored on function not template count** | unchanged from postmortem |
123| 2 | **`stress.c`** — error-sourced local temperature field on Mess3 | pre-registered below |
124| 3 | **coherence-domain sweep** on `belief_field_agent.c` | gives "correct but forget" its axis |
125| 4 | `chain12` robustness (longer runs, `NRXN`/`NSPEC` variation) | unchanged from postmortem |
126| 5 | write up **deferred vs instantaneous selection** as its own note | now has independent support |
127
128---
129
130## Pre-registration — `stress.c`
131
132**Question.** Does a locally-sourced, error-proportional, provenance-destroyed temperature
133field cross the Mess3 structure-learning valley, where a global schedule (`da-em.c`) and a
134usage-entropy homeostat (`critical.c`) did not?
135
136**Arms.** M units, each an independent candidate tensor over the *same* stream, Metropolis
137proposals, differing only in where each unit's temperature comes from:
138
139| arm | temperature source |
140|---|---|
141| **A** stress-sharing | diffused field — own + neighbours, **indistinguishable at the read** |
142| **B** no sharing | own excess only (Levin's own control arm) |
143| **B2** mean-T-matched | uncoupled, but T rescaled to match A's realized mean T |
144| **C** global schedule | one shared annealing schedule (prior art: `da-em.c`, `soc.c`) |
145
146**B2 exists because of postmortem lesson (a)** — one knob moving two variables, 3 of 4 prior
147instances failed. Coupling raises mean temperature *and* targets it. B2 holds the mean fixed
148so the surviving difference is **targeting**, not amount. Both A and B get the same `T_FLOOR`
149so B is not trivially frozen.
150
151**Primary endpoint — and this is the trap.** `README.md` records that **prediction (log-loss)
152barely distinguishes finite / infinite / fractal structure**. Scoring on log-loss alone would
153repeat a documented error. Primary endpoint is therefore the **distinct-belief-state count vs
154resolution** (box-dim growth); log-loss gap is **secondary**.
155Reference ladders at G=30/100/300/1000/3000 (`critical.c`): true Mess3
156**396 / 2399 / 8924 / 26394 / 54821**; `learn.c` collapse **5 / 9 / 14 / 20 / 36**.
157Optimal log-loss ≈ **0.794 nats**.
158
159**Statistic.** Two-arm question → report the **separation** A−B across seeds with its spread,
160never an absolute bar (postmortem lesson (b): `linkage.c` used an absolute bar on a control in
161a two-arm experiment).
162
163**"Did the test actually run?" guard** — the thing that caught four invalid experiments:
1641. arm A's field must actually diffuse and arm B's must not (cross-unit stress correlation)
1652. uphill acceptances must be > 0 in A, B, B2 — otherwise no annealing happened → **VOID**
1663. arm C's schedule must actually span its β range
1674. the generator must emit all 3 symbols at plausible marginals
168
169**Pre-registered most-likely null, stated before the run.** Levin's valley is a **spatial
170rearrangement** barrier — cells physically blocking each other. Ours is a **parameter-space**
171barrier — an HMM local optimum. These may not be the same kind of wall, and that is the
172likeliest reason for a null. Recorded here, and in the file header, because *"a written
173diagnosis did not survive context pressure"* — the template-abundance error was diagnosed in
174`genome.md` in plain language and then rebuilt twice.
175
176**What counts as what.** Hit: A's box-count ladder grows while B/B2/C stay flat or collapsed,
177consistently across seeds. Null: A ≈ B2. Either is a result — a hit revises the structural
178claim that *inference is local, learning is not*; a null hardens it against the strongest
179counterexample anyone has produced.
180
181---
182
183# Record — `stress.c` run 1: **VOID**
184
185*Not a null. An invalid experiment, caught by a control that was missing from the
186pre-registration above and has since been added as guard [6].*
187
188## What run 1 reported
189
190| arm | gap vs optimal | ladder G=30…3000 |
191|---|---|---|
192| A shared | +0.2513 ± 0.0186 | 17 / 40 / 84 / 197 / 441 |
193| B private | +0.2472 ± 0.0159 | 16 / 44 / 98 / 244 / 576 |
194| B2 matched | +0.2460 ± 0.0203 | 15 / 36 / 83 / 202 / 444 |
195| C global | +0.2589 ± 0.0101 | 20 / 61 / 142 / 386 / 980 |
196| *true Mess3* | 0 | *396 / 2399 / 8924 / 26394 / 54821* |
197
198Guards [1]–[5] all passed. Separation B2−A = −0.0053 ± 0.0212 — no effect.
199
200**The tell:** all four arms landed on the same number, including **C, the prior art**. When
201every arm including the control agrees, the knob under test was not the operative variable.
202
203## The missing control
204
205`poscheck.c` — seed a unit at the **TRUE tensor** and run the same Metropolis:
206
207```
208TRUE-seed start 0.7960 (gap +0.0000) -> end 0.8055 (gap +0.0096) uphill 1998/4000
209NEAR-true start 0.7985 (gap +0.0025) -> end 0.8119 (gap +0.0159) uphill 2028/4000
210```
211
212**The harness drifts away from an answer it is handed**, accepting 50% of uphill moves. No
213arm result can mean anything under that.
214
215This is the `byproduct.c` failed-positive-control and `fidfloor.c` broken-baseline class,
216repeated. Guard [2] ("did annealing happen?") is not the same question as **"can this harness
217succeed at all?"** — it answered yes while the search was pure diffusion.
218
219## Diagnosis — measured, not guessed (`dscale.c`)
220
221| WIN | signal: \|Δ\| per single-entry STEP | window-to-window noise | noise/signal |
222|---|---|---|---|
223| 10 000 | 0.00002 | 0.00662 | **380×** |
224| 50 000 | 0.00001 | 0.00306 | 290× |
225| 200 000 | 0.00001 | 0.00082 | 114× |
226
227Two independent defects, both fatal, both invisible without this measurement:
228
2291. **Temperature 250× too hot.** Signal is 2×10⁻⁵; run 1 used `T_FLOOR` 3.5×10⁻³. At that
230 temperature `exp(−2e−5/5e−3) = 0.996` — it accepted essentially every uphill move. Not
231 annealing; diffusion.
2322. **Δ taken across different windows.** `d = llp(window_t) − ll[u](window_{t−1})`. With noise
233 at 380× the signal, every acceptance test in every arm was a coin flip on sampling noise.
234 **That is why all four arms agree.**
235
236**Generalizes beyond this file:** noise is still 114× signal at a 20× larger window, so
237**common random numbers is mandatory, not a refinement** — window size cannot buy you out of
238it. Any sampled-window Metropolis/annealing search over this HMM needs shared-window Δ and
239T ≈ 10⁻⁵. The Part A arc would have wanted this number.
240
241## Fix verified before re-running (one change, one verify)
242
243`poscheck.c` swept on T:
244
245| T | TRUE-seed end gap | NEAR-true end gap |
246|---|---|---|
247| 5×10⁻³ *(run 1)* | **+0.0096** ✗ drifts off | **+0.0159** ✗ diverges |
248| 2×10⁻⁴ | +0.0012 | +0.0007 |
249| **2×10⁻⁵** | **+0.0005** ✓ holds | **+0.0001** ✓ **converges** |
250| 5×10⁻⁶ | +0.0002 ✓ | +0.0001 ✓ |
251
252At the calibrated temperature the harness both **holds** the optimum and **converges** to it
253from near-true. Capability established; run 2 is therefore interpretable.
254
255**Applied to `stress.c`:** `T_FLOOR` 3.5e−3 → **5e−6**, `T_GAIN` 0.045 → **6e−4**, Δ now taken
256on a shared window, and **guard [6] = positive control** added so this cannot recur silently.
257
258## Lesson (for the postmortem's list)
259
260> **"Did the test run?" and "can the test succeed?" are different guards.** Run 1 had four
261> guards of the first kind and none of the second. A search that cannot hold an answer it is
262> *handed* will report a confident, well-behaved, fully-guarded null for any hypothesis you
263> put through it.
264
265Corollary: **when every arm including the control agrees, suspect the harness, not the
266hypothesis.** The uniform +0.25 across four arms was visible in the first output and is a
267stronger signal than any of the five guards that passed.
268
269*(Run 1 killed mid-re-run by a power outage; all artifacts survived intact. Run 2 below.)*
270
271---
272
273# Record — `stress.c` run 2: **NULL** (valid)
274
275All six guards passed, positive control [6] at **+0.0002**. Harness capability established
276before the arms were read. This is an interpretable result.
277
278## PRIMARY — distinct belief states vs resolution (seed 0 best unit)
279
280| arm | G=30 | 100 | 300 | 1000 | 3000 |
281|---|---|---|---|---|---|
282| A shared | 127 | 488 | 1430 | 3381 | 5989 |
283| B private | 180 | 776 | 2210 | 5085 | 8763 |
284| B2 matched | 216 | 955 | 2597 | 5539 | 9187 |
285| C global | 121 | 481 | 1395 | 3364 | 6137 |
286| **TRUE Mess3** | **396** | **2399** | **8924** | **26394** | **54821** |
287| learn.c collapse | 5 | 9 | 14 | 20 | 36 |
288
289## SECONDARY — log-loss gap (5 seeds)
290
291| arm | gap | |
292|---|---|---|
293| A shared | +0.0051 ± 0.0020 | |
294| B private | +0.0049 ± 0.0019 | |
295| B2 matched | +0.0069 ± 0.0023 | |
296| C global | +0.0102 ± 0.0044 | |
297
298**Separation B2 − A = +0.0018 ± 0.0042** — crosses zero. No effect.
299
300## Verdict: the hypothesis is not supported
301
302**Leaking did not help.** A (shared) ≈ B (private) on log-loss, and on the primary endpoint A
303is the **worst of the three local arms**. Anonymized error-leak produced no advantage over
304each unit annealing on its own error, and A is indistinguishable from C, the global schedule
305it was supposed to beat.
306
307The **pre-registered most-likely null stands as the leading explanation**: Levin's valley is a
308*spatial rearrangement* barrier — cells physically blocking one another, where a neighbour
309must literally move aside. Ours is a *parameter-space* barrier. Leaking a scalar into a
310parameter search has no "get out of the way" move to buy. This was written in the file header
311before the run and is what the data now says.
312
313## Two things the run establishes that were not the hypothesis
314
315**1. No arm crossed.** Every arm sits 6–9× below true Mess3 at G=3000 (5989–9187 vs 54821).
316The valley was not crossed by *any* temperature-sourcing strategy. The wall documented in
317Part A is undisturbed.
318
319**2. The ladder and log-loss disagree on ordering** — B2 is *best* on the ladder and *worst*
320of the local arms on log-loss. That is an independent confirmation of the README's finding
321that **prediction barely distinguishes structure**, arriving here by accident. Had this been
322scored on log-loss alone (the obvious choice) it would have reported the opposite ranking.
323
324## Known weakness — fix before citing the ordering
325
326**The primary endpoint is n=1.** The ladder is computed for seed 0's best unit only; only the
327secondary endpoint has 5 seeds. So the B2 > B > A ordering **cannot be claimed** — it is one
328draw. What survives n=1 is the robust part: *no arm is near true*, which holds across all four
329arms and agrees with the log-loss.
330
331Next: compute the ladder per seed and report its spread. Until then the ordering is an
332observation, not a result.
333
334---
335
336# Record — `dup.c`: **NEGATIVE** (valid). Growing is *worse* than starting there.
337
338Guards passed: both arms end N=3 (equal capacity), scoring-call budget **exactly matched
339(ratio 1.000)**, positive control +0.0001.
340
341## PRIMARY — distinct belief states @ G=3000, all 5 seeds
342
343| | s0 | s1 | s2 | s3 | s4 | mean |
344|---|---|---|---|---|---|---|
345| **F fixed** | 7083 | 9159 | 7851 | 8132 | 9643 | **8374** |
346| **D grow** | 4766 | 2296 | 5118 | 5378 | 5351 | **4582** |
347
348*true Mess3 @ G=3000: 54821 ; learn.c collapse: 36*
349
350**F beats D on 5/5 seeds.** Secondary agrees: F +0.0052 ± 0.0022 vs D +0.0192 ± 0.0068,
351separation **F−D = −0.0140 ± 0.0074**, negative on every seed. Both endpoints agree this
352time (they disagreed in run 2), which strengthens it.
353
354## This is not the null that was pre-registered
355
356Pre-registered: *D ≈ F, because the N=2 optimum lands in the same basin its duplicate
357occupies.* Observed: D is **reliably and substantially worse**. The pre-registered
358explanation does not cover the result and is hereby not claimed.
359
360## The likely mechanism — and it is interesting
361
362**Duplication creates a symmetry, and breaking that symmetry is itself a valley.**
363
364An exact copy leaves two states identical. Divergence from that point requires coordinated
365change across both copies, with single-entry proposals at T=2e-5 — the same class of barrier
366the whole arc is about, now manufactured one level down by the very move meant to avoid it.
367Random init at N=3 starts *already asymmetric* and pays no such cost. Worse, the N=2 solution
368seeding the duplication is only 200 sweeps old and has already committed to a 2-state
369explanation of a 3-state process; D inherits that commitment.
370
371So dimension-addition did not let the search walk *around* the barrier. It walked into a new
372one.
373
374## What this does and does not establish
375
376**Does not rescue the substrate hypothesis.** The claim was that the wall is a property of
37727-fixed-parameters, not of coordination. Given a way to add a degree of freedom, the search
378did worse. The wall held.
379
380**Does not establish the law either.** This tested *one cheap implementation* —
381scheduled duplication, from N=1, single-entry proposals, and critically **no selection
382between units**. The M=16 units are independent restarts reported as a max, which is not
383population+selection. So this experiment added the one resource the substrate lacked while
384still missing the one resource that is *known to work in this repo*: `evoworld.c` crosses this
385exact valley with population+selection.
386
387**That is the design flaw, and it names the next experiment.** In biology duplication without
388differential survival is just noise injection — duplicates are culled or fixed by selection,
389not annealed. Dimension-addition and selection are plausibly a *conjunction*, and this run
390supplied one without the other.
391
392→ Next: duplication **inside** `evoworld.c`'s population+selection loop. Arms: selection
393alone (reproduces evoworld), duplication alone (this run), both. If the conjunction crosses
394where neither alone does, that is a real result and it matches how the mechanism works in
395reality.
396
397## Standing correction to the law (from the review that prompted this)
398
399PAPER.md §4 — *"cannot be crossed by search... its resolution is always the same: a supplied
400boundary"* — **overstates its own evidence and is contradicted inside the repo**:
401
402- `rung34.c`: compartmentalization — **a boundary** — evolved **un-forced** (0.1→0.94),
403 frozen control collapsed. Not supplied.
404- `evoworld.c`: the valley **is** crossed by population+selection. §2 says so explicitly
405 ("two things cross it"); §4 then says it cannot be crossed.
406
407Defensible restatement: *a **local, online, greedy, single-lineage, fixed-dimension** search
408cannot cross a coordination valley.* That is what was measured. The general claim about
409collectives and individuality is falsified by ordinary biology — multicellularity arose
410independently ~25 times with nobody supplying the vesicle — and "cannot" is doing work that
411"rarely" should be doing, since valley crossing is a **rate** question (stochastic tunnelling)
412not a possibility question.
basal-agent/dscale.c +58 -0
……@@ -0,0 +1,58 @@
1/* dscale.c — calibration, not an experiment. Measures the two numbers stress.c guessed:
2 * (1) |delta| from a single-entry STEP perturbation near the optimum -> what T must sit below
3 * (2) window sampling noise in the log-loss estimate -> the floor on resolvable delta
4 * If (2) >= (1), the acceptance test is a coin flip and no temperature schedule can work. */
5#include <math.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#define K 3
10static const double TT[K][K][K]={
11 {{0.765,0.00375,0.00375},{0.0425,0.0675,0.00375},{0.0425,0.00375,0.0675}},
12 {{0.0675,0.0425,0.00375},{0.00375,0.765,0.00375},{0.00375,0.0425,0.0675}},
13 {{0.0675,0.00375,0.0425},{0.00375,0.0675,0.0425},{0.00375,0.00375,0.765}}};
14static unsigned long long RNG;
15static unsigned long long xs(void){RNG^=RNG<<13;RNG^=RNG>>7;RNG^=RNG<<17;return RNG;}
16static double urand(void){return (double)(xs()>>11)*(1.0/9007199254740992.0);}
17static void gen(unsigned char*o,int n){int s=0;for(int i=0;i<n;i++){double u=urand(),a=0;int e=0,nj=0,d=0;
18 for(int y=0;y<K&&!d;y++)for(int j=0;j<K&&!d;j++){a+=TT[y][s][j];if(u<a){e=y;nj=j;d=1;}}o[i]=(unsigned char)e;s=nj;}}
19static double ll_(const double T[K][K][K],const unsigned char*s,long off,int n){
20 double b[K]={1.0/3,1.0/3,1.0/3},L=0;
21 for(int t=0;t<n;t++){int x=s[off+t];double px=0,nb[K]={0,0,0};
22 for(int i=0;i<K;i++)for(int j=0;j<K;j++){double m=b[i]*T[x][i][j];nb[j]+=m;px+=m;}
23 if(px<1e-300)px=1e-300;
24 L+=-log(px);
25 for(int j=0;j<K;j++)b[j]=nb[j]/px;}
26 return L/(double)n;}
27static void rn(double T[K][K][K]){for(int i=0;i<K;i++){double z=0;
28 for(int s=0;s<K;s++)for(int j=0;j<K;j++){if(T[s][i][j]<1e-6)T[s][i][j]=1e-6;z+=T[s][i][j];}
29 for(int s=0;s<K;s++)for(int j=0;j<K;j++)T[s][i][j]/=z;}}
30int main(void){
31 const long NTR=600000;unsigned char*tr=malloc(NTR);
32 RNG=0x9e3779b97f4a7c15ULL;gen(tr,(int)NTR);
33 int WINS[3]={10000,50000,200000};
34 RNG=0xabcdef1234567ULL;
35 for(int w=0;w<3;w++){
36 int W=WINS[w];
37 /* (1) |delta| from STEP=0.06 single-entry perturbation, SAME window (common random numbers) */
38 double s1=0,s2=0;int N=300;
39 for(int k=0;k<N;k++){
40 long off=(long)(urand()*(double)(NTR-W-1));
41 double base=ll_(TT,tr,off,W),T2[K][K][K];memcpy(T2,TT,sizeof T2);
42 int si=(int)(urand()*K),ii=(int)(urand()*K),jj=(int)(urand()*K);
43 if(si>=K)si=K-1;
44 if(ii>=K)ii=K-1;
45 if(jj>=K)jj=K-1;
46 T2[si][ii][jj]*=exp(0.06*(2*urand()-1));rn(T2);
47 double d=fabs(ll_((const double(*)[K][K])T2,tr,off,W)-base);
48 s1+=d;s2+=d*d;}
49 double md=s1/N,sd=sqrt(s2/N-md*md);
50 /* (2) window-to-window noise in the SAME tensor's score */
51 double n1=0,n2=0;int NN=300;
52 for(int k=0;k<NN;k++){long off=(long)(urand()*(double)(NTR-W-1));
53 double v=ll_(TT,tr,off,W);n1+=v;n2+=v*v;}
54 double mn=n1/NN,sn=sqrt(n2/NN-mn*mn);
55 printf("WIN=%-7d |delta| from one STEP: %.5f (sd %.5f) window noise sd: %.5f ratio noise/delta = %.2f\n",
56 W,md,sd,sn,sn/md);
57 }
58 free(tr);return 0;}
basal-agent/dup.c +246 -0
……@@ -0,0 +1,246 @@
1/* dup.c — does ADDING A DIMENSION cross the valley that tunnelling through it cannot?
2 *
3 * WHY THIS EXPERIMENT. stress.c (run 2, NULL) tested a local mechanism that crosses a
4 * SPATIAL valley, in a PARAMETER-SPACE valley. It failed for the reason pre-registered.
5 * Reviewing why the law "nothing local crosses" held in these models at all exposed that
6 * it contradicts the repo's own results: rung34.c has compartmentalization evolving
7 * UN-FORCED (0.1->0.94, frozen control collapsed) and evoworld.c crosses this very valley
8 * with population+selection. PAPER.md §2 says "two things cross it"; §4 then says "cannot
9 * be crossed" and "always a SUPPLIED boundary". Both cannot hold.
10 *
11 * The models could only ever buy TWO of the four resources reality spends on coordination:
12 * directed read (global statistics) ...... mom.c -- had it
13 * population + selection ................. evoworld -- had it
14 * dimension-addition (duplication/HGT) ... NOTHING IN THE REPO HAS THIS
15 * a neighbour's willingness to move ...... stress.c -- tested, null
16 * Every tensor here has been 27 fixed parameters forever. With no way to ADD a degree of
17 * freedom, a search can only tunnel THROUGH a barrier, never walk AROUND it. That is the
18 * standard way evolution crosses valleys (Ohno duplication-divergence) and it is the one
19 * mechanism the substrate structurally forbade. The wall may be a property of the
20 * substrate, not of coordination.
21 *
22 * THE TEST. Both arms end at N=3 hidden states -- IDENTICAL final capacity, so this is not
23 * a parameter-count comparison:
24 * F fixed : start at N=3 random, anneal. (= stress.c arm B, the best local arm.)
25 * D grow : start at N=1, duplicate-and-diverge 1->2->3, then refine.
26 * ONE KNOB: whether the search GREW into dimension 3 or STARTED there.
27 *
28 * D IS HANDICAPPED ON PURPOSE. It spends its first 400 sweeps below full capacity, so it
29 * refines at N=3 for 3600 sweeps vs F's 4000. Scoring-call budget is reported. If D wins it
30 * wins DESPITE less time at full capacity -- the conservative direction.
31 *
32 * Duplication = literal gene duplication: state i is copied exactly to a new index, the
33 * INCOMING mass to i is split 50/50 between the two, then both are perturbed to break the
34 * symmetry. An exact copy followed by divergence.
35 *
36 * CALIBRATED, not guessed (dscale.c): |delta| per single-entry step = 2e-5, window noise
37 * = 380x that. So T=2e-5 and delta MUST be taken on a shared window (common random
38 * numbers). poscheck.c verified at this T a TRUE-seeded model HOLDS (+0.0005) and near-true
39 * CONVERGES (+0.0025 -> +0.0001).
40 *
41 * PRIMARY ENDPOINT = box-count ladder, NOT log-loss (README: prediction barely
42 * distinguishes finite/infinite/fractal). Reported PER SEED this time -- run 2's ladder was
43 * n=1 and could not support an ordering claim.
44 * true Mess3 396/2399/8924/26394/54821 ; learn.c collapse 5/9/14/20/36 ; optimal 0.796
45 *
46 * PRE-REGISTERED MOST-LIKELY NULL: the N=2 optimum may sit in the SAME basin its N=3
47 * duplicate lands in, so growing buys a different starting point but not a different basin.
48 * If D ~= F, that is the first explanation to reach for, not a tuning problem.
49 *
50 * build: cc -O2 -std=c11 -o dup dup.c -lm && ./dup
51 */
52#include <math.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56
57#define K 3
58#define NMAX 3
59#define M 16
60#define SWEEPS 4000
61#define WIN 10000
62#define NSEED 5
63#define TEMP 2e-5 /* calibrated; see dscale.c / poscheck.c */
64#define STEP 0.06
65#define DUP1 200 /* N: 1 -> 2 */
66#define DUP2 400 /* N: 2 -> 3 */
67
68static const double TT[K][K][K]={
69 {{0.765,0.00375,0.00375},{0.0425,0.0675,0.00375},{0.0425,0.00375,0.0675}},
70 {{0.0675,0.0425,0.00375},{0.00375,0.765,0.00375},{0.00375,0.0425,0.0675}},
71 {{0.0675,0.00375,0.0425},{0.00375,0.0675,0.0425},{0.00375,0.00375,0.765}}};
72
73static unsigned long long RNG;
74static unsigned long long xs(void){RNG^=RNG<<13;RNG^=RNG>>7;RNG^=RNG<<17;return RNG;}
75static double urand(void){return (double)(xs()>>11)*(1.0/9007199254740992.0);}
76static void gen(unsigned char*o,int n){int s=0;for(int i=0;i<n;i++){double u=urand(),a=0;int e=0,nj=0,d=0;
77 for(int y=0;y<K&&!d;y++)for(int j=0;j<K&&!d;j++){a+=TT[y][s][j];if(u<a){e=y;nj=j;d=1;}}o[i]=(unsigned char)e;s=nj;}}
78
79static long SCORECALLS;
80/* variable-N edge-emitting HMM: T[sym][i][j] = P(emit sym, next j | i) */
81static double llN(const double T[K][NMAX][NMAX],int N,const unsigned char*s,long off,int n){
82 SCORECALLS++;
83 double b[NMAX],L=0; for(int i=0;i<N;i++)b[i]=1.0/N;
84 for(int t=0;t<n;t++){int x=s[off+t];double px=0,nb[NMAX];
85 for(int j=0;j<N;j++)nb[j]=0;
86 for(int i=0;i<N;i++)for(int j=0;j<N;j++){double m=b[i]*T[x][i][j];nb[j]+=m;px+=m;}
87 if(px<1e-300)px=1e-300;
88 L+=-log(px);
89 for(int j=0;j<N;j++)b[j]=nb[j]/px;}
90 return L/(double)n;}
91
92static long distinctN(const double T[K][NMAX][NMAX],int N,const unsigned char*s,int n,int G){
93 double b[NMAX]; for(int i=0;i<N;i++)b[i]=1.0/N;
94 char*seen=calloc((size_t)(G+1)*(G+1),1); long d=0;
95 for(int t=0;t<n;t++){int q0=(int)(b[0]*G+0.5),q1=(int)((N>1?b[1]:0.0)*G+0.5);
96 if(q0<0)q0=0;
97 if(q0>G)q0=G;
98 if(q1<0)q1=0;
99 if(q1>G)q1=G;
100 size_t key=(size_t)q0*(G+1)+q1; if(!seen[key]){seen[key]=1;d++;}
101 int x=s[t];double px=0,nb[NMAX];
102 for(int j=0;j<N;j++)nb[j]=0;
103 for(int i=0;i<N;i++)for(int j=0;j<N;j++){double m=b[i]*T[x][i][j];nb[j]+=m;px+=m;}
104 if(px<1e-300)px=1e-300;
105 for(int j=0;j<N;j++)b[j]=nb[j]/px;}
106 free(seen);return d;}
107
108static void rnN(double T[K][NMAX][NMAX],int N){
109 for(int i=0;i<N;i++){double z=0;
110 for(int s=0;s<K;s++)for(int j=0;j<N;j++){if(T[s][i][j]<1e-6)T[s][i][j]=1e-6;z+=T[s][i][j];}
111 for(int s=0;s<K;s++)for(int j=0;j<N;j++)T[s][i][j]/=z;}}
112
113/* gene duplication: exact copy of state `src` into index N, incoming mass split 50/50,
114 * then both diverged. Returns new N. */
115static int duplicate(double T[K][NMAX][NMAX],int N,int src){
116 int nw=N;
117 for(int s=0;s<K;s++)for(int j=0;j<N;j++) T[s][nw][j]=T[s][src][j]; /* outgoing: exact copy */
118 for(int s=0;s<K;s++)for(int i=0;i<=nw;i++){ /* incoming: split 50/50 */
119 T[s][i][src]*=0.5; T[s][i][nw]=T[s][i][src]; }
120 N=nw+1;
121 for(int s=0;s<K;s++)for(int j=0;j<N;j++){ /* diverge */
122 T[s][src][j]*=exp(0.10*(2*urand()-1)); T[s][nw][j]*=exp(0.10*(2*urand()-1)); }
123 rnN(T,N); return N;}
124
125typedef struct { double gap; long lad[5]; long calls; int Nend; } Res;
126
127/* arm: 0 = F fixed at N=3 ; 1 = D grow 1->2->3 */
128static Res run_arm(int arm,const unsigned char*tr,long ntr,const unsigned char*te,int nte,
129 unsigned long long seed,double ll_opt)
130{
131 static double T[M][K][NMAX][NMAX],Tp[K][NMAX][NMAX];
132 double ll[M]; int N[M];
133 Res R; memset(&R,0,sizeof R);
134 long c0=SCORECALLS;
135 RNG=seed;
136 for(int u=0;u<M;u++){
137 N[u] = arm? 1 : NMAX;
138 memset(T[u],0,sizeof T[u]);
139 for(int i=0;i<N[u];i++){double z=0;
140 for(int s=0;s<K;s++)for(int j=0;j<N[u];j++){T[u][s][i][j]=0.1+urand();z+=T[u][s][i][j];}
141 for(int s=0;s<K;s++)for(int j=0;j<N[u];j++)T[u][s][i][j]/=z;}
142 ll[u]=1e9;}
143
144 for(int sw=0;sw<SWEEPS;sw++){
145 long off=(long)(urand()*(double)(ntr-WIN-1));
146 if(arm==1){ /* scheduled duplication -- one knob, no stall-detector second knob */
147 if(sw==DUP1||sw==DUP2)
148 for(int u=0;u<M;u++) if(N[u]<NMAX){ int src=(int)(urand()*N[u]); if(src>=N[u])src=N[u]-1;
149 N[u]=duplicate(T[u],N[u],src); } }
150 for(int u=0;u<M;u++){
151 /* COMMON RANDOM NUMBERS: current and proposal scored on the SAME window. Run 1 of
152 * stress.c compared across windows where noise is 380x the signal -> coin flip. */
153 ll[u]=llN((const double(*)[NMAX][NMAX])T[u],N[u],tr,off,WIN);
154 memcpy(Tp,T[u],sizeof Tp);
155 int si=(int)(urand()*K),ii=(int)(urand()*N[u]),jj=(int)(urand()*N[u]);
156 if(si>=K)si=K-1;
157 if(ii>=N[u])ii=N[u]-1;
158 if(jj>=N[u])jj=N[u]-1;
159 Tp[si][ii][jj]*=exp(STEP*(2.0*urand()-1.0)); rnN(Tp,N[u]);
160 double p=llN((const double(*)[NMAX][NMAX])Tp,N[u],tr,off,WIN),d=p-ll[u];
161 if(d<=0||urand()<exp(-d/TEMP)){ memcpy(T[u],Tp,sizeof Tp); ll[u]=p; }
162 }
163 }
164 int ub=0; double bb=1e9;
165 for(int u=0;u<M;u++){ double v=llN((const double(*)[NMAX][NMAX])T[u],N[u],te,0,nte);
166 if(v<bb){bb=v;ub=u;} }
167 R.gap=bb-ll_opt; R.Nend=N[ub]; R.calls=SCORECALLS-c0;
168 int Gs[5]={30,100,300,1000,3000};
169 for(int g=0;g<5;g++) R.lad[g]=distinctN((const double(*)[NMAX][NMAX])T[ub],N[ub],te,nte,Gs[g]);
170 return R;}
171
172int main(void){
173 const long NTR=600000; const int NTE=200000;
174 unsigned char*tr=malloc(NTR),*te=malloc(NTE);
175 RNG=0x9e3779b97f4a7c15ULL;gen(tr,(int)NTR); RNG=0xd1b54a32d192ed03ULL;gen(te,NTE);
176 double ll_opt=llN((const double(*)[NMAX][NMAX])TT,K,te,0,NTE);
177
178 printf("=== dup.c — does DIMENSION-ADDITION cross where tunnelling cannot? ===\n");
179 printf(" M=%d units, %d sweeps, window %d, %d seeds, T=%.0e\n",M,SWEEPS,WIN,NSEED,(double)TEMP);
180 printf(" F fixed: N=3 throughout D grow: N=1 ->(sw %d) 2 ->(sw %d) 3\n",DUP1,DUP2);
181 printf(" optimal log-loss %.4f nats\n\n",ll_opt);
182
183 Res F[NSEED],D[NSEED];
184 for(int sd=0;sd<NSEED;sd++){
185 unsigned long long seed=0x243f6a8885a308d3ULL+0x1234567ULL*(unsigned long long)sd;
186 F[sd]=run_arm(0,tr,NTR,te,NTE,seed,ll_opt);
187 D[sd]=run_arm(1,tr,NTR,te,NTE,seed,ll_opt);
188 fprintf(stderr," seed %d: F %+.4f (G3k %6ld) D %+.4f (G3k %6ld) Nend F%d D%d\n",
189 sd,F[sd].gap,F[sd].lad[4],D[sd].gap,D[sd].lad[4],F[sd].Nend,D[sd].Nend);
190 }
191
192 /* ---------- guards ---------- */
193 int vd=0;
194 printf(" --- guard: did the test actually run? ---\n");
195 int nd=1; for(int i=0;i<NSEED;i++){ if(F[i].Nend!=3)nd=0; if(D[i].Nend!=3)nd=0; }
196 printf(" [1] both arms end at N=3 (equal capacity)? %s\n",nd?"yes":"NO");
197 if(!nd)vd=1;
198 long cf=0,cd=0; for(int i=0;i<NSEED;i++){cf+=F[i].calls;cd+=D[i].calls;}
199 printf(" [2] scoring-call budget F %ld D %ld (ratio %.3f; D handicapped if <1)\n",
200 cf,cd,(double)cd/(double)cf);
201 if(cd>cf){ printf(" FAIL: D got MORE compute than F.\n"); vd=1; }
202 { /* [3] positive control: can this harness hold an answer it is handed? */
203 double Tc[K][NMAX][NMAX],Tp2[K][NMAX][NMAX]; memcpy(Tc,TT,sizeof Tc);
204 RNG=0x51ee7c0deULL;
205 for(int sw=0;sw<SWEEPS;sw++){ long off=(long)(urand()*(double)(NTR-WIN-1));
206 double cur=llN((const double(*)[NMAX][NMAX])Tc,K,tr,off,WIN);
207 memcpy(Tp2,Tc,sizeof Tp2);
208 int si=(int)(urand()*K),ii=(int)(urand()*K),jj=(int)(urand()*K);
209 if(si>=K)si=K-1;
210 if(ii>=K)ii=K-1;
211 if(jj>=K)jj=K-1;
212 Tp2[si][ii][jj]*=exp(STEP*(2.0*urand()-1.0)); rnN(Tp2,K);
213 double p=llN((const double(*)[NMAX][NMAX])Tp2,K,tr,off,WIN),d=p-cur;
214 if(d<=0||urand()<exp(-d/TEMP)) memcpy(Tc,Tp2,sizeof Tc); }
215 double held=llN((const double(*)[NMAX][NMAX])Tc,K,te,0,NTE)-ll_opt;
216 printf(" [3] positive control: TRUE-seeded ends at gap %+.4f (must stay <+0.01)\n",held);
217 if(!(held<0.01))vd=1; }
218 if(vd){ printf("\n *** VOID — invalid experiment, NOT a null. ***\n"); return 1; }
219 printf(" guard PASSED.\n\n");
220
221 /* ---------- PRIMARY: ladder, PER SEED (run 2's was n=1) ---------- */
222 printf(" PRIMARY — distinct belief states @ G=3000, ALL %d seeds:\n",NSEED);
223 printf(" %-8s","seed"); for(int i=0;i<NSEED;i++)printf(" %8d",i); printf(" mean\n");
224 double mF=0,mD=0;
225 printf(" %-8s","F fixed"); for(int i=0;i<NSEED;i++){printf(" %8ld",F[i].lad[4]);mF+=F[i].lad[4];} printf(" %7.0f\n",mF/NSEED);
226 printf(" %-8s","D grow "); for(int i=0;i<NSEED;i++){printf(" %8ld",D[i].lad[4]);mD+=D[i].lad[4];} printf(" %7.0f\n",mD/NSEED);
227 printf(" (true Mess3 @ G=3000: 54821 ; learn.c collapse: 36)\n\n");
228 printf(" full ladder, seed 0: %8s %8s %8s %8s %8s\n","G=30","100","300","1000","3000");
229 printf(" %-8s","F fixed"); for(int g=0;g<5;g++)printf(" %8ld",F[0].lad[g]); printf("\n");
230 printf(" %-8s","D grow "); for(int g=0;g<5;g++)printf(" %8ld",D[0].lad[g]); printf("\n");
231 printf(" %-8s %8d %8d %8d %8d %8d\n","TRUE",396,2399,8924,26394,54821);
232
233 /* ---------- SECONDARY ---------- */
234 double muF=0,muD=0,sepm=0;
235 for(int i=0;i<NSEED;i++){muF+=F[i].gap;muD+=D[i].gap;}
236 muF/=NSEED;muD/=NSEED;
237 double vF=0,vD=0,vs=0;
238 for(int i=0;i<NSEED;i++){vF+=(F[i].gap-muF)*(F[i].gap-muF);vD+=(D[i].gap-muD)*(D[i].gap-muD);}
239 for(int i=0;i<NSEED;i++) sepm+=F[i].gap-D[i].gap; sepm/=NSEED;
240 for(int i=0;i<NSEED;i++){double d=(F[i].gap-D[i].gap)-sepm;vs+=d*d;}
241 printf("\n SECONDARY — log-loss gap: F %+.4f +- %.4f | D %+.4f +- %.4f\n",
242 muF,sqrt(vF/(NSEED-1)),muD,sqrt(vD/(NSEED-1)));
243 printf(" SEPARATION F - D = %+.4f +- %.4f (>0 means GROWING beat starting there)\n",
244 sepm,sqrt(vs/(NSEED-1)));
245 printf(" NOTE: log-loss SECONDARY by pre-registration. Judge on the ladder.\n");
246 free(tr);free(te);return 0;}
basal-agent/dup.err +5 -0
……@@ -0,0 +1,5 @@
1 seed 0: F +0.0082 (G3k 7083) D +0.0207 (G3k 4766) Nend F3 D3
2 seed 1: F +0.0029 (G3k 9159) D +0.0291 (G3k 2296) Nend F3 D3
3 seed 2: F +0.0066 (G3k 7851) D +0.0206 (G3k 5118) Nend F3 D3
4 seed 3: F +0.0051 (G3k 8132) D +0.0119 (G3k 5378) Nend F3 D3
5 seed 4: F +0.0034 (G3k 9643) D +0.0139 (G3k 5351) Nend F3 D3
basal-agent/dup.out +26 -0
……@@ -0,0 +1,26 @@
1=== dup.c — does DIMENSION-ADDITION cross where tunnelling cannot? ===
2 M=16 units, 4000 sweeps, window 10000, 5 seeds, T=2e-05
3 F fixed: N=3 throughout D grow: N=1 ->(sw 200) 2 ->(sw 400) 3
4 optimal log-loss 0.7960 nats
5
6 --- guard: did the test actually run? ---
7 [1] both arms end at N=3 (equal capacity)? yes
8 [2] scoring-call budget F 640080 D 640080 (ratio 1.000; D handicapped if <1)
9 [3] positive control: TRUE-seeded ends at gap +0.0001 (must stay <+0.01)
10 guard PASSED.
11
12 PRIMARY — distinct belief states @ G=3000, ALL 5 seeds:
13 seed 0 1 2 3 4 mean
14 F fixed 7083 9159 7851 8132 9643 8374
15 D grow 4766 2296 5118 5378 5351 4582
16 (true Mess3 @ G=3000: 54821 ; learn.c collapse: 36)
17
18 full ladder, seed 0: G=30 100 300 1000 3000
19 F fixed 128 531 1524 3845 7083
20 D grow 94 369 994 2494 4766
21 TRUE 396 2399 8924 26394 54821
22
23 SECONDARY — log-loss gap: F +0.0052 +- 0.0022 | D +0.0192 +- 0.0068
24 SEPARATION F - D = -0.0140 +- 0.0074 (>0 means GROWING beat starting there)
25 NOTE: log-loss SECONDARY by pre-registration. Judge on the ladder.
26EXIT=0
basal-agent/poscheck.c +66 -0
……@@ -0,0 +1,66 @@
1/* poscheck.c — the positive control stress.c was missing.
2 * Q1: can the scorer recognize the optimum (does a TRUE-seeded unit stay)?
3 * Q2: can this Metropolis reach it from NEAR-true (is the search capable at all)?
4 * If Q2 fails, stress.c's null is UNINFORMATIVE, not a null. */
5#include <math.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#define K 3
10#ifndef TEMP
11#define TEMP 0.0050
12#endif
13static const double TT[K][K][K]={
14 {{0.765,0.00375,0.00375},{0.0425,0.0675,0.00375},{0.0425,0.00375,0.0675}},
15 {{0.0675,0.0425,0.00375},{0.00375,0.765,0.00375},{0.00375,0.0425,0.0675}},
16 {{0.0675,0.00375,0.0425},{0.00375,0.0675,0.0425},{0.00375,0.00375,0.765}}};
17static unsigned long long RNG;
18static unsigned long long xs(void){RNG^=RNG<<13;RNG^=RNG>>7;RNG^=RNG<<17;return RNG;}
19static double urand(void){return (double)(xs()>>11)*(1.0/9007199254740992.0);}
20static void gen(unsigned char*o,int n){int s=0;for(int i=0;i<n;i++){double u=urand(),a=0;int e=0,nj=0,d=0;
21 for(int y=0;y<K&&!d;y++)for(int j=0;j<K&&!d;j++){a+=TT[y][s][j];if(u<a){e=y;nj=j;d=1;}}o[i]=(unsigned char)e;s=nj;}}
22static double ll_(const double T[K][K][K],const unsigned char*s,long off,int n){
23 double b[K]={1.0/3,1.0/3,1.0/3},L=0;
24 for(int t=0;t<n;t++){int x=s[off+t];double px=0,nb[K]={0,0,0};
25 for(int i=0;i<K;i++)for(int j=0;j<K;j++){double m=b[i]*T[x][i][j];nb[j]+=m;px+=m;}
26 if(px<1e-300)px=1e-300;
27 L+=-log(px);
28 for(int j=0;j<K;j++)b[j]=nb[j]/px;}
29 return L/(double)n;}
30static void rn(double T[K][K][K]){for(int i=0;i<K;i++){double z=0;
31 for(int s=0;s<K;s++)for(int j=0;j<K;j++){if(T[s][i][j]<1e-6)T[s][i][j]=1e-6;z+=T[s][i][j];}
32 for(int s=0;s<K;s++)for(int j=0;j<K;j++)T[s][i][j]/=z;}}
33int main(void){
34 const long NTR=600000;const int NTE=200000;
35 unsigned char*tr=malloc(NTR),*te=malloc(NTE);
36 RNG=0x9e3779b97f4a7c15ULL;gen(tr,(int)NTR); RNG=0xd1b54a32d192ed03ULL;gen(te,NTE);
37 double opt=ll_(TT,te,0,NTE);
38 printf("optimal (test) %.4f nats\n",opt);
39 /* Q1: TRUE-seeded, run the SAME Metropolis stress.c uses */
40 for(int trial=0;trial<2;trial++){
41 double T[K][K][K],Tp[K][K][K];
42 memcpy(T,TT,sizeof T);
43 RNG=0x243f6a8885a308d3ULL+trial;
44 if(trial==1){ /* NEAR-true: perturb every entry by up to +-25% */
45 for(int s=0;s<K;s++)for(int i=0;i<K;i++)for(int j=0;j<K;j++)T[s][i][j]*=exp(0.25*(2*urand()-1));
46 rn(T);}
47 double start=ll_((const double(*)[K][K])T,te,0,NTE);
48 long off0=0; double cur=ll_((const double(*)[K][K])T,tr,off0,10000);
49 long up=0;
50 for(int sw=0;sw<4000;sw++){
51 long off=(long)(urand()*(double)(NTR-10001));
52 cur=ll_((const double(*)[K][K])T,tr,off,10000);
53 memcpy(Tp,T,sizeof Tp);
54 int si=(int)(urand()*K),ii=(int)(urand()*K),jj=(int)(urand()*K);
55 if(si>=K)si=K-1;
56 if(ii>=K)ii=K-1;
57 if(jj>=K)jj=K-1;
58 Tp[si][ii][jj]*=exp(0.06*(2*urand()-1)); rn(Tp);
59 double p=ll_((const double(*)[K][K])Tp,tr,off,10000),d=p-cur;
60 if(d<=0||urand()<exp(-d/TEMP)){if(d>0)up++;memcpy(T,Tp,sizeof T);}
61 }
62 double end=ll_((const double(*)[K][K])T,te,0,NTE);
63 printf("%-10s start %.4f (gap %+.4f) -> end %.4f (gap %+.4f) uphill accepts %ld/4000\n",
64 trial?"NEAR-true":"TRUE-seed",start,start-opt,end,end-opt,up);
65 }
66 free(tr);free(te);return 0;}
basal-agent/run2.err +5 -0
……@@ -0,0 +1,5 @@
1 seed 0: A +0.0084 B +0.0054 B2 +0.0029 C +0.0092
2 seed 1: A +0.0056 B +0.0040 B2 +0.0072 C +0.0132
3 seed 2: A +0.0039 B +0.0032 B2 +0.0088 C +0.0050
4 seed 3: A +0.0036 B +0.0041 B2 +0.0081 C +0.0076
5 seed 4: A +0.0041 B +0.0080 B2 +0.0075 C +0.0159
basal-agent/run2.out +32 -0
……@@ -0,0 +1,32 @@
1=== stress.c — LEAKED error-sourced temperature vs Mess3 valley ===
2 M=16 units, 4000 sweeps, window 10000, 5 seeds
3 optimal log-loss 0.7960 nats | symbol marginals 0.334 0.334 0.332
4
5 --- guard: did the test actually run? ---
6 [1] field mixed? A stress~field corr 0.704 (want <0.99) B corr 1.000 (want 1.00)
7 [2] uphill moves? A 45644 B 42338 B2 47935 (all must be >0)
8 [3] C schedule span 0.0003 (must be >0)
9 [4] generator marginals sane? yes
10 [5] mean T: A 3.48e-05 vs B2 3.48e-05 (B2 must match A; that is the point)
11 [6] positive control: TRUE-seeded unit ends at gap +0.0002 (must stay <+0.01)
12 guard PASSED.
13
14 PRIMARY — distinct belief states vs resolution (seed 0 best unit):
15 arm G=30 100 300 1000 3000
16 A shared 127 488 1430 3381 5989
17 B private 180 776 2210 5085 8763
18 B2 matched 216 955 2597 5539 9187
19 C global 121 481 1395 3364 6137
20 TRUE Mess3 396 2399 8924 26394 54821
21 learn.c coll 5 9 14 20 36
22
23 SECONDARY — log-loss gap vs optimal (mean +- sd over 5 seeds):
24 A shared +0.0051 +- 0.0020 (mean T 0.0000)
25 B private +0.0049 +- 0.0019 (mean T 0.0000)
26 B2 matched +0.0069 +- 0.0023 (mean T 0.0000)
27 C global +0.0102 +- 0.0044 (mean T 0.0002)
28
29 SEPARATION B2 - A = +0.0018 +- 0.0042 nats (>0 means TARGETING beat amount)
30 NOTE: log-loss is SECONDARY by pre-registration — README records that it barely
31 distinguishes finite/infinite/fractal structure. Judge on the ladder above.
32EXIT=0
basal-agent/stress.c +324 -0
……@@ -0,0 +1,324 @@
1/* stress.c — does an error-sourced, LEAKED temperature field cross the Mess3 valley?
2 *
3 * PRE-REGISTERED in TRAJECTORY.md (2026-09-11). Read that first.
4 *
5 * THE CLAIM UNDER TEST. Part A concluded: nothing local/online/greedy/self-organized
6 * crosses the Mess3 structure-learning valley (nine mechanisms, learn.c..wakesleep2.c).
7 * Every annealing attempt used a GLOBAL SCALAR SCHEDULE: da-em.c broke onto a wrong
8 * branch or re-symmetrized at beta_c; soc.c found beta_c but online averaging washed it
9 * out; critical.c's homeostat was BLIND because washout IS max usage-entropy.
10 *
11 * Shreesha & Levin, BBRC 731 (2024) 150396, Fig 1 A1/A2 is a fitness valley crossed by a
12 * LOCAL mechanism: a stuck cell leaks stress to neighbours already at their setpoints,
13 * raising their plasticity ("temperature", their word) until they accept a temporarily
14 * worse configuration and open a channel. The temperature is a FIELD sourced from local
15 * error, and the receiving unit CANNOT TELL whose error it is.
16 *
17 * This does not share critical.c's failure mode: it is driven by distance-from-setpoint,
18 * and washout has HIGH error, so the field holds temperature UP instead of declaring
19 * victory.
20 *
21 * !!! PRE-REGISTERED MOST-LIKELY NULL — WRITTEN BEFORE THE RUN !!!
22 * Levin's valley is a SPATIAL REARRANGEMENT barrier (cells physically blocking each
23 * other). Ours is a PARAMETER-SPACE barrier (an HMM local optimum). These may not be the
24 * same kind of wall. If this nulls, that is the first explanation to reach for -- NOT a
25 * tuning problem. Recorded here and not only in a .md because the template-abundance
26 * error was diagnosed in genome.md in plain language and then rebuilt twice.
27 *
28 * ARMS (differ ONLY in where each unit's temperature comes from):
29 * A shared : diffused field, own + neighbours indistinguishable at the read
30 * B private : own excess only (Levin's own control arm)
31 * B2 matched : uncoupled, T rescaled to match A's REALIZED mean T
32 * -> postmortem lesson (a): coupling moves mean temperature AND targets
33 * it. B2 holds the mean fixed so the survivor is TARGETING, not amount.
34 * 3 of 4 prior one-knob-two-variable claims failed. This is the fix.
35 * C global : one shared annealing schedule (prior art: da-em.c, soc.c)
36 *
37 * PRIMARY ENDPOINT = distinct-belief-state count vs resolution (box-dim growth).
38 * NOT log-loss: README.md records that prediction barely distinguishes finite/infinite/
39 * fractal structure. Scoring on log-loss alone would repeat a documented error.
40 * Reference (critical.c, G=30/100/300/1000/3000):
41 * true Mess3 396 / 2399 / 8924 / 26394 / 54821
42 * learn.c collapse 5 / 9 / 14 / 20 / 36 optimal log-loss ~0.794 nats
43 *
44 * STATISTIC: two-arm question -> report the SEPARATION across seeds, never an absolute
45 * bar (postmortem lesson (b): linkage.c used an absolute bar on a control in a two-arm
46 * experiment).
47 *
48 * The setpoint is the field's own best-achieved loss -- observable, collective, and it
49 * does NOT encode the Mess3 answer. A unit sitting at the best has zero OWN stress, so
50 * only the leak can move it. That is exactly Fig 1 A1 vs A2.
51 *
52 * build: cc -O2 -Wall -std=c11 -o stress stress.c -lm && ./stress
53 */
54#include <math.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58
59#define K 3
60#define M 16 /* units in the ring */
61#define SWEEPS 4000
62#define WIN 10000 /* scoring window per sweep */
63#define NSEED 5
64
65#define T_FLOOR 5e-6 /* baseline exploration, IDENTICAL in A, B, B2 -- so B is not
66 * trivially frozen at its own setpoint.
67 * CALIBRATED (dscale.c): |delta| per single-entry STEP is 2e-5.
68 * Run 1 used 3.5e-3 = 175x too hot -> pure diffusion. See VOID note. */
69#define T_GAIN 6e-4 /* stress -> temperature */
70#define LEAK 0.60 /* fraction of a unit's deposit that leaves it (arm A) */
71#define STEP 0.06 /* proposal size */
72
73static const double TT[K][K][K] = {
74 {{0.765,0.00375,0.00375},{0.0425,0.0675,0.00375},{0.0425,0.00375,0.0675}},
75 {{0.0675,0.0425,0.00375},{0.00375,0.765,0.00375},{0.00375,0.0425,0.0675}},
76 {{0.0675,0.00375,0.0425},{0.00375,0.0675,0.0425},{0.00375,0.00375,0.765}},
77};
78
79static unsigned long long RNG;
80static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
81static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
82
83static void gen_mess3(unsigned char *out,int n){
84 int s=0;
85 for(int i=0;i<n;i++){ double u=urand(),acc=0; int es=0,nj=0,d=0;
86 for(int sym=0;sym<K&&!d;sym++)for(int j=0;j<K&&!d;j++){acc+=TT[sym][s][j];if(u<acc){es=sym;nj=j;d=1;}}
87 out[i]=(unsigned char)es; s=nj; }
88}
89
90/* mean negative log-likelihood of the exact belief filter under tensor T, over s[off..off+n) */
91static double filter_ll(const double T[K][K][K],const unsigned char *s,long off,int n){
92 double b[K]={1.0/3,1.0/3,1.0/3},ll=0;
93 for(int t=0;t<n;t++){ int x=s[off+t]; double px=0,nb[K]={0,0,0};
94 for(int i=0;i<K;i++)for(int j=0;j<K;j++){double m=b[i]*T[x][i][j];nb[j]+=m;px+=m;}
95 if(px<1e-300)px=1e-300; ll+=-log(px); for(int j=0;j<K;j++)b[j]=nb[j]/px; }
96 return ll/(double)n;
97}
98static long filter_distinct(const double T[K][K][K],const unsigned char *s,int n,int G){
99 double b[K]={1.0/3,1.0/3,1.0/3}; char *seen=calloc((size_t)(G+1)*(G+1),1); long d=0;
100 for(int t=0;t<n;t++){ int q0=(int)(b[0]*G+0.5),q1=(int)(b[1]*G+0.5);
101 if(q0<0)q0=0; if(q0>G)q0=G; if(q1<0)q1=0; if(q1>G)q1=G;
102 size_t key=(size_t)q0*(G+1)+q1; if(!seen[key]){seen[key]=1;d++;}
103 int x=s[t]; double px=0,nb[K]={0,0,0};
104 for(int i=0;i<K;i++)for(int j=0;j<K;j++){double m=b[i]*T[x][i][j];nb[j]+=m;px+=m;}
105 if(px<1e-300)px=1e-300; for(int j=0;j<K;j++)b[j]=nb[j]/px; }
106 free(seen); return d;
107}
108static void renorm(double T[K][K][K]){
109 for(int i=0;i<K;i++){ double z=0;
110 for(int s=0;s<K;s++)for(int j=0;j<K;j++){ if(T[s][i][j]<1e-6)T[s][i][j]=1e-6; z+=T[s][i][j]; }
111 for(int s=0;s<K;s++)for(int j=0;j<K;j++) T[s][i][j]/=z; }
112}
113
114typedef struct {
115 double ll_best; /* best full-test log-loss found by any unit */
116 long ladder[5]; /* box-count ladder of the best unit's tensor */
117 double meanT; /* realized mean temperature (for B2 matching) */
118 long uphill; /* accepted-worse moves (guard 2) */
119 double fieldcorr; /* cross-unit stress correlation (guard 1) */
120 double beta_span; /* arm C only (guard 3) */
121} Res;
122
123/* arm: 0=A shared 1=B private 2=B2 matched 3=C global schedule */
124static Res run_arm(int arm,const unsigned char *tr,long ntr,const unsigned char *te,int nte,
125 unsigned long long seed,double meanT_target)
126{
127 static double T[M][K][K][K], Tp[K][K][K];
128 double ll[M], stress[M], field[M], Temp[M];
129 Res R; memset(&R,0,sizeof R);
130
131 RNG=seed;
132 for(int u=0;u<M;u++){
133 for(int i=0;i<K;i++){ double z=0;
134 for(int s=0;s<K;s++)for(int j=0;j<K;j++){ T[u][s][i][j]=0.1+urand(); z+=T[u][s][i][j]; }
135 for(int s=0;s<K;s++)for(int j=0;j<K;j++) T[u][s][i][j]/=z; }
136 ll[u]=1e9; stress[u]=0; Temp[u]=T_FLOOR;
137 }
138
139 double Tsum=0; long Tn=0, corr_n=0; double corr_acc=0;
140 double beta_lo=1e9, beta_hi=-1e9;
141
142 for(int sw=0; sw<SWEEPS; sw++){
143 long off = (long)(urand()*(double)(ntr-WIN-1)); /* same window for every unit */
144
145 /* COMMON RANDOM NUMBERS (mandatory, not a refinement). dscale.c measured
146 * window-to-window noise at 380x the per-step signal, and only 114x even at a
147 * 20x larger window -- so delta MUST be taken on one shared window. Run 1
148 * compared llp(window_t) against ll[u](window_{t-1}) and was a coin flip on
149 * noise in every arm, which is why all four arms landed on the same number. */
150 for(int u=0;u<M;u++) ll[u]=filter_ll((const double(*)[K][K])T[u],tr,off,WIN);
151
152 /* ---- setpoint: the best loss anyone in the field has achieved this sweep ---- */
153 double best=1e9; for(int u=0;u<M;u++) if(ll[u]<best) best=ll[u];
154 for(int u=0;u<M;u++){ double e=ll[u]-best; stress[u]= e>0? e:0; }
155
156 /* ---- the field ---- */
157 if(arm==0){
158 /* deposit, then diffuse around the ring. The read is a SINGLE number: the unit
159 * cannot decompose field[u] into own vs neighbour. That is the anonymization. */
160 for(int u=0;u<M;u++){
161 int l=(u+M-1)%M, r=(u+1)%M;
162 field[u] = (1.0-LEAK)*stress[u] + 0.5*LEAK*(stress[l]+stress[r]);
163 }
164 /* guard 1: did the field actually mix? correlate field against own stress */
165 double ms=0,mf=0; for(int u=0;u<M;u++){ms+=stress[u];mf+=field[u];} ms/=M; mf/=M;
166 double sn=0,ss=0,ff=0;
167 for(int u=0;u<M;u++){ double a=stress[u]-ms,b=field[u]-mf; sn+=a*b; ss+=a*a; ff+=b*b; }
168 if(ss>1e-18&&ff>1e-18){ corr_acc+=sn/sqrt(ss*ff); corr_n++; }
169 } else {
170 for(int u=0;u<M;u++) field[u]=stress[u];
171 if(arm!=3){ corr_acc+=1.0; corr_n++; } /* private: field IS own stress, corr=1 */
172 }
173
174 double gsched = 0.0;
175 if(arm==3){ /* one global schedule shared by all units */
176 double frac=(double)sw/(double)SWEEPS;
177 gsched = T_FLOOR + T_GAIN*0.5*(1.0-frac);
178 if(gsched<beta_lo)beta_lo=gsched; if(gsched>beta_hi)beta_hi=gsched;
179 }
180
181 for(int u=0;u<M;u++){
182 if(arm==3) Temp[u]=gsched;
183 else if(arm==2) Temp[u]=meanT_target; /* mean-matched, untargeted */
184 else Temp[u]=T_FLOOR + T_GAIN*field[u];
185 Tsum+=Temp[u]; Tn++;
186
187 memcpy(Tp,T[u],sizeof Tp);
188 int si=(int)(urand()*K), ii=(int)(urand()*K), jj=(int)(urand()*K);
189 if(si>=K)si=K-1; if(ii>=K)ii=K-1; if(jj>=K)jj=K-1;
190 Tp[si][ii][jj] *= exp(STEP*(2.0*urand()-1.0));
191 renorm(Tp);
192
193 double llp=filter_ll((const double(*)[K][K])Tp,tr,off,WIN);
194 double d=llp-ll[u];
195 int accept;
196 if(d<=0) accept=1;
197 else { accept = (urand() < exp(-d/(Temp[u]>1e-12?Temp[u]:1e-12))); if(accept) R.uphill++; }
198 if(accept){ memcpy(T[u],Tp,sizeof Tp); ll[u]=llp; }
199 }
200 }
201
202 R.meanT = Tn? Tsum/(double)Tn : 0.0;
203 R.fieldcorr = corr_n? corr_acc/(double)corr_n : -2.0;
204 R.beta_span = (arm==3)? beta_hi-beta_lo : 0.0;
205
206 int ubest=0; double bb=1e9;
207 for(int u=0;u<M;u++){ double v=filter_ll((const double(*)[K][K])T[u],te,0,nte);
208 if(v<bb){bb=v;ubest=u;} }
209 R.ll_best=bb;
210 int Gs[5]={30,100,300,1000,3000};
211 for(int g=0;g<5;g++) R.ladder[g]=filter_distinct((const double(*)[K][K])T[ubest],te,nte,Gs[g]);
212 return R;
213}
214
215int main(void){
216 const long NTR=600000; const int NTE=200000;
217 unsigned char *tr=malloc(NTR),*te=malloc(NTE);
218 RNG=0x9e3779b97f4a7c15ULL; gen_mess3(tr,(int)NTR);
219 RNG=0xd1b54a32d192ed03ULL; gen_mess3(te,NTE);
220
221 /* guard 4: generator sane? */
222 long cnt[K]={0,0,0}; for(long i=0;i<NTR;i++) cnt[tr[i]]++;
223 int gen_ok = 1;
224 for(int s=0;s<K;s++){ double f=(double)cnt[s]/(double)NTR; if(f<0.25||f>0.42) gen_ok=0; }
225
226 double ll_opt=filter_ll(TT,te,0,NTE);
227
228 printf("=== stress.c — LEAKED error-sourced temperature vs Mess3 valley ===\n");
229 printf(" M=%d units, %d sweeps, window %d, %d seeds\n",M,SWEEPS,WIN,NSEED);
230 printf(" optimal log-loss %.4f nats | symbol marginals %.3f %.3f %.3f\n\n",
231 ll_opt,(double)cnt[0]/NTR,(double)cnt[1]/NTR,(double)cnt[2]/NTR);
232
233 const char *nm[4]={"A shared ","B private","B2 matched","C global "};
234 double gap[4][NSEED]; long lad[4][5]; double mT[4]={0,0,0,0};
235 long uph[4]={0,0,0,0}; double fcorr[4]={0,0,0,0}, bspan=0;
236 memset(lad,0,sizeof lad);
237
238 for(int sd=0; sd<NSEED; sd++){
239 unsigned long long seed=0x243f6a8885a308d3ULL + 0x1234567ULL*(unsigned long long)sd;
240 Res rA=run_arm(0,tr,NTR,te,NTE,seed,0.0);
241 Res rB=run_arm(1,tr,NTR,te,NTE,seed,0.0);
242 Res rM=run_arm(2,tr,NTR,te,NTE,seed,rA.meanT); /* matched to A's REALIZED mean T */
243 Res rC=run_arm(3,tr,NTR,te,NTE,seed,0.0);
244 Res all[4]={rA,rB,rM,rC};
245 for(int a=0;a<4;a++){
246 gap[a][sd]=all[a].ll_best-ll_opt;
247 mT[a]+=all[a].meanT; uph[a]+=all[a].uphill; fcorr[a]+=all[a].fieldcorr;
248 if(sd==0) for(int g=0;g<5;g++) lad[a][g]=all[a].ladder[g];
249 }
250 bspan+=rC.beta_span;
251 fprintf(stderr," seed %d: A %+.4f B %+.4f B2 %+.4f C %+.4f\n",
252 sd,gap[0][sd],gap[1][sd],gap[2][sd],gap[3][sd]);
253 }
254 for(int a=0;a<4;a++){ mT[a]/=NSEED; fcorr[a]/=NSEED; }
255 bspan/=NSEED;
256
257 /* ---------- guard: did the test actually run? ---------- */
258 int void_run=0;
259 printf(" --- guard: did the test actually run? ---\n");
260 printf(" [1] field mixed? A stress~field corr %.3f (want <0.99) B corr %.3f (want 1.00)\n",
261 fcorr[0],fcorr[1]);
262 if(!(fcorr[0]<0.99)) { printf(" FAIL: arm A's field did not mix.\n"); void_run=1; }
263 printf(" [2] uphill moves? A %ld B %ld B2 %ld (all must be >0)\n",uph[0],uph[1],uph[2]);
264 if(uph[0]==0||uph[1]==0||uph[2]==0){ printf(" FAIL: no annealing happened.\n"); void_run=1; }
265 printf(" [3] C schedule span %.4f (must be >0)\n",bspan);
266 if(!(bspan>0)){ printf(" FAIL: global schedule was flat.\n"); void_run=1; }
267 printf(" [4] generator marginals sane? %s\n", gen_ok?"yes":"NO");
268 if(!gen_ok) void_run=1;
269 printf(" [5] mean T: A %.2e vs B2 %.2e (B2 must match A; that is the point)\n",mT[0],mT[2]);
270 if(fabs(mT[0]-mT[2])>1e-12){ printf(" FAIL: B2 not matched.\n"); void_run=1; }
271 /* [6] POSITIVE CONTROL -- the guard run 1 did not have, and the reason run 1 was VOID.
272 * Seed a unit at the TRUE tensor and anneal it with this harness at T_FLOOR. If it
273 * cannot HOLD an answer it is handed, no arm result means anything. */
274 {
275 double Tc[K][K][K],Tp2[K][K][K]; memcpy(Tc,TT,sizeof Tc);
276 RNG=0x51ee7c0deULL; long ofc=0; double cur=filter_ll((const double(*)[K][K])Tc,tr,ofc,WIN);
277 for(int sw=0;sw<SWEEPS;sw++){
278 long off=(long)(urand()*(double)(NTR-WIN-1));
279 cur=filter_ll((const double(*)[K][K])Tc,tr,off,WIN);
280 memcpy(Tp2,Tc,sizeof Tp2);
281 int si=(int)(urand()*K),ii=(int)(urand()*K),jj=(int)(urand()*K);
282 if(si>=K)si=K-1;
283 if(ii>=K)ii=K-1;
284 if(jj>=K)jj=K-1;
285 Tp2[si][ii][jj]*=exp(STEP*(2.0*urand()-1.0)); renorm(Tp2);
286 double p=filter_ll((const double(*)[K][K])Tp2,tr,off,WIN),d=p-cur;
287 if(d<=0||urand()<exp(-d/T_FLOOR)) memcpy(Tc,Tp2,sizeof Tc);
288 }
289 double held=filter_ll((const double(*)[K][K])Tc,te,0,NTE)-ll_opt;
290 printf(" [6] positive control: TRUE-seeded unit ends at gap %+.4f (must stay <+0.01)\n",held);
291 if(!(held<0.01)){ printf(" FAIL: harness cannot hold the optimum it is handed.\n"); void_run=1; }
292 }
293 if(void_run){ printf("\n *** VOID — invalid experiment, NOT a null. ***\n"); free(tr);free(te); return 1; }
294 printf(" guard PASSED.\n\n");
295
296 /* ---------- PRIMARY endpoint: structure, not prediction ---------- */
297 printf(" PRIMARY — distinct belief states vs resolution (seed 0 best unit):\n");
298 printf(" %-11s %8s %8s %8s %8s %8s\n","arm","G=30","100","300","1000","3000");
299 for(int a=0;a<4;a++){
300 printf(" %-11s",nm[a]);
301 for(int g=0;g<5;g++) printf(" %8ld",lad[a][g]);
302 printf("\n");
303 }
304 printf(" %-11s %8d %8d %8d %8d %8d\n","TRUE Mess3",396,2399,8924,26394,54821);
305 printf(" %-11s %8d %8d %8d %8d %8d\n","learn.c coll",5,9,14,20,36);
306
307 /* ---------- SECONDARY: log-loss, reported as a SEPARATION ---------- */
308 printf("\n SECONDARY — log-loss gap vs optimal (mean +- sd over %d seeds):\n",NSEED);
309 double mu[4],sd_[4];
310 for(int a=0;a<4;a++){
311 double s=0; for(int i=0;i<NSEED;i++) s+=gap[a][i]; mu[a]=s/NSEED;
312 double v=0; for(int i=0;i<NSEED;i++){double d=gap[a][i]-mu[a]; v+=d*d;}
313 sd_[a]=NSEED>1?sqrt(v/(NSEED-1)):0.0;
314 printf(" %-11s %+.4f +- %.4f (mean T %.4f)\n",nm[a],mu[a],sd_[a],mT[a]);
315 }
316 double sep=0,sv=0;
317 for(int i=0;i<NSEED;i++) sep+=gap[2][i]-gap[0][i]; sep/=NSEED;
318 for(int i=0;i<NSEED;i++){double d=(gap[2][i]-gap[0][i])-sep; sv+=d*d;}
319 printf("\n SEPARATION B2 - A = %+.4f +- %.4f nats (>0 means TARGETING beat amount)\n",
320 sep,NSEED>1?sqrt(sv/(NSEED-1)):0.0);
321 printf(" NOTE: log-loss is SECONDARY by pre-registration — README records that it barely\n");
322 printf(" distinguishes finite/infinite/fractal structure. Judge on the ladder above.\n");
323 free(tr); free(te); return 0;
324}