| … | … | @@ -0,0 +1,117 @@ |
| 1 | /* ribozyme.c — the deepest attempt: does a replicase that BOOTSTRAPS ITS OWN FIDELITY ignite from a |
| 2 | * random low-fidelity soup? And does it need compartments to survive parasites? (digital-analogy land) |
| 3 | * |
| 4 | * polymer.c hit Eigen's bootstrap paradox: heritable function needs fidelity un-catalyzed templating |
| 5 | * can't supply, and the replicase that would supply it needs the fidelity first. The proposed escape is a |
| 6 | * ribozyme replicase that improves fidelity for its own kind -> positive feedback over the threshold. |
| 7 | * |
| 8 | * RAZOR (no encoded winner): catalysis is an EMERGENT STRUCTURAL property, not a named sequence. A strand's |
| 9 | * catalytic quality phi(s) = how well it folds into a HAIRPIN (self-complementarity: pair i with L-1-i, |
| 10 | * complementary when the bits differ, since 0 pairs 1). A fixed fold->function rule; MANY sequences reach |
| 11 | * high phi. FIDELITY EMERGES from catalysis: f = f0 + (F1-f0)*(meanphi/phimax) -- more replicase present, |
| 12 | * higher-fidelity copying for all in that compartment (the bootstrap coupling). NOTHING rewards being the |
| 13 | * replicase directly. The CATCH (what makes it honest): catalysis is a PUBLIC GOOD, and structured catalysts |
| 14 | * pay a replication cost while unstructured PARASITES (low phi) replicate faster and free-ride (weight |
| 15 | * 1+beta*(1-phi/phimax)). Measured: does phi (hence fidelity) RISE from a random start, or do parasites |
| 16 | * crush it? WELL-MIXED (one big pool, no group selection) vs COMPARTMENTS (stochastic corrector: small |
| 17 | * protocells, random assortment at division, between-compartment selection on catalytic content). |
| 18 | * |
| 19 | * build: cc -O2 -Wall -std=c11 -o ribozyme ribozyme.c -lm |
| 20 | */ |
| 21 | #include <math.h> |
| 22 | #include <stdio.h> |
| 23 | #include <stdint.h> |
| 24 | |
| 25 | #define L 24 |
| 26 | #define PHIMAX (L/2) /* max hairpin pairs = 12 */ |
| 27 | #define TOTAL 4800 /* total strands (= NCOMP*CSZ for the compartment arm) */ |
| 28 | #define GEN 200 |
| 29 | #define F0 0.85 /* un-catalyzed fidelity */ |
| 30 | #define F1 0.999 /* fully-catalyzed (good ribozyme) fidelity */ |
| 31 | #define BETA 2.0 /* parasite advantage: low-phi strands replicate 1+BETA x faster */ |
| 32 | |
| 33 | static unsigned long long RNG; |
| 34 | static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; } |
| 35 | static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); } |
| 36 | |
| 37 | static int phi(uint32_t s){ int c=0; for(int i=0;i<PHIMAX;i++){ int a=(s>>i)&1, b=(s>>(L-1-i))&1; if(a!=b) c++; } return c; } |
| 38 | static uint32_t replicate(uint32_t t,double f){ uint32_t c=0; for(int i=0;i<L;i++){ int b=(t>>i)&1; int nb=(urand()<f)?(1-b):b; if(nb) c|=(1u<<i);} return c; } |
| 39 | |
| 40 | static uint32_t pool[TOTAL], nxt[TOTAL]; |
| 41 | |
| 42 | /* run: ncomp compartments of csz (ncomp*csz=TOTAL). group=1 enables between-compartment selection+assortment. |
| 43 | returns final mean phi; writes final mean fidelity and start mean phi. */ |
| 44 | static double run(int ncomp,int csz,int group,double *f_end,double *phi_start){ |
| 45 | for(int i=0;i<TOTAL;i++){ uint32_t s=0; for(int b=0;b<L;b++) if(urand()<0.5) s|=(1u<<b); pool[i]=s; } |
| 46 | { double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(pool[i]); *phi_start=sp/TOTAL; } |
| 47 | |
| 48 | for(int g=0;g<GEN;g++){ |
| 49 | /* within each compartment: Wright-Fisher replication; fidelity from mean phi; parasites replicate faster */ |
| 50 | for(int cmp=0;cmp<ncomp;cmp++){ |
| 51 | int base=cmp*csz; double sphi=0; for(int k=0;k<csz;k++) sphi+=phi(pool[base+k]); double mphi=sphi/csz; |
| 52 | double f=F0+(F1-F0)*(mphi/PHIMAX); |
| 53 | double tot=0; static double w[TOTAL]; static double cum[TOTAL]; |
| 54 | for(int k=0;k<csz;k++){ double ww=1.0+BETA*(1.0-(double)phi(pool[base+k])/PHIMAX); tot+=ww; cum[base+k]=tot; (void)w; } |
| 55 | for(int k=0;k<csz;k++){ double r=urand()*tot; int lo=0,hi=csz-1; while(lo<hi){int mid=(lo+hi)/2; if(cum[base+mid]<r)lo=mid+1; else hi=mid;} nxt[base+k]=replicate(pool[base+lo],f); } |
| 56 | } |
| 57 | for(int i=0;i<TOTAL;i++) pool[i]=nxt[i]; |
| 58 | |
| 59 | if(group){ |
| 60 | /* between-compartment: productivity = mean phi (catalytic content); sample parents ~productivity; |
| 61 | seed each daughter by RANDOM ASSORTMENT (draw csz strands w/ replacement) -> stochastic corrector */ |
| 62 | static double P[TOTAL/1], cumP[TOTAL/1]; double tp=0; |
| 63 | for(int cmp=0;cmp<ncomp;cmp++){ int base=cmp*csz; double sphi=0; for(int k=0;k<csz;k++) sphi+=phi(pool[base+k]); tp+=sphi/csz; cumP[cmp]=tp; P[cmp]=0; (void)P; } |
| 64 | for(int cmp=0;cmp<ncomp;cmp++){ |
| 65 | double r=urand()*tp; int lo=0,hi=ncomp-1; while(lo<hi){int mid=(lo+hi)/2; if(cumP[mid]<r)lo=mid+1; else hi=mid;} int par=lo; |
| 66 | for(int k=0;k<csz;k++){ int src=par*csz+(int)(xs()%csz); nxt[cmp*csz+k]=pool[src]; } |
| 67 | } |
| 68 | for(int i=0;i<TOTAL;i++) pool[i]=nxt[i]; |
| 69 | } |
| 70 | } |
| 71 | double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(pool[i]); double mphi=sp/TOTAL; |
| 72 | *f_end=F0+(F1-F0)*(mphi/PHIMAX); return mphi; |
| 73 | } |
| 74 | |
| 75 | int main(void){ |
| 76 | unsigned long long seeds[]={0x9e3779b97f4a7c15ULL,0xd1b54a32d192ed03ULL,0x2545f4914f6cdd1dULL}; |
| 77 | int NS=sizeof(seeds)/sizeof(seeds[0]); |
| 78 | printf("=== Ribozyme replicase bootstrap: does fidelity ignite from a random soup? ===\n"); |
| 79 | printf(" Catalysis = hairpin fold score phi (emergent, no encoded winner). Fidelity = f0 + (f1-f0)*phi/%d.\n",PHIMAX); |
| 80 | printf(" Parasites (low phi) replicate %.0fx faster and free-ride. f0=%.2f, f1=%.3f. %d strands, %d gens, %d seeds.\n",1+BETA,F0,F1,TOTAL,GEN,NS); |
| 81 | printf(" Random start: mean phi ~%d (fidelity ~%.2f). RISE = bootstrap ignites; FALL = parasites win.\n\n",PHIMAX/2,F0+(F1-F0)*0.5); |
| 82 | printf(" arm | mean phi (start->end of %2d) | fidelity end\n",PHIMAX); |
| 83 | printf(" ----------------------------+-----------------------------+-------------\n"); |
| 84 | |
| 85 | double wmS=0,wmE=0,wmF=0; |
| 86 | for(int s=0;s<NS;s++){ double fe,ps; RNG=seeds[s]; wmE+=run(1,TOTAL,0,&fe,&ps); wmS+=ps; wmF+=fe; } |
| 87 | wmS/=NS;wmE/=NS;wmF/=NS; |
| 88 | printf(" WELL-MIXED (no compartments)| %.2f -> %.2f | %.3f\n", wmS,wmE,wmF); |
| 89 | |
| 90 | /* sweep compartment SIZE: the stochastic corrector predicts small compartments are required |
| 91 | (more assortment variance -> parasite-free daughters). Report the DEPENDENCE, do not cherry-pick. */ |
| 92 | int sizes[]={4,8,16,32}; int nSz=sizeof(sizes)/sizeof(int); |
| 93 | double best_end=wmE; int best_sz=0; double cpE_small=0,cpS_small=0; |
| 94 | for(int z=0;z<nSz;z++){ int csz=sizes[z], ncomp=TOTAL/csz; |
| 95 | double cS=0,cE=0,cF=0; for(int s=0;s<NS;s++){ double fe,ps; RNG=seeds[s]; cE+=run(ncomp,csz,1,&fe,&ps); cS+=ps; cF+=fe; } |
| 96 | cS/=NS;cE/=NS;cF/=NS; |
| 97 | printf(" COMPARTMENTS (%4d x %2d) | %.2f -> %.2f | %.3f\n", ncomp,csz, cS,cE,cF); |
| 98 | if(cE>best_end){ best_end=cE; best_sz=csz; } |
| 99 | if(csz==sizes[0]){ cpE_small=cE; cpS_small=cS; } |
| 100 | } |
| 101 | printf("\n"); |
| 102 | |
| 103 | int wm_up = (wmE > wmS+0.5); |
| 104 | int cp_up = (cpE_small > cpS_small+0.5) || (best_sz>0 && best_end>wmS+0.8); |
| 105 | printf(" well-mixed : phi %s (%.2f->%.2f)\n", wm_up?"ROSE":(wmE<wmS-0.5?"FELL":"~flat"), wmS,wmE); |
| 106 | printf(" compartments: best at size=%d -> phi end %.2f (vs random start %.2f) %s\n", best_sz, best_end, wmS, cp_up?"ROSE":"~flat/fell"); |
| 107 | printf("\n"); |
| 108 | if(cp_up && !wm_up) |
| 109 | printf(" => BOOTSTRAP IGNITES, BUT ONLY WITH COMPARTMENTS. Well-mixed: catalysis is a public good, parasites\n free-ride and drive phi (hence fidelity) DOWN -- the replicase can't pay its own way. Compartments\n (stochastic corrector): random assortment makes some protocells catalyst-rich; between-compartment\n selection on catalytic content spreads them, out-running the within-compartment parasites -> phi and\n fidelity RISE from the random soup. The replicase bootstraps its own fidelity -- but the escape from\n Eigen's paradox is COMPARTMENTALIZATION, matching the field (Szathmary-Demeter stochastic corrector)\n and our own 'heredity may REQUIRE compartments' finding. HONEST BOUND: I supplied the fold->catalysis\n rule and the fidelity coupling as physics; whether THOSE arise unaided is the deeper edge.\n"); |
| 110 | else if(cp_up && wm_up) |
| 111 | printf(" => Bootstrap ignites even well-mixed -- parasite pressure (BETA) too weak to create the public-\n goods tragedy here; the compartment result is then not decisive. Raise BETA and re-examine.\n"); |
| 112 | else if(!cp_up) |
| 113 | printf(" => Bootstrap does NOT ignite even with compartments -- honest null: parasites win at both levels\n in this regime; the replicase cannot bootstrap its fidelity here. Do not tune to force it.\n"); |
| 114 | else |
| 115 | printf(" => Mixed/ambiguous outcome -- report the numbers as-is.\n"); |
| 116 | return 0; |
| 117 | } |