| … | … | @@ -57,3 +57,8 @@ ladder35 |
| 57 | 57 | chain12 |
| 58 | 58 | threecarrier |
| 59 | 59 | fluctuate |
| 60 | stress | |
| 61 | poscheck | |
| 62 | poscheck_t | |
| 63 | dscale | |
| 64 | dup |
| … | … | @@ -0,0 +1,412 @@ |
| 1 | # Trajectory — 2026-09-11 | |
| 2 | ||
| 3 | Written 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 | |
| 6 | explicitly *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 | |
| 13 | function, not template count** as next step #1: cheapest, highest value, design already | |
| 14 | correct, only the metric wrong (reading raised working fraction 0.294 → 0.478 and function | |
| 15 | 1.27 → 1.47). Nothing below displaces it. A new idea must not push out a nearly-finished | |
| 16 | one — 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 | ||
| 24 | Our law (`PAPER.md` §4): *a fitness valley cannot be crossed by search; only by a directed | |
| 25 | structural move plus non-greedy drift* — and Part A's wall: **nothing local / online / | |
| 26 | greedy / self-organized crosses it** (nine mechanisms, `learn.c` through `wakesleep2.c`). | |
| 27 | ||
| 28 | Shreesha & Levin 2024 (BBRC 731:150396), Fig. 1 A1/A2, is a fitness valley crossed by a | |
| 29 | local 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 | ||
| 36 | Why this is not one of our nine: every annealing mechanism we tried used a **global scalar | |
| 37 | schedule**. `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 | ||
| 41 | Levin's is a **temperature field sourced from local error and leaked with its provenance | |
| 42 | destroyed**. Never tried here. And it does not share `critical.c`'s failure mode: it is | |
| 43 | driven by distance-from-setpoint, and washout has *high* error, so the field holds | |
| 44 | temperature up rather than declaring victory. | |
| 45 | ||
| 46 | → **`stress.c`**, below. | |
| 47 | ||
| 48 | ### 2. Anonymity, not messaging, is the collective mechanism | |
| 49 | ||
| 50 | The 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 | ||
| 55 | Addressed messages give you a **society**. Destroyed provenance gives you an **individual** — | |
| 56 | a cell cannot locate where its own self ends. Cooperation with **zero altruism**: every cell | |
| 57 | only ever minimizes its own stress. | |
| 58 | ||
| 59 | Our law says individuality must be **supplied** (*"an isolated collective cannot bootstrap | |
| 60 | its own individuality"*), so `belief_field_agent.c` supplies it. Anonymized error-leak is the | |
| 61 | first concrete candidate mechanism for *what the supplied thing could be*, rather than "draw | |
| 62 | a box". | |
| 63 | ||
| 64 | ### 3. `deferred vs instantaneous selection` has independent cross-domain support | |
| 65 | ||
| 66 | Our fifth 1→2 constraint, found on the last night: **memory cannot pay under instantaneous | |
| 67 | selection** — *"anything scored on current state cannot afford storage."* | |
| 68 | ||
| 69 | The stress paper's flagged negative result: **anatomical goal states could not be inferred | |
| 70 | from observation of stress states**, *"revealing the limitations of knowledge of goals by an | |
| 71 | extern observer outside the system itself."* | |
| 72 | ||
| 73 | Same claim, opposite direction: **the instantaneous error signal underdetermines the deferred | |
| 74 | goal.** Two groups, different substrates. By this repo's own standard — `chain12` earned its | |
| 75 | weight by being the one *replicated* effect — this is the strongest thing in the folder and it | |
| 76 | is currently a bullet under "Research ideas". | |
| 77 | ||
| 78 | ### 4. A metric we are missing, and already measure the shadow of | |
| 79 | ||
| 80 | The stress paper measures **radius of influence** (persists to stage ~85 with sharing, ~10 | |
| 81 | without) and names it the **cognitive light cone** — the spatio-temporal radius of goal states | |
| 82 | a 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. | |
| 88 | That is a result waiting for an axis. | |
| 89 | ||
| 90 | ### 5. Their methodology is ours, with a number attached | |
| 91 | ||
| 92 | Levin §5.5: *"in systems where every component is known, there is nowhere to hide... quantify | |
| 93 | the effort put in and the competencies that emerge; the delta between them."* | |
| 94 | ||
| 95 | Our razor: *"never encode the answer in the update rule — did I encode the outcome, or did it | |
| 96 | arise?"* Same discipline; ours is **binary**, theirs is **graded**. Adopting the delta framing | |
| 97 | turns ~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 | |
| 133 | field cross the Mess3 structure-learning valley, where a global schedule (`da-em.c`) and a | |
| 134 | usage-entropy homeostat (`critical.c`) did not? | |
| 135 | ||
| 136 | **Arms.** M units, each an independent candidate tensor over the *same* stream, Metropolis | |
| 137 | proposals, 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 | |
| 147 | instances failed. Coupling raises mean temperature *and* targets it. B2 holds the mean fixed | |
| 148 | so the surviving difference is **targeting**, not amount. Both A and B get the same `T_FLOOR` | |
| 149 | so B is not trivially frozen. | |
| 150 | ||
| 151 | **Primary endpoint — and this is the trap.** `README.md` records that **prediction (log-loss) | |
| 152 | barely distinguishes finite / infinite / fractal structure**. Scoring on log-loss alone would | |
| 153 | repeat a documented error. Primary endpoint is therefore the **distinct-belief-state count vs | |
| 154 | resolution** (box-dim growth); log-loss gap is **secondary**. | |
| 155 | Reference 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**. | |
| 157 | Optimal log-loss ≈ **0.794 nats**. | |
| 158 | ||
| 159 | **Statistic.** Two-arm question → report the **separation** A−B across seeds with its spread, | |
| 160 | never an absolute bar (postmortem lesson (b): `linkage.c` used an absolute bar on a control in | |
| 161 | a two-arm experiment). | |
| 162 | ||
| 163 | **"Did the test actually run?" guard** — the thing that caught four invalid experiments: | |
| 164 | 1. arm A's field must actually diffuse and arm B's must not (cross-unit stress correlation) | |
| 165 | 2. uphill acceptances must be > 0 in A, B, B2 — otherwise no annealing happened → **VOID** | |
| 166 | 3. arm C's schedule must actually span its β range | |
| 167 | 4. 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 | |
| 170 | rearrangement** barrier — cells physically blocking each other. Ours is a **parameter-space** | |
| 171 | barrier — an HMM local optimum. These may not be the same kind of wall, and that is the | |
| 172 | likeliest reason for a null. Recorded here, and in the file header, because *"a written | |
| 173 | diagnosis 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, | |
| 177 | consistently across seeds. Null: A ≈ B2. Either is a result — a hit revises the structural | |
| 178 | claim that *inference is local, learning is not*; a null hardens it against the strongest | |
| 179 | counterexample 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 | |
| 186 | pre-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 | ||
| 198 | Guards [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 | |
| 201 | every 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 | ``` | |
| 208 | TRUE-seed start 0.7960 (gap +0.0000) -> end 0.8055 (gap +0.0096) uphill 1998/4000 | |
| 209 | NEAR-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 | |
| 213 | arm result can mean anything under that. | |
| 214 | ||
| 215 | This is the `byproduct.c` failed-positive-control and `fidfloor.c` broken-baseline class, | |
| 216 | repeated. Guard [2] ("did annealing happen?") is not the same question as **"can this harness | |
| 217 | succeed 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 | ||
| 227 | Two independent defects, both fatal, both invisible without this measurement: | |
| 228 | ||
| 229 | 1. **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. | |
| 232 | 2. **Δ 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 | |
| 238 | it. Any sampled-window Metropolis/annealing search over this HMM needs shared-window Δ and | |
| 239 | T ≈ 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 | ||
| 252 | At the calibrated temperature the harness both **holds** the optimum and **converges** to it | |
| 253 | from 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 | |
| 256 | on 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 | ||
| 265 | Corollary: **when every arm including the control agrees, suspect the harness, not the | |
| 266 | hypothesis.** The uniform +0.25 across four arms was visible in the first output and is a | |
| 267 | stronger 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 | ||
| 275 | All six guards passed, positive control [6] at **+0.0002**. Harness capability established | |
| 276 | before 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 | |
| 303 | is the **worst of the three local arms**. Anonymized error-leak produced no advantage over | |
| 304 | each unit annealing on its own error, and A is indistinguishable from C, the global schedule | |
| 305 | it was supposed to beat. | |
| 306 | ||
| 307 | The **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 | |
| 309 | must literally move aside. Ours is a *parameter-space* barrier. Leaking a scalar into a | |
| 310 | parameter search has no "get out of the way" move to buy. This was written in the file header | |
| 311 | before 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). | |
| 316 | The valley was not crossed by *any* temperature-sourcing strategy. The wall documented in | |
| 317 | Part A is undisturbed. | |
| 318 | ||
| 319 | **2. The ladder and log-loss disagree on ordering** — B2 is *best* on the ladder and *worst* | |
| 320 | of the local arms on log-loss. That is an independent confirmation of the README's finding | |
| 321 | that **prediction barely distinguishes structure**, arriving here by accident. Had this been | |
| 322 | scored 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 | |
| 327 | secondary endpoint has 5 seeds. So the B2 > B > A ordering **cannot be claimed** — it is one | |
| 328 | draw. What survives n=1 is the robust part: *no arm is near true*, which holds across all four | |
| 329 | arms and agrees with the log-loss. | |
| 330 | ||
| 331 | Next: compute the ladder per seed and report its spread. Until then the ordering is an | |
| 332 | observation, not a result. | |
| 333 | ||
| 334 | --- | |
| 335 | ||
| 336 | # Record — `dup.c`: **NEGATIVE** (valid). Growing is *worse* than starting there. | |
| 337 | ||
| 338 | Guards 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, | |
| 351 | separation **F−D = −0.0140 ± 0.0074**, negative on every seed. Both endpoints agree this | |
| 352 | time (they disagreed in run 2), which strengthens it. | |
| 353 | ||
| 354 | ## This is not the null that was pre-registered | |
| 355 | ||
| 356 | Pre-registered: *D ≈ F, because the N=2 optimum lands in the same basin its duplicate | |
| 357 | occupies.* Observed: D is **reliably and substantially worse**. The pre-registered | |
| 358 | explanation 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 | ||
| 364 | An exact copy leaves two states identical. Divergence from that point requires coordinated | |
| 365 | change across both copies, with single-entry proposals at T=2e-5 — the same class of barrier | |
| 366 | the whole arc is about, now manufactured one level down by the very move meant to avoid it. | |
| 367 | Random init at N=3 starts *already asymmetric* and pays no such cost. Worse, the N=2 solution | |
| 368 | seeding the duplication is only 200 sweeps old and has already committed to a 2-state | |
| 369 | explanation of a 3-state process; D inherits that commitment. | |
| 370 | ||
| 371 | So dimension-addition did not let the search walk *around* the barrier. It walked into a new | |
| 372 | one. | |
| 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 | |
| 377 | 27-fixed-parameters, not of coordination. Given a way to add a degree of freedom, the search | |
| 378 | did worse. The wall held. | |
| 379 | ||
| 380 | **Does not establish the law either.** This tested *one cheap implementation* — | |
| 381 | scheduled duplication, from N=1, single-entry proposals, and critically **no selection | |
| 382 | between units**. The M=16 units are independent restarts reported as a max, which is not | |
| 383 | population+selection. So this experiment added the one resource the substrate lacked while | |
| 384 | still missing the one resource that is *known to work in this repo*: `evoworld.c` crosses this | |
| 385 | exact valley with population+selection. | |
| 386 | ||
| 387 | **That is the design flaw, and it names the next experiment.** In biology duplication without | |
| 388 | differential survival is just noise injection — duplicates are culled or fixed by selection, | |
| 389 | not annealed. Dimension-addition and selection are plausibly a *conjunction*, and this run | |
| 390 | supplied one without the other. | |
| 391 | ||
| 392 | → Next: duplication **inside** `evoworld.c`'s population+selection loop. Arms: selection | |
| 393 | alone (reproduces evoworld), duplication alone (this run), both. If the conjunction crosses | |
| 394 | where neither alone does, that is a real result and it matches how the mechanism works in | |
| 395 | reality. | |
| 396 | ||
| 397 | ## Standing correction to the law (from the review that prompted this) | |
| 398 | ||
| 399 | PAPER.md §4 — *"cannot be crossed by search... its resolution is always the same: a supplied | |
| 400 | boundary"* — **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 | ||
| 407 | Defensible restatement: *a **local, online, greedy, single-lineage, fixed-dimension** search | |
| 408 | cannot cross a coordination valley.* That is what was measured. The general claim about | |
| 409 | collectives and individuality is falsified by ordinary biology — multicellularity arose | |
| 410 | independently ~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) | |
| 412 | not a possibility question. |
| … | … | @@ -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 | |
| 10 | static 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}}}; | |
| 14 | static unsigned long long RNG; | |
| 15 | static unsigned long long xs(void){RNG^=RNG<<13;RNG^=RNG>>7;RNG^=RNG<<17;return RNG;} | |
| 16 | static double urand(void){return (double)(xs()>>11)*(1.0/9007199254740992.0);} | |
| 17 | static 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;}} | |
| 19 | static 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;} | |
| 27 | static 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;}} | |
| 30 | int 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;} |
| … | … | @@ -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 | ||
| 68 | static 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 | ||
| 73 | static unsigned long long RNG; | |
| 74 | static unsigned long long xs(void){RNG^=RNG<<13;RNG^=RNG>>7;RNG^=RNG<<17;return RNG;} | |
| 75 | static double urand(void){return (double)(xs()>>11)*(1.0/9007199254740992.0);} | |
| 76 | static 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 | ||
| 79 | static long SCORECALLS; | |
| 80 | /* variable-N edge-emitting HMM: T[sym][i][j] = P(emit sym, next j | i) */ | |
| 81 | static 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 | ||
| 92 | static 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 | ||
| 108 | static 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. */ | |
| 115 | static 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 | ||
| 125 | typedef 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 */ | |
| 128 | static 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 | ||
| 172 | int 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;} |
| … | … | @@ -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 |
| … | … | @@ -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. | |
| 26 | EXIT=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 | |
| 13 | static 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}}}; | |
| 17 | static unsigned long long RNG; | |
| 18 | static unsigned long long xs(void){RNG^=RNG<<13;RNG^=RNG>>7;RNG^=RNG<<17;return RNG;} | |
| 19 | static double urand(void){return (double)(xs()>>11)*(1.0/9007199254740992.0);} | |
| 20 | static 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;}} | |
| 22 | static 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;} | |
| 30 | static 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;}} | |
| 33 | int 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;} |
| … | … | @@ -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 |
| … | … | @@ -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. | |
| 32 | EXIT=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 | ||
| 73 | static 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 | ||
| 79 | static unsigned long long RNG; | |
| 80 | static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; } | |
| 81 | static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); } | |
| 82 | ||
| 83 | static 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) */ | |
| 91 | static 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 | } | |
| 98 | static 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 | } | |
| 108 | static 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 | ||
| 114 | typedef 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 */ | |
| 124 | static 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 | ||
| 215 | int 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 | } |