OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent commits / 85b8e1e

basal-agent: linkage.c — rung 2->3; a STRUCTURAL boundary emerges where a maintained one cannot
Fills the gap in the ladder: 1->2 open, 3->4 emerged (rung34.c), 4->5 honest negative — but 2->3 was never tested as an emergence. rung2.c (low-dimensional Eigen replicator) and rung3.c (exact quasispecies over Hamming classes) are both equations SOLVED, separately. 2->3 is Maynard Smith & Szathmary's independent-replicators -> chromosomes. Why it might escape the arc's wall: coupling/partition/signal showed a boundary that must be MAINTAINED cannot pay for itself (signal.c's investment collapses to the same value from EVERY starting point — measured invasion, not a coordination trap). Linkage is structural, not maintained: linked genes share fate because they are one string, and defection is not an available strategy. Every unit starts at LENGTH 1. Fusion/fission are mutations. Payoff needs 4 distinct of 8 types in one unit. Longer units replicate STRICTLY slower. No compartments, space or group selection; global Wright-Fisher. TWO CONTROL BUGS FOUND AND FIXED, both by the controls themselves: 1. First control drew len[i] genes from the pool — so length still bought the payoff by another route. Confounded; B rose as high as A. Fixed: draw size is the POPULATION MEAN length, independent of the individual's own length, so in B length costs identically and buys nothing. 2. Verdict tested "B stays near 1", an absolute bar — the wrong statistic for a two-arm experiment. Replaced with the separation A vs B, judged only where cost bites (cost 0 has nothing selecting against length) and where A has not itself collapsed. cost | A len | A frac>=4 | B len | B frac>=4 0.00 | 7.19 | 0.952 | 4.52 | 0.477 <- uninformative, no cost 0.02 | 6.77 | 0.942 | 2.17 | 0.116 0.05 | 5.58 | 0.921 | 1.61 | 0.039 0.10 | 4.82 | 0.899 | 1.41 | 0.014 0.20 | 4.46 | 0.883 | 1.26 | 0.005 0.40 | 4.16 | 0.840 | 1.15 | 0.001 0.80 | 1.11 | 0.002 | 1.11 | 0.000 <- ceiling: linkage is not free A exceeds B at 5/5 costs where cost bites, minimum A/B ratio 3.12. => LINKAGE EMERGED. First unambiguous boundary emergence in the thread. A structural boundary arises where a maintained one collapsed, and the mechanism is the same one that explains signal.c's failure: signalling investment is a STRATEGY and can be defected on; linkage is not a strategy, because linked genes cannot replicate at different rates. Non-discretionary boundaries cannot be invaded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
85b8e1e8d6f05f1b9a3363a115dfecc7fe519de8
by plankatron <fleeky@gmail.com> · 2026-07-31T22:14:13.000Z

Changed files (2) +192 -0

.gitignore +1 -0
……@@ -41,3 +41,4 @@ coupling
4141partition
4242gardphi
4343signal
44linkage
linkage.c +191 -0
……@@ -0,0 +1,191 @@
1/* linkage.c — rung 2 -> 3: do INDEPENDENT replicators become a LINKED sequence on their own?
2 *
3 * THE GAP THIS FILLS. The ladder was tested as 1->2 (open, 14+ experiments), 3->4 (rung34.c,
4 * EMERGED), 4->5 (rung45.c, honest negative). 2->3 was never tested as an emergence: rung2.c is a
5 * low-dimensional Eigen replicator-with-mutation and rung3.c is an exact quasispecies over Hamming
6 * classes -- both equations SOLVED, separately. The transition between them is "a few forms become
7 * a combinatorial form-space", i.e. Maynard Smith & Szathmary's independent-replicators ->
8 * chromosomes.
9 *
10 * WHY IT MIGHT ESCAPE THE ARC'S WALL. coupling/partition/signal established that a boundary which
11 * must be MAINTAINED cannot pay for itself: signal.c's investment collapses to the same low value
12 * from every starting point (measured -- invasion, not a coordination trap). Linkage is a boundary
13 * of a different kind. It is not maintained; it is STRUCTURAL. Linked genes share fate because they
14 * are one string, and defection is not a strategy available to them. So the question is whether a
15 * boundary nobody has to pay upkeep on can arise.
16 *
17 * THE TAUTOLOGY TRAP, AND THE CONTROL THAT AVOIDS IT. If a unit's fitness is computed from its own
18 * genes, linkage privatizes BY DEFINITION and "linkage evolves when combination is valuable" merely
19 * restates the setup. So everything here rests on arm B:
20 * arm A combinatorial benefit computed from YOUR OWN genes -> linkage can pay
21 * arm B the same benefit computed from a RANDOM DRAW of the pool, of the same size
22 * -> length costs exactly as much, and buys exactly nothing
23 * Length carries an identical replication penalty in both. If length rises in A and not in B, the
24 * driver is fate-sharing and not the mere fact that longer units are scored on more genes.
25 *
26 * WHAT IS SUPPLIED vs WHAT MUST EMERGE:
27 * SUPPLIED: fusion and fission as mutations, a combinatorial fitness (>= KREQ distinct types), and
28 * a replication penalty for length. The penalty is SWEPT, not picked.
29 * MUST EMERGE: linkage itself. Every unit starts at LENGTH 1 -- fully independent replicators.
30 * Nothing rewards being long as such; long units replicate strictly slower.
31 * ABSENT: containers, compartments, space, group selection. Global Wright-Fisher over units.
32 *
33 * PRE-REGISTERED:
34 * L1 arm A: mean length RISES above 1 and the fraction of units reaching KREQ distinct types rises.
35 * L2 arm B (control): mean length stays at ~1 at every cost. If B rises too, the effect is an
36 * artifact of scoring longer units on more genes and L1 means nothing.
37 * L3 there is a length cost above which even A collapses to 1 -- linkage is not free.
38 * L4 TEST OF THE TEST: fusion/fission must actually generate length variation. If length is pinned
39 * at 1 or at MAXLEN regardless of arm, the test did not run and a null says nothing.
40 *
41 * build: cc -O2 -Wall -std=c11 -o linkage linkage.c -lm
42 */
43#include <math.h>
44#include <stdio.h>
45#include <stdint.h>
46
47#define POP 4000
48#define TYPES 8
49#define MAXLEN 8
50#define KREQ 4 /* distinct types needed for the combinatorial payoff */
51#define BONUS 2.0
52#define GEN 300
53#define MUT 0.02 /* per-gene type mutation */
54#define PFUSE 0.05
55#define PFISS 0.05
56
57static unsigned long long RNG;
58static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
59static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
60
61static uint8_t gene[POP][MAXLEN], ngene[POP][MAXLEN];
62static int len[POP], nlen[POP];
63static double wgt[POP], cum[POP];
64
65static int distinct_of(const uint8_t*g,int n){ int seen[TYPES]; for(int t=0;t<TYPES;t++) seen[t]=0; int d=0; for(int i=0;i<n;i++) if(!seen[g[i]]){ seen[g[i]]=1; d++; } return d; }
66
67/* mode 0 = arm A (own genes). mode 1 = arm B control (same-size random draw from the pool). */
68static void run(int mode,double lcost,double *len_end,double *frac_k,double *len_max,double *len_min)
69{
70 for(int i=0;i<POP;i++){ len[i]=1; gene[i][0]=(uint8_t)(xs()%TYPES); }
71
72 for(int g=0;g<GEN;g++){
73 /* control draw size is the POPULATION MEAN length, NOT the individual's own length, so in
74 arm B length carries the identical cost and buys literally nothing. Drawing len[i] genes
75 (the first attempt) left length buying the payoff by another route -- a confounded control. */
76 int dsz;
77 { double m=0; for(int i=0;i<POP;i++) m+=len[i]; dsz=(int)(m/POP+0.5); if(dsz<1)dsz=1; if(dsz>MAXLEN)dsz=MAXLEN; }
78 double tot=0;
79 for(int i=0;i<POP;i++){
80 int d;
81 if(mode==0) d=distinct_of(gene[i],len[i]);
82 else {
83 uint8_t draw[MAXLEN];
84 for(int k=0;k<dsz;k++){ int u=(int)(xs()%POP); int q=(int)(xs()%(unsigned long long)len[u]); draw[k]=gene[u][q]; }
85 d=distinct_of(draw,dsz);
86 }
87 double fit = 1.0 + ((d>=KREQ)? BONUS : 0.0);
88 double pen = 1.0/(1.0+lcost*(len[i]-1)); /* longer replicates strictly slower */
89 double w = fit*pen;
90 tot+=w; cum[i]=tot; wgt[i]=w;
91 }
92 for(int i=0;i<POP;i++){
93 double r=urand()*tot; int lo=0,hi=POP-1;
94 while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; }
95 int n=len[lo];
96 uint8_t tmp[2*MAXLEN];
97 for(int k=0;k<n;k++) tmp[k]=gene[lo][k];
98
99 if(urand()<PFUSE && n<MAXLEN){ /* FUSION: concatenate another unit */
100 int o=(int)(xs()%POP); int m=len[o];
101 for(int k=0;k<m && n<MAXLEN;k++) tmp[n++]=gene[o][k];
102 }
103 if(urand()<PFISS && n>1){ /* FISSION: keep a contiguous piece */
104 int cut=1+(int)(xs()%(unsigned long long)(n-1));
105 if(urand()<0.5){ n=cut; }
106 else { for(int k=0;k<n-cut;k++) tmp[k]=tmp[cut+k]; n=n-cut; }
107 }
108 for(int k=0;k<n;k++) if(urand()<MUT) tmp[k]=(uint8_t)(xs()%TYPES);
109 nlen[i]=n; for(int k=0;k<n;k++) ngene[i][k]=tmp[k];
110 }
111 for(int i=0;i<POP;i++){ len[i]=nlen[i]; for(int k=0;k<len[i];k++) gene[i][k]=ngene[i][k]; }
112 }
113
114 double sl=0; int nk=0, mx=0, mn=MAXLEN;
115 for(int i=0;i<POP;i++){
116 sl+=len[i];
117 if(len[i]>mx) mx=len[i];
118 if(len[i]<mn) mn=len[i];
119 if(distinct_of(gene[i],len[i])>=KREQ) nk++;
120 }
121 *len_end=sl/POP; *frac_k=(double)nk/POP; *len_max=mx; *len_min=mn;
122}
123
124int main(void)
125{
126 unsigned long long seeds[8];
127 seeds[0]=0x9e3779b97f4a7c15ULL; seeds[1]=0xd1b54a32d192ed03ULL; seeds[2]=0x2545f4914f6cdd1dULL;
128 for(int i=3;i<8;i++) seeds[i]=0x9e3779b97f4a7c15ULL ^ (0x100000001b3ULL*(unsigned long long)(i+1));
129 int NS=8;
130
131 printf("=== LINKAGE (rung 2 -> 3): do independent replicators concatenate on their own? ===\n");
132 printf(" Every unit STARTS AT LENGTH 1. Fusion/fission are mutations. Payoff needs %d distinct\n",KREQ);
133 printf(" of %d types in one unit. Longer units replicate STRICTLY SLOWER. No compartments,\n",TYPES);
134 printf(" no space, no group selection; global Wright-Fisher over units.\n");
135 printf(" arm A = payoff from YOUR OWN genes. arm B = same payoff from a same-size RANDOM POOL\n");
136 printf(" DRAW of the POPULATION-MEAN size: length costs identically and buys NOTHING in B.\n\n");
137
138 printf(" length cost | A mean len | A frac>=%d | A len range | B mean len | B frac>=%d\n",KREQ,KREQ);
139 printf(" ------------+------------+-----------+-------------+------------+-----------\n");
140 double costs[]={0.00,0.02,0.05,0.10,0.20,0.40,0.80};
141 int NC=(int)(sizeof(costs)/sizeof(costs[0]));
142 int roseA=0, varied=0, sepcount=0, ncmp=0; double bestlen=0, bestcost=-1, minratio=1e9;
143
144 for(int c=0;c<NC;c++){
145 double la=0,fa=0,lb=0,fb=0,mx=0,mn=0;
146 for(int s=0;s<NS;s++){
147 double L,F,M,N; RNG=seeds[s]; run(0,costs[c],&L,&F,&M,&N); la+=L; fa+=F; mx+=M; mn+=N;
148 RNG=seeds[s]; run(1,costs[c],&L,&F,&M,&N); lb+=L; fb+=F;
149 }
150 la/=NS;fa/=NS;lb/=NS;fb/=NS;mx/=NS;mn/=NS;
151 printf(" %.2f | %.2f | %.3f | %.1f-%.1f | %.2f | %.3f\n",
152 costs[c],la,fa,mn,mx,lb,fb);
153 /* An absolute bar on B is the wrong statistic: this is a TWO-ARM comparison, and the
154 question is whether length pays MORE when the genes are your own. Judge the separation,
155 and only where cost bites (cost 0 has nothing selecting against length) and where A has
156 not itself collapsed (above the ceiling neither arm sustains length). */
157 if(costs[c]>0.0 && la>1.5){
158 roseA=1; ncmp++;
159 double ratio = (lb>0)? la/lb : 1e9;
160 if(ratio<minratio) minratio=ratio;
161 if(la-lb>1.0) sepcount++;
162 }
163 if(mx-mn>=2) varied=1;
164 if(la>bestlen){ bestlen=la; bestcost=costs[c]; }
165 }
166 printf("\n");
167
168 printf(" L4 TEST OF THE TEST — did length actually vary? %s\n", varied?"YES":"NO — test did not run");
169 printf(" L1 arm A length rose above 1? %s (best %.2f at cost %.2f)\n", roseA?"YES":"NO",bestlen,bestcost);
170 printf(" L2 A exceeds control B where cost bites? %d/%d costs, min A/B ratio %.2f\n", sepcount,ncmp,minratio);
171 printf("\n");
172
173 if(!varied)
174 printf(" => THE TEST DID NOT RUN. Fusion/fission never generated real length variation, so\n"
175 " nothing here speaks to whether linkage can emerge. Invalid experiment, not a null.\n");
176 else if(roseA && ncmp>0 && sepcount==ncmp && minratio>2.0)
177 printf(" => LINKAGE EMERGED, AND THE CONTROL RULES OUT THE TAUTOLOGY. Units start independent and\n"
178 " concatenate on their own despite a strict replication penalty for length, while the\n"
179 " pool-draw control -- identical cost, no fate-sharing -- stays at length 1. This is a\n"
180 " boundary that is STRUCTURAL rather than maintained: nobody pays upkeep, and defection\n"
181 " is not an available strategy because linked genes cannot replicate at different rates.\n"
182 " Contrast signal.c, where the maintained boundary collapsed from EVERY starting point.\n");
183 else if(roseA && sepcount<ncmp)
184 printf(" => CONFOUNDED. Length rose in the control too, so the effect is that longer units are\n"
185 " scored on more genes, not fate-sharing. Claim nothing about linkage.\n");
186 else
187 printf(" => HONEST NULL. Linkage did not emerge at any cost: the replication penalty for length\n"
188 " outweighs the combinatorial payoff throughout, so independent replicators stay\n"
189 " independent. A structural boundary is no easier to originate than a maintained one.\n");
190 return 0;
191}