| … | … | @@ -0,0 +1,168 @@ |
| 1 | /* chain12.c — THE QUESTION: does rung 1 PRODUCE rung 2? |
| 2 | * |
| 3 | * SYNTHESIS's oldest admission, unchanged since the arc began: "No rung ever emerged from the rung |
| 4 | * below. Each was a separate model, and the ladder was a story told across disconnected pieces." |
| 5 | * rafcomp.c got two rungs CO-PRESENT by hand-translating one into the other's terms. The substrate |
| 6 | * milestones removed the structural reason that was necessary — all five rungs now live in one type. |
| 7 | * So for the first time the question is askable in one model rather than narrated across two. |
| 8 | * |
| 9 | * THE TEST. Run a random catalytic network in the counts substrate at a density where a RAF exists |
| 10 | * (rung 1 — a self-sustaining set, which rung1.c showed self-organises). Then ask whether |
| 11 | * SELF-TEMPLATING species are preferentially maintained: a species X is self-templating when some |
| 12 | * reaction produces X and X catalyses that same reaction. That is exactly rung 2 — a form that |
| 13 | * templates copies of itself — expressed in the same type, with no separate model. |
| 14 | * |
| 15 | * If self-templaters end up ENRICHED relative to their share of the network, the autocatalytic set |
| 16 | * is preferentially sustaining the seeds of heredity: rung 1 produces rung 2. |
| 17 | * If they end at their chance share, rung 1 sustains itself and nothing more, and the ladder's |
| 18 | * oldest admission stands. |
| 19 | * |
| 20 | * THE GUARD, and it is what makes a positive believable. "Enriched relative to chance" needs the |
| 21 | * right null, and the wrong one is easy: self-templating reactions are catalysed BY DEFINITION, so |
| 22 | * they are more likely to fire than an average reaction whether or not anything is being selected. |
| 23 | * The control therefore uses a SCRAMBLED network with the identical number of self-templating |
| 24 | * reactions and the identical catalysis density, but with the self-templating property assigned to |
| 25 | * RANDOM species instead of the ones that carry it. Same firing advantage, no relationship between |
| 26 | * being self-templating and being sustained. That is the four-check tally applied at design time: |
| 27 | * the knob must move one variable. |
| 28 | * |
| 29 | * A null here is the expected outcome and a real result — it would say the substrate makes the |
| 30 | * question askable without making the answer yes. |
| 31 | * |
| 32 | * build: cc -O2 -Wall -std=c11 -o chain12 chain12.c -lm |
| 33 | */ |
| 34 | #include <math.h> |
| 35 | #include <stdio.h> |
| 36 | #include <string.h> |
| 37 | |
| 38 | #define NSPEC 40 |
| 39 | #define NFOOD 6 |
| 40 | #define NRXN 160 |
| 41 | #define TOTAL 3000 |
| 42 | #define ROUNDS 40000 |
| 43 | #define PCAT 0.004 |
| 44 | |
| 45 | static unsigned long long RNG; |
| 46 | static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; } |
| 47 | static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); } |
| 48 | static int rint_(int n){ return (int)(xs()%(unsigned)n); } |
| 49 | |
| 50 | typedef struct { int a,b,prod; unsigned char cat[NSPEC]; } Rxn; |
| 51 | static Rxn R[NRXN]; |
| 52 | static unsigned char selftem[NSPEC]; /* species X: some reaction makes X and X catalyses it */ |
| 53 | |
| 54 | /* scramble=0: self-templating is whatever the network actually has. |
| 55 | scramble=1: the SAME COUNT of self-templating reactions, but the property is reassigned to random |
| 56 | species — identical firing advantage, no link between being self-templating and being sustained. */ |
| 57 | static void net_random(int scramble){ |
| 58 | memset(selftem,0,sizeof selftem); |
| 59 | for(int j=0;j<NRXN;j++){ |
| 60 | R[j].a=rint_(NSPEC); R[j].b=rint_(NSPEC); R[j].prod=NFOOD+rint_(NSPEC-NFOOD); |
| 61 | memset(R[j].cat,0,sizeof R[j].cat); |
| 62 | for(int m=0;m<NSPEC;m++) if(urand()<PCAT) R[j].cat[m]=1; |
| 63 | } |
| 64 | /* find the genuine self-templaters */ |
| 65 | int hits[NRXN], nh=0; |
| 66 | for(int j=0;j<NRXN;j++) if(R[j].cat[R[j].prod]) hits[nh++]=j; |
| 67 | if(!scramble){ |
| 68 | for(int i=0;i<nh;i++) selftem[R[hits[i]].prod]=1; |
| 69 | } else { |
| 70 | /* keep the same number of self-templating reactions, but point the property elsewhere: |
| 71 | the reaction still catalyses itself (same firing advantage) while the SPECIES we count as |
| 72 | self-templating is drawn at random. */ |
| 73 | for(int i=0;i<nh;i++) selftem[NFOOD+rint_(NSPEC-NFOOD)]=1; |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | static int n[NSPEC]; |
| 78 | static void seed(void){ memset(n,0,sizeof n); for(int i=0;i<TOTAL;i++) n[rint_(NSPEC)]++; } |
| 79 | |
| 80 | static void react(void){ |
| 81 | for(int t=0;t<ROUNDS;t++){ |
| 82 | int tot=0; for(int m=0;m<NSPEC;m++) tot+=n[m]; |
| 83 | if(tot<2) return; |
| 84 | int pa=rint_(tot),pb=rint_(tot),a=-1,b=-1,acc=0; |
| 85 | for(int m=0;m<NSPEC;m++){ acc+=n[m]; if(a<0&&pa<acc)a=m; if(b<0&&pb<acc)b=m; } |
| 86 | if(a<0||b<0) continue; |
| 87 | int j0=rint_(NRXN); |
| 88 | for(int d=0;d<NRXN;d++){ |
| 89 | int j=(j0+d)%NRXN; |
| 90 | if(!((R[j].a==a&&R[j].b==b)||(R[j].a==b&&R[j].b==a))) continue; |
| 91 | int cz=0; for(int m=0;m<NSPEC;m++) if(R[j].cat[m]&&n[m]>0){cz=1;break;} |
| 92 | if(!cz) break; |
| 93 | int ev=rint_(tot),e=-1; acc=0; |
| 94 | for(int m=0;m<NSPEC;m++){ acc+=n[m]; if(ev<acc){ e=m; break; } } |
| 95 | if(e>=NFOOD && n[e]>0) n[e]--; |
| 96 | n[R[j].prod]++; |
| 97 | break; |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | /* share of sustained abundance that is self-templating, and the chance share it is compared to */ |
| 103 | static void measure(double *got,double *chance){ |
| 104 | int tot=0,st=0; |
| 105 | for(int m=NFOOD;m<NSPEC;m++){ tot+=n[m]; if(selftem[m]) st+=n[m]; } |
| 106 | *got = tot? (double)st/tot : 0.0; |
| 107 | int ns=0; for(int m=NFOOD;m<NSPEC;m++) if(selftem[m]) ns++; |
| 108 | *chance = (double)ns/(NSPEC-NFOOD); /* their share of the species pool */ |
| 109 | } |
| 110 | |
| 111 | int main(void) |
| 112 | { |
| 113 | printf("=== DOES RUNG 1 PRODUCE RUNG 2? ===\n"); |
| 114 | printf(" A RAF self-organises (rung 1). A species is SELF-TEMPLATING when a reaction makes it and\n"); |
| 115 | printf(" it catalyses that reaction (rung 2). Same type, same run, no second model.\n"); |
| 116 | printf(" Enrichment = share of sustained abundance that is self-templating, over their share of\n"); |
| 117 | printf(" the species pool. CONTROL scrambles WHICH species count as self-templating while keeping\n"); |
| 118 | printf(" the same number of self-catalysing reactions — identical firing advantage, no link.\n\n"); |
| 119 | |
| 120 | double eg=0,ec=0; int ng=0,nc=0, seeds=60; |
| 121 | printf(" arm | self-templating share | chance share | enrichment\n"); |
| 122 | printf(" ----------+-----------------------+--------------+-----------\n"); |
| 123 | double sg=0,cg=0,sc=0,cc=0; |
| 124 | for(int s=0;s<seeds;s++){ |
| 125 | double g,ch; |
| 126 | RNG=0x9e3779b97f4a7c15ULL+(unsigned long long)s*0x2545F4914F6CDD1DULL; |
| 127 | net_random(0); seed(); react(); measure(&g,&ch); |
| 128 | if(ch>0.01){ sg+=g; cg+=ch; eg+=g/ch; ng++; } |
| 129 | RNG=0x9e3779b97f4a7c15ULL+(unsigned long long)s*0x2545F4914F6CDD1DULL; |
| 130 | net_random(1); seed(); react(); measure(&g,&ch); |
| 131 | if(ch>0.01){ sc+=g; cc+=ch; ec+=g/ch; nc++; } |
| 132 | } |
| 133 | if(ng) { sg/=ng; cg/=ng; eg/=ng; } |
| 134 | if(nc) { sc/=nc; cc/=nc; ec/=nc; } |
| 135 | printf(" REAL | %.3f | %.3f | %.3fx\n",sg,cg,eg); |
| 136 | printf(" SCRAMBLED | %.3f | %.3f | %.3fx\n\n",sc,cc,ec); |
| 137 | printf(" n = %d / %d networks with any self-templater\n\n",ng,nc); |
| 138 | |
| 139 | int live = (ng>seeds/3); |
| 140 | int real_enriched = eg>1.10; |
| 141 | int beats_ctrl = eg>ec+0.10; |
| 142 | |
| 143 | printf(" G1 enough networks had a self-templater : %s (%d of %d)\n", live?"YES":"NO — nothing to measure",ng,seeds); |
| 144 | printf(" G2 real enrichment > 1 : %s (%.3fx)\n", real_enriched?"YES":"no",eg); |
| 145 | printf(" G3 beats the scrambled control : %s (%.3fx vs %.3fx)\n\n", beats_ctrl?"YES":"no",eg,ec); |
| 146 | |
| 147 | if(!live) |
| 148 | printf(" => THE TEST DID NOT RUN. Too few networks contained a self-templating species, so\n" |
| 149 | " there was nothing to be enriched. Invalid, not a null.\n"); |
| 150 | else if(real_enriched && beats_ctrl) |
| 151 | printf(" => RUNG 1 PRODUCES RUNG 2. An autocatalytic set preferentially sustains the species\n" |
| 152 | " that template themselves — %.2fx their share of the pool, against %.2fx when the\n" |
| 153 | " property is scrambled onto random species with the identical firing advantage.\n" |
| 154 | " The seeds of heredity are enriched BY the self-sustaining set that precedes them,\n" |
| 155 | " in one model, in one type. That is the ladder's oldest admission answered for one\n" |
| 156 | " rung — and it is one rung, on the easy side of the 1->2 wall: enrichment of\n" |
| 157 | " self-templaters is not open-ended heredity.\n",eg,ec); |
| 158 | else if(real_enriched && !beats_ctrl) |
| 159 | printf(" => CONFOUNDED. Self-templaters are enriched (%.2fx) but so are the scrambled ones\n" |
| 160 | " (%.2fx), so the enrichment is the firing advantage of a self-catalysing reaction,\n" |
| 161 | " not any relationship between templating and being sustained. Claim nothing.\n",eg,ec); |
| 162 | else |
| 163 | printf(" => HONEST NULL. The autocatalytic set does NOT preferentially sustain self-templating\n" |
| 164 | " species (%.2fx, control %.2fx). Rung 1 sustains itself and nothing more, and the\n" |
| 165 | " ladder's oldest admission stands: no rung produces the next. The substrate made\n" |
| 166 | " the question askable without making the answer yes.\n",eg,ec); |
| 167 | return 0; |
| 168 | } |