/* replicase.c — the closed genotype/phenotype loop. Can it bootstrap?
*
* WHERE THIS COMES FROM. genome.c v1/v2 gave templates a fair test and they failed twice, but the
* second failure exposed something I had been getting for free: TEMPLATE COPYING WAS FREE PHYSICS
* (child = par, perfect, no cost). In reality copying a genome faithfully needs a REPLICASE, which
* is itself a catalyst, which is itself specified by a template. That is the loop, and it is exactly
* rung 1→2.
*
* Two flaws in genome.c are fixed here:
* (1) a picked template ALWAYS became a catalyst when reading was on, so reading was a dead end for
* the template lineage — it could be useful or persist, never both. Now a picked template is
* READ with probability PREAD and otherwise COPIED TRUE, exactly as a catalyst is copied true.
* Reading is a FUNCTION templates provide, not a route by which they propagate.
* (2) template fidelity was free. Now it is CONDITIONAL on the compartment holding a catalyst of
* the replicase type: with one, templates copy at MU*RLO; without, at MU*RHI.
*
* THE RAZOR. This is where encoding the answer is easiest, so, precisely:
* SUPPLIED as physics: "a type-REPTYPE catalyst improves template fidelity in its compartment" —
* a function, the same shape as ribozyme.c's supplied fold→catalysis map.
* NOT SUPPLIED: any reward for being or holding a replicase. REPTYPE is EXCLUDED FROM THE TARGET
* SET, so it contributes nothing to payoff directly — it is pure overhead unless the template
* loop pays for itself. It is not seeded, not protected, not favoured in replication. Non-folders
* still replicate faster, so the parasite advantage is intact and the replicase is a PUBLIC GOOD
* within its compartment, free-ridable exactly as catalysis was in ribozyme.c.
* MEASURED: whether lineages acquire and HOLD the replicase, and whether function is higher for it.
*
* THE CONTROL, built to today's matched-condition lesson. Turning the replicase effect on also
* changes the average template mutation rate, which would confound any gain. So the control applies
* the IDENTICAL two-rate structure conditioned on a COIN FLIP per compartment instead of on
* replicase presence — same mutation-rate distribution, no type to select for. The realized
* low-fidelity fraction is reported for both arms so the match is visible rather than assumed.
*
* PRE-REGISTERED:
* R1 replicase frequency RISES above the control's. Lineages hold a type that pays them nothing
* directly, because it protects the templates that carry everything else.
* R2 target repertoire is HIGHER with the replicase effect than with the coin-flip control.
* R3 TEST OF THE TEST: catalysts and templates coexist, and the two arms' low-fidelity fractions
* are comparable. If they diverge sharply the comparison is confounded by mutation load.
* R4 the advantage should GROW with base mu — the replicase matters most where templates decay fast.
*
* HONEST PRIOR: partial. The replicase is a public good inside its compartment, so free-riding should
* bite exactly as it did in ribozyme.c — one level up. A null here is a real result.
*
* build: cc -O2 -Wall -std=c11 -o replicase replicase.c -lm
*/
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#define NFOLD 16
#define NPAIR (NFOLD/2)
#define THETA 6
#define NTYPE 8
#define REPTYPE 0 /* the replicase type — excluded from the target set */
#define NTARG 3 /* target types, drawn from types 1..7 */
#define NCOMP 600
#define CSZ 8
#define GEN 200
#define BETA 2.0
#define PREAD 0.50
#define RLO 0.25 /* template mutation multiplier WITH a replicase present */
#define RHI 1.50 /* ... and without */
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 TARGET[NTYPE];
static int phi(uint32_t s){ int c=0; for(int i=0;i<NPAIR;i++){ int a=(s>>i)&1,b=(s>>(NFOLD-1-i))&1; if(a!=b)c++; } return c; }
static int isfold(uint32_t s){ return phi(s)>=THETA; }
static int typeof_(uint32_t s){ return (int)((s>>NFOLD)&7); }
static uint32_t mut(uint32_t s,double mu){ for(int i=0;i<NFOLD+3;i++) if(urand()<mu) s^=(1u<<i); return s; }
static uint32_t cell[NCOMP][CSZ], ncell[NCOMP][CSZ];
static double cum[NCOMP];
static int payoff_of(const uint32_t *c){
int seen[NTYPE]; for(int t=0;t<NTYPE;t++) seen[t]=0;
int d=0;
for(int k=0;k<CSZ;k++) if(isfold(c[k])){ int t=typeof_(c[k]); if(!seen[t]){ seen[t]=1; if(TARGET[t]) d++; } }
return d;
}
static int has_replicase(const uint32_t *c){
for(int k=0;k<CSZ;k++) if(isfold(c[k]) && typeof_(c[k])==REPTYPE) return 1;
return 0;
}
/* mode 0 = REPLICASE (fidelity conditioned on holding one), 1 = CONTROL (same structure, coin flip) */
static void run(int mode,double mu,double pflip,double *rep_freq,double *pay_out,double *tmpl,double *lofrac)
{
for(int t=0;t<NTYPE;t++) TARGET[t]=0;
for(int got=0;got<NTARG;){ int t=1+(int)(xs()%(NTYPE-1)); if(!TARGET[t]){ TARGET[t]=1; got++; } }
for(int c=0;c<NCOMP;c++)
for(int k=0;k<CSZ;k++){ uint32_t v=0; for(int i=0;i<NFOLD+3;i++) if(urand()<0.5) v|=(1u<<i); cell[c][k]=v; }
double losum=0; long lon=0;
for(int g=0;g<GEN;g++){
for(int c=0;c<NCOMP;c++){
int lo_fid = (mode==0)? has_replicase(cell[c]) : (urand()<pflip);
losum += lo_fid; lon++;
double tmu = mu*(lo_fid?RLO:RHI);
double tot=0,cw[CSZ];
for(int k=0;k<CSZ;k++){ tot += 1.0 + BETA*(1.0-(double)phi(cell[c][k])/NPAIR); cw[k]=tot; }
int mach=-1; for(int k=0;k<CSZ;k++) if(isfold(cell[c][k])){ mach=k; break; }
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(cw[mid]<r) lo=mid+1; else hi=mid; }
uint32_t par=cell[c][lo], child; double emu;
if(!isfold(par)){
if(mach>=0 && urand()<PREAD){ /* READ: template -> catalyst */
child=(cell[c][mach]&((1u<<NFOLD)-1))|((uint32_t)typeof_(par)<<NFOLD);
emu=mu; /* the new catalyst is a catalyst */
} else { child=par; emu=tmu; } /* COPY TRUE, at template fidelity */
} else { child=par; emu=mu; } /* catalyst -> catalyst */
ncell[c][k]=mut(child,emu);
}
}
for(int c=0;c<NCOMP;c++) for(int k=0;k<CSZ;k++) cell[c][k]=ncell[c][k];
double tot=0;
for(int c=0;c<NCOMP;c++){ tot += 0.05 + (double)payoff_of(cell[c]); cum[c]=tot; }
for(int c=0;c<NCOMP;c++){
double r=urand()*tot; int lo=0,hi=NCOMP-1;
while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; }
for(int k=0;k<CSZ;k++) ncell[c][k]=cell[lo][(int)(xs()%CSZ)];
}
for(int c=0;c<NCOMP;c++) for(int k=0;k<CSZ;k++) cell[c][k]=ncell[c][k];
}
long nt=0; double rp=0,pay=0;
for(int c=0;c<NCOMP;c++){
rp += has_replicase(cell[c]); pay += payoff_of(cell[c]);
for(int k=0;k<CSZ;k++) if(!isfold(cell[c][k])) nt++;
}
*rep_freq=rp/NCOMP; *pay_out=pay/NCOMP;
*tmpl=(double)nt/((double)NCOMP*CSZ); *lofrac=losum/(double)lon;
}
int main(void)
{
unsigned long long seeds[6];
seeds[0]=0x9e3779b97f4a7c15ULL; seeds[1]=0xd1b54a32d192ed03ULL; seeds[2]=0x2545f4914f6cdd1dULL;
for(int i=3;i<6;i++) seeds[i]=0x9e3779b97f4a7c15ULL ^ (0x100000001b3ULL*(unsigned long long)(i+1));
int NS=6;
printf("=== REPLICASE: can the genotype/phenotype loop close on itself? ===\n");
printf(" A type-%d catalyst improves TEMPLATE fidelity in its compartment (x%.2f vs x%.2f).\n",REPTYPE,RLO,RHI);
printf(" It is EXCLUDED from the target set, so it pays nothing directly — pure overhead unless\n");
printf(" the template loop pays for itself. Not seeded, not protected; non-folders still replicate\n");
printf(" %.0fx faster, so the replicase is a PUBLIC GOOD inside its compartment and free-ridable.\n",1+BETA);
printf(" CONTROL applies the identical two-rate structure by COIN FLIP instead — same mutation\n");
printf(" distribution, no type to select for. %d comps x %d, %d gens, %d seeds.\n\n",NCOMP,CSZ,GEN,NS);
printf(" mu | REPLICASE: rep-freq / payoff / tmpl | CONTROL: rep-freq / payoff | lo-fid frac R/C\n");
printf(" ------+-------------------------------------+----------------------------+----------------\n");
double mus[]={0.005,0.01,0.02,0.04,0.08};
int nM=5, r1=0, r2=0, matched=1; double g0=0,g1=0;
for(int i=0;i<nM;i++){
/* TWO PASS, so the control is matched rather than guessed: run the replicase arm, measure the
fraction of compartment-generations that actually got the low rate, then give the control a
coin flip at exactly that probability. The first version guessed PFLIP=0.60 from a uniform-type
estimate; selection purges type 0 (it pays nothing) so the real figure is 0.03-0.13, and the
control was running at a fraction of the mutation load. R3 caught it. */
double a1=0,a2=0,a3=0,a4=0, b1=0,b2=0,b4=0;
double lf_meas[8];
for(int s=0;s<NS;s++){
double rf,pv,tm,lf;
RNG=seeds[s]; run(0,mus[i],0.0,&rf,&pv,&tm,&lf); a1+=rf; a2+=pv; a3+=tm; a4+=lf; lf_meas[s]=lf;
}
for(int s=0;s<NS;s++){
double rf,pv,tm,lf;
RNG=seeds[s]; run(1,mus[i],lf_meas[s],&rf,&pv,&tm,&lf); b1+=rf; b2+=pv; b4+=lf;
}
a1/=NS;a2/=NS;a3/=NS;a4/=NS; b1/=NS;b2/=NS;b4/=NS;
printf(" %.3f | %.3f / %.2f / %.3f | %.3f / %.2f | %.2f / %.2f\n",
mus[i],a1,a2,a3,b1,b2,a4,b4);
if(a1>b1+0.02) r1++;
if(a2>b2+0.05) r2++;
if(fabs(a4-b4)>0.03) matched=0;
if(i==0) g0=a2-b2;
g1=a2-b2;
}
printf("\n rep-freq = fraction of compartments holding a replicase; payoff = target types present (max %d)\n\n",NTARG);
printf(" R3 low-fidelity fractions comparable : %s\n", matched?"YES":"NO — CONFOUNDED by mutation load");
printf(" R1 replicase held above control : %d/%d mutation rates\n",r1,nM);
printf(" R2 payoff higher than control : %d/%d mutation rates\n",r2,nM);
printf(" R4 advantage grows with mu : %+.2f at mu=%.3f -> %+.2f at mu=%.3f\n\n",g0,mus[0],g1,mus[nM-1]);
if(!matched)
printf(" => CONFOUNDED. The arms did not experience comparable mutation loads, so any difference\n"
" is the load and not the loop.\n");
else if(r1>=nM-1 && r2>=nM-1)
printf(" => THE LOOP CLOSED. Lineages hold a catalyst type that pays them NOTHING directly,\n"
" because it protects the templates that carry everything that does pay — and they\n"
" carry more function for it than the matched control. Genotype and phenotype became\n"
" mutually dependent without either being rewarded for it. That is rung 1->2's\n"
" architecture, bootstrapped rather than installed.\n");
else if(r2>=nM-1)
printf(" => FUNCTION UP, REPLICASE NOT HELD (%d/%d vs %d/%d). The fidelity boost helps where it\n"
" happens to occur, but lineages do not retain the replicase — free-riding inside the\n"
" compartment wins, exactly as ribozyme.c found one level down. The loop does not close.\n",r2,nM,r1,nM);
else
printf(" => HONEST NULL. The replicase is not held and function is not raised. A catalyst that\n"
" pays only by protecting templates cannot pay for itself here: it is a public good\n"
" inside its own compartment and is free-ridden away. The genotype/phenotype loop\n"
" needs something this model does not have.\n");
return 0;
}