/* rung34.c — does rung 4 (compartmentalization) EMERGE from rung 3, un-forced?
*
* The honest test (not hand-coding rung 4): compartmentalization is a HERITABLE trait
* c in [0,1] that can mutate UP OR DOWN. It sets a lineage's compartment size
* D(c) = Dmax at c=0 (big ~ well-mixed) -> Dmin at c=1 (tiny, strong compartmentalization).
* Cooperators keep a compartment viable; parasites replicate faster within it (free-ride).
* Survival is weighted by cooperator FRACTION (quality, size-neutral) — so nothing rewards
* small compartments for being small. We only watch which way selection drives c.
*
* Mechanism (Szathmary-Demeter stochastic corrector): small compartments have HIGH variance
* in cooperator fraction among daughters -> selection finds cooperator-rich ones -> maintains
* cooperation AND (since only small D produces those) drives c UP. Large compartments: within-
* level parasite growth wins, low variance, all daughters low-quality -> die. If c climbs on
* its own, rung 4 EMERGED — selection discovered compartmentalization, we didn't impose it.
* (We supply the OPTION — the law-space; evolution supplies the selection.)
*
* Control: freeze c (no mutation) at its low start -> cooperation should COLLAPSE.
*
* build: cc -O2 -Wall -std=c11 -o rung34 rung34.c -lm
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define NCOMP 600
#define GEN 500
#define SADV 0.6 /* parasite replication advantage */
#define DMIN 2
#define DMAX 40
#define MUTC 0.03
#define MUP 0.10 /* cooperator->parasite mutation: sustained parasite pressure */
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 double randn(void){ double u=urand(),v=urand(); if(u<1e-300)u=1e-300; return sqrt(-2*log(u))*cos(6.283185307*v); }
static int Dof(double c){ int D=(int)(DMIN+(1.0-c)*(DMAX-DMIN)+0.5); return D<DMIN?DMIN:(D>DMAX?DMAX:D); }
static int binom(int n,double p){ int k=0; for(int i=0;i<n;i++) if(urand()<p) k++; return k; }
static double cc[NCOMP]; static int nC[NCOMP];
static double dcc[2*NCOMP]; static int dnC[2*NCOMP], dD[2*NCOMP]; static double cum[2*NCOMP];
/* returns final mean c; writes final coop fraction to *coopf. evolve_c toggles c mutation. */
static double run(int evolve_c,double *coopf,int verbose){
for(int i=0;i<NCOMP;i++){ cc[i]=0.10; nC[i]=Dof(0.10)/2; } /* weak compartmentalization start */
for(int g=0;g<GEN;g++){
for(int i=0;i<NCOMP;i++){
int D=Dof(cc[i]); int nc=nC[i]; if(nc>D)nc=D; int np=D-nc;
double wc=nc, wp=np*(1.0+SADV); double p=(wc+wp>0)?wc/(wc+wp):0;
int g2=binom(2*D,p); g2=binom(g2,1.0-MUP); double frac=(double)g2/(2*D);
for(int d=0;d<2;d++){
double c2 = evolve_c ? cc[i]+MUTC*randn() : cc[i];
if(c2<0)c2=0; if(c2>1)c2=1;
int D2=Dof(c2);
dcc[2*i+d]=c2; dD[2*i+d]=D2; dnC[2*i+d]=binom(D2,frac);
}
}
/* select NCOMP survivors weighted by cooperator FRACTION (size-neutral quality) */
double tot=0; for(int i=0;i<2*NCOMP;i++){ tot+=(double)dnC[i]/dD[i]; cum[i]=tot; }
if(tot<=0){ for(int i=0;i<NCOMP;i++){ nC[i]=0; } }
else for(int i=0;i<NCOMP;i++){
double r=urand()*tot; int lo=0,hi=2*NCOMP-1;
while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; }
cc[i]=dcc[lo]; nC[i]=dnC[lo];
}
if(verbose && (g%50==0||g==GEN-1)){
double mc=0; long sc=0,sd=0; for(int i=0;i<NCOMP;i++){ mc+=cc[i]; int D=Dof(cc[i]); sc+=nC[i]; sd+=D; }
fprintf(stderr," gen %3d mean c=%.3f D=%d coop frac=%.3f\n",g,mc/NCOMP,Dof(mc/NCOMP),(double)sc/sd);
}
}
double mc=0; long sc=0,sd=0; for(int i=0;i<NCOMP;i++){ mc+=cc[i]; sc+=nC[i]; sd+=Dof(cc[i]); }
*coopf=(double)sc/sd; return mc/NCOMP;
}
int main(void){
printf("=== RUNG 3 -> 4 EMERGENCE: does compartmentalization evolve un-forced? ===\n");
printf(" trait c free to mutate up/down; D(c): c=0 -> D=%d (well-mixed), c=1 -> D=%d (compartmentalized)\n",DMAX,DMIN);
printf(" start c=0.10 (weak); parasite advantage %.0f%%\n\n",SADV*100);
fprintf(stderr," [c EVOLVABLE]\n");
RNG=0x9e3779b97f4a7c15ULL; double cf1; double c1=run(1,&cf1,1);
fprintf(stderr," [c FROZEN — control]\n");
RNG=0x9e3779b97f4a7c15ULL; double cf0; double c0=run(0,&cf0,1);
printf(" c EVOLVABLE : final mean c = %.3f (D=%d) cooperation frac = %.3f\n",c1,Dof(c1),cf1);
printf(" c FROZEN : final mean c = %.3f (D=%d) cooperation frac = %.3f\n",c0,Dof(c0),cf0);
printf("\n %s\n", (c1>0.4 && cf1>0.3)
? "=> compartmentalization EVOLVED UP on its own and rescued cooperation. Rung 4 EMERGED."
: "=> compartmentalization did not clearly emerge here — see trajectory / tune the world.");
printf(" (We supplied the option to compartmentalize; the world's parasite pressure selected it.)\n");
return 0;
}