/* genome.c — does a system OFFLOAD its information into a cheap non-folding molecule?
* (the parasite-as-proto-genome test)
*
* WHY THIS, AND WHY NOW. fidfloor.c's division-size sweep found the two demands on a compartment are
* irreconcilable in one parameter: purging parasites needs SMALL compartments (ribozyme.c,
* chemoton.c, Test A), maintaining sequence information needs LARGE ones, and the sweep showed no
* optimum anywhere — SELECT − MIXED is negative and monotone at every division size and fidelity.
* So the way out cannot be a better compartment size. It has to be to stop asking one molecule to do
* both jobs: put the memory somewhere that does not have to fold.
*
* And that carrier is already in every model we have built. A parasite is a cheap, fast-replicating,
* NON-FOLDING strand — which is a precise description of a gene. Genes do not do chemistry. They get
* copied. So rung 1→2 may not be catalysts acquiring heredity; it may be catalysts DOMESTICATING a
* parasite, precisely because it is cheap to copy and carries no structural constraint.
*
* THE STRUCTURAL PREREQUISITE. Offloading needs something to offload TO, so fold and information must
* be separable. A strand is 16 FOLD bits (φ = complementary pairs, 0..8) plus 3 TYPE bits. A strand
* that folds (φ ≥ THETA) is a CATALYST of its type; one that does not is a TEMPLATE carrying only
* type. Both mutate at the same per-bit rate — but a template has 3 bits to protect and a catalyst
* has 19, which is the whole hypothesis: the same information costs fewer constrained bits when it
* is not also load-bearing structure.
*
* THE RAZOR (issue #6 — this is where encoding the answer is easiest, so state it precisely):
* SUPPLIED as physics, outcome left open: a template can be READ — an existing catalyst's fold bits
* plus a template's type bits make a new catalyst of that type. That is transcription/translation
* in miniature, and it is exactly the kind of coupling ribozyme.c supplied as its fold→catalysis
* premise. It is a mechanism, not a reward.
* NOT SUPPLIED: any benefit to holding templates. Templates fold nothing, contribute nothing
* directly, and cost material like everything else. They keep the parasite advantage — non-folders
* replicate faster (weight 1 + BETA·(1 − φ/PHIMAX)) — so they can still free-ride and take over.
* Nothing says a lineage should keep them, read them, or protect them.
* MEASURED: whether template fraction RISES and whether functional diversity is higher because of it.
*
* WHAT IS ALSO SUPPLIED, AND FLAGGED: between-compartment selection is DECREED here (sample parents ∝
* productivity, reseed by assortment), as in ribozyme.c. chemoton.c showed that step is derivable;
* re-deriving it inside this model would confound the one new variable, so it is handed in
* deliberately. This experiment is about offloading, not about where compartment selection comes from.
*
* PRE-REGISTERED:
* G1 READ OFF: templates are purged — they contribute nothing and are pure parasites.
* G2 READ ON: template fraction RISES and distinct catalyst types is HIGHER than with reading off.
* Information moved off the folded molecule onto the cheap one, unforced.
* G3 CONTROL — SCRAMBLED: reading works, but a template's type bits are replaced by random bits when
* read, so the mechanism exists and carries NO information. If templates still rise here, the
* effect is the reading machinery, not the information, and G2 means nothing.
* G4 TEST OF THE TEST: catalysts and templates must coexist. If either goes extinct in every arm
* there was no offloading to observe and a null says nothing.
* G5 The advantage should GROW with mutation rate μ — a template protects 3 bits where a catalyst
* protects 19, so the gap should widen exactly where folds get fragile.
*
* build: cc -O2 -Wall -std=c11 -o genome genome.c -lm
*/
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#define NFOLD 16 /* fold bits: pairs (i, NFOLD-1-i), i in 0..7 */
#define NPAIR (NFOLD/2) /* max fold score = 8 */
#define THETA 6 /* folds (is a catalyst) if phi >= THETA */
#define NTYPE 8 /* 3 type bits */
#define NCOMP 600
#define CSZ 8 /* small compartments: the regime the corrector needs */
#define GEN 200
#define PREAD 0.50 /* chance a picked template is READ rather than copied true */
#define BETA 2.0 /* non-folders replicate faster — the parasite advantage stays */
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); }
/* strand = 16 fold bits (0..15) + 3 type bits (16..18) */
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 int TARGET[NTYPE]; /* world-supplied: which types are worth having (payoff mode 1) */
static int NTARG=4;
static uint32_t cell[NCOMP][CSZ], ncell[NCOMP][CSZ];
static double cum[NCOMP];
/* payoff 0 = DIVERSITY: any distinct catalyst types count (genome.c's original).
payoff 1 = TARGET: only types in a world-supplied target set count.
The difference is the whole point: under DIVERSITY any repertoire is as good as any other, so
there is nothing worth remembering and a dice-roll beats a memory. Under TARGET a SPECIFIC
configuration beats a random one, so faithful reading has something to be faithful TO. */
static int repertoire_mode(const uint32_t *c,int payoff){
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(payoff==0||TARGET[t]) d++; } }
return d;
}
static int repertoire(const uint32_t *c){ return repertoire_mode(c,0); }
/* mode 0 = READ OFF, 1 = READ ON, 2 = SCRAMBLED control (reads, but type bits randomised) */
static double run(int mode,double mu,int payoff,double *tmpl_frac,double *cat_frac,double *rep_out)
{
/* world-supplied target: a random NTARG-subset of the types, redrawn per run so no particular
set is special-cased. Same shape as polymer.c's random target motif. */
for(int t=0;t<NTYPE;t++) TARGET[t]=0;
for(int got=0;got<NTARG;){ int t=(int)(xs()%NTYPE); 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; }
for(int g=0;g<GEN;g++){
/* ---- within compartment: replication. Non-folders are faster (parasite advantage). ---- */
for(int c=0;c<NCOMP;c++){
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; }
/* index of some catalyst in this compartment, if any — the generic reading machinery */
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;
if(mode!=0 && !isfold(par) && mach>=0 && urand()<PREAD){
/* READ (template -> catalyst): a catalyst's fold bits + this template's type bits.
v1/v2 made this the ONLY thing a template could do, so reading was a dead end for
the template lineage — it could be useful or persist, never both. Real genomes are
copied AS genomes and SEPARATELY read. Now reading happens with probability PREAD
and otherwise the template is copied as a template, exactly as a catalyst is
copied as a catalyst. Both classes propagate only by copying; reading is a
FUNCTION templates provide, not an extra route to propagate. */
uint32_t ty = (mode==2) ? (uint32_t)(xs()&7) : (uint32_t)typeof_(par);
child = (cell[c][mach] & ((1u<<NFOLD)-1)) | (ty<<NFOLD);
} else child = par; /* copy true: catalyst->catalyst, template->template */
ncell[c][k]=mut(child,mu);
}
}
for(int c=0;c<NCOMP;c++) for(int k=0;k<CSZ;k++) cell[c][k]=ncell[c][k];
/* ---- between compartment: DECREED selection on functional repertoire (flagged, not derived) ---- */
double tot=0;
for(int c=0;c<NCOMP;c++){ tot += 0.05 + (double)repertoire_mode(cell[c],payoff); 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,nc=0; double rp=0;
for(int c=0;c<NCOMP;c++){
rp += repertoire_mode(cell[c],payoff);
for(int k=0;k<CSZ;k++){ if(isfold(cell[c][k])) nc++; else nt++; }
}
*tmpl_frac=(double)nt/((double)NCOMP*CSZ);
*cat_frac =(double)nc/((double)NCOMP*CSZ);
*rep_out = rp/NCOMP;
return *rep_out;
}
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("=== PARASITE AS PROTO-GENOME v2: does the PAYOFF decide whether memory pays? ===\n");
printf(" v1 found reading raises function (+0.92 at high mu) but SCRAMBLED reading — random type\n");
printf(" instead of the template's — BEAT faithful reading everywhere. Diagnosis: the payoff\n");
printf(" rewarded DIVERSITY, and randomness supplies diversity better than fidelity does. A world\n");
printf(" where any repertoire is as good as any other has nothing worth remembering.\n");
printf(" v2 adds a TARGET payoff: only %d of %d types count, drawn at random per run. Now a\n",4,NTYPE);
printf(" SPECIFIC configuration beats a random one. PREDICTION: the control INVERTS.\n\n");
double mus[]={0.005,0.01,0.02,0.04,0.08};
int nM=5;
const char *pn[2]={"DIVERSITY (v1)","TARGET (v2)"};
int inverted=0, div_scr_wins=0, tgt_faith_wins=0;
for(int pay=0;pay<2;pay++){
printf(" --- payoff = %s ---\n",pn[pay]);
printf(" mu | READ OFF | READ ON (faithful) | SCRAMBLED | faithful - scrambled\n");
printf(" ------+----------+--------------------+-----------+---------------------\n");
for(int i=0;i<nM;i++){
double r0=0,r1=0,r2=0;
for(int s=0;s<NS;s++){
double tf,cf,rp;
RNG=seeds[s]; run(0,mus[i],pay,&tf,&cf,&rp); r0+=rp;
RNG=seeds[s]; run(1,mus[i],pay,&tf,&cf,&rp); r1+=rp;
RNG=seeds[s]; run(2,mus[i],pay,&tf,&cf,&rp); r2+=rp;
}
r0/=NS;r1/=NS;r2/=NS;
double d=r1-r2;
printf(" %.3f | %.2f | %.2f | %.2f | %+.3f\n",mus[i],r0,r1,r2,d);
if(pay==0 && d<-0.02) div_scr_wins++;
if(pay==1 && d>0.02) tgt_faith_wins++;
}
printf("\n");
}
inverted = (div_scr_wins>=4 && tgt_faith_wins>=4);
printf(" under DIVERSITY, scrambled beats faithful : %d/%d mutation rates\n",div_scr_wins,nM);
printf(" under TARGET, faithful beats scrambled : %d/%d mutation rates\n\n",tgt_faith_wins,nM);
if(inverted)
printf(" => THE CONTROL INVERTS, AND THE PAYOFF IS WHAT DECIDES. The identical mechanism, the\n"
" identical molecules, the identical parasite advantage — and whether carrying\n"
" information on a cheap non-folding strand pays depends entirely on whether the world\n"
" rewards a SPECIFIC configuration or merely variety. Memory is worthless in a world\n"
" that will take any answer, and selected for in one that will not. That is a\n"
" condition on the ENVIRONMENT for the genotype/phenotype split, not on the chemistry.\n");
else if(tgt_faith_wins>=4)
printf(" => FAITHFUL WINS UNDER TARGET (%d/%d) but the diversity contrast did not come out as\n"
" cleanly (%d/%d). The direction supports the diagnosis; report the asymmetry as-is.\n",
tgt_faith_wins,nM,div_scr_wins,nM);
else
printf(" => HONEST NULL. Even with a target payoff, faithful reading does NOT beat scrambled.\n"
" The diagnosis from v1 was wrong: giving the world something specific to want is not\n"
" what makes memory pay, and the missing ingredient is still unidentified.\n");
return 0;
}