/* ribozyme.c — the deepest attempt: does a replicase that BOOTSTRAPS ITS OWN FIDELITY ignite from a
* random low-fidelity soup? And does it need compartments to survive parasites? (digital-analogy land)
*
* polymer.c hit Eigen's bootstrap paradox: heritable function needs fidelity un-catalyzed templating
* can't supply, and the replicase that would supply it needs the fidelity first. The proposed escape is a
* ribozyme replicase that improves fidelity for its own kind -> positive feedback over the threshold.
*
* RAZOR (no encoded winner): catalysis is an EMERGENT STRUCTURAL property, not a named sequence. A strand's
* catalytic quality phi(s) = how well it folds into a HAIRPIN (self-complementarity: pair i with L-1-i,
* complementary when the bits differ, since 0 pairs 1). A fixed fold->function rule; MANY sequences reach
* high phi. FIDELITY EMERGES from catalysis: f = f0 + (F1-f0)*(meanphi/phimax) -- more replicase present,
* higher-fidelity copying for all in that compartment (the bootstrap coupling). NOTHING rewards being the
* replicase directly. The CATCH (what makes it honest): catalysis is a PUBLIC GOOD, and structured catalysts
* pay a replication cost while unstructured PARASITES (low phi) replicate faster and free-ride (weight
* 1+beta*(1-phi/phimax)). Measured: does phi (hence fidelity) RISE from a random start, or do parasites
* crush it? WELL-MIXED (one big pool, no group selection) vs COMPARTMENTS (stochastic corrector: small
* protocells, random assortment at division, between-compartment selection on catalytic content).
*
* build: cc -O2 -Wall -std=c11 -o ribozyme ribozyme.c -lm
*/
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#define L 24
#define PHIMAX (L/2) /* max hairpin pairs = 12 */
#define TOTAL 4800 /* total strands (= NCOMP*CSZ for the compartment arm) */
#define GEN 200
#define F0 0.85 /* un-catalyzed fidelity */
#define F1 0.999 /* fully-catalyzed (good ribozyme) fidelity */
#define BETA 2.0 /* parasite advantage: low-phi strands replicate 1+BETA x faster */
static unsigned long long RNG;
static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
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; }
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; }
static uint32_t pool[TOTAL], nxt[TOTAL];
/* run: ncomp compartments of csz (ncomp*csz=TOTAL). group=1 enables between-compartment selection+assortment.
returns final mean phi; writes final mean fidelity and start mean phi. */
static double run(int ncomp,int csz,int group,double *f_end,double *phi_start){
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; }
{ double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(pool[i]); *phi_start=sp/TOTAL; }
for(int g=0;g<GEN;g++){
/* within each compartment: Wright-Fisher replication; fidelity from mean phi; parasites replicate faster */
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]); double mphi=sphi/csz;
double f=F0+(F1-F0)*(mphi/PHIMAX);
double tot=0; static double w[TOTAL]; static double cum[TOTAL];
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; }
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); }
}
for(int i=0;i<TOTAL;i++) pool[i]=nxt[i];
if(group){
/* between-compartment: productivity = mean phi (catalytic content); sample parents ~productivity;
seed each daughter by RANDOM ASSORTMENT (draw csz strands w/ replacement) -> stochastic corrector */
static double P[TOTAL/1], cumP[TOTAL/1]; double tp=0;
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; }
for(int cmp=0;cmp<ncomp;cmp++){
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;
for(int k=0;k<csz;k++){ int src=par*csz+(int)(xs()%csz); nxt[cmp*csz+k]=pool[src]; }
}
for(int i=0;i<TOTAL;i++) pool[i]=nxt[i];
}
}
double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(pool[i]); double mphi=sp/TOTAL;
*f_end=F0+(F1-F0)*(mphi/PHIMAX); return mphi;
}
int main(void){
unsigned long long seeds[]={0x9e3779b97f4a7c15ULL,0xd1b54a32d192ed03ULL,0x2545f4914f6cdd1dULL};
int NS=sizeof(seeds)/sizeof(seeds[0]);
printf("=== Ribozyme replicase bootstrap: does fidelity ignite from a random soup? ===\n");
printf(" Catalysis = hairpin fold score phi (emergent, no encoded winner). Fidelity = f0 + (f1-f0)*phi/%d.\n",PHIMAX);
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);
printf(" Random start: mean phi ~%d (fidelity ~%.2f). RISE = bootstrap ignites; FALL = parasites win.\n\n",PHIMAX/2,F0+(F1-F0)*0.5);
printf(" arm | mean phi (start->end of %2d) | fidelity end\n",PHIMAX);
printf(" ----------------------------+-----------------------------+-------------\n");
double wmS=0,wmE=0,wmF=0;
for(int s=0;s<NS;s++){ double fe,ps; RNG=seeds[s]; wmE+=run(1,TOTAL,0,&fe,&ps); wmS+=ps; wmF+=fe; }
wmS/=NS;wmE/=NS;wmF/=NS;
printf(" WELL-MIXED (no compartments)| %.2f -> %.2f | %.3f\n", wmS,wmE,wmF);
/* sweep compartment SIZE: the stochastic corrector predicts small compartments are required
(more assortment variance -> parasite-free daughters). Report the DEPENDENCE, do not cherry-pick. */
int sizes[]={4,8,16,32}; int nSz=sizeof(sizes)/sizeof(int);
double best_end=wmE; int best_sz=0; double cpE_small=0,cpS_small=0;
for(int z=0;z<nSz;z++){ int csz=sizes[z], ncomp=TOTAL/csz;
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; }
cS/=NS;cE/=NS;cF/=NS;
printf(" COMPARTMENTS (%4d x %2d) | %.2f -> %.2f | %.3f\n", ncomp,csz, cS,cE,cF);
if(cE>best_end){ best_end=cE; best_sz=csz; }
if(csz==sizes[0]){ cpE_small=cE; cpS_small=cS; }
}
printf("\n");
int wm_up = (wmE > wmS+0.5);
int cp_up = (cpE_small > cpS_small+0.5) || (best_sz>0 && best_end>wmS+0.8);
printf(" well-mixed : phi %s (%.2f->%.2f)\n", wm_up?"ROSE":(wmE<wmS-0.5?"FELL":"~flat"), wmS,wmE);
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");
printf("\n");
if(cp_up && !wm_up)
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");
else if(cp_up && wm_up)
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");
else if(!cp_up)
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");
else
printf(" => Mixed/ambiguous outcome -- report the numbers as-is.\n");
return 0;
}