/* rung3.c — the sequence replicator: the SHARP error catastrophe, and the ignition
* of open-ended evolution. Built on rung 2 (templating) but forms are now SEQUENCES.
*
* Rung 2's fidelity erosion was SMOOTH (few forms). Make the form a length-L sequence
* (2^L of them) with a single fittest "master" sequence (fitness sigma, all others 1),
* and rung 2's soft requirement becomes Eigen's SHARP ERROR CATASTROPHE — a real phase
* transition at a critical per-site mutation rate mu_c ~ ln(sigma)/L:
* mu < mu_c : population LOCALIZES on the master (heredity of a large information store
* = the genome; the stable substrate the "directed read" needs)
* mu > mu_c : population DELOCALIZES over sequence space (information lost)
*
* Exact deterministic quasispecies over Hamming-distance classes k=0..L (fitness and
* mutation are permutation-symmetric, so classes suffice). Class transition is a
* binomial convolution: a parent at distance j has j "wrong" and L-j "right" sites;
* offspring distance i = j - (corrected) + (newly wrong).
*
* This is the rung where heredity+variation+selection over a vast form-space becomes
* open-ended evolution — the point from which the ladder builds ITSELF (rung 3, stabilized
* by rung 4). Contrast the SHARP drop here with rung 2's smooth curve.
*
* build: cc -O2 -Wall -std=c11 -o rung3 rung3.c -lm
*/
#include <math.h>
#include <stdio.h>
#define L 20 /* sequence length -> 2^L forms */
#define SIGMA 10.0 /* master-sequence fitness advantage */
static double binom[L+1][L+1];
static void init_binom(void){
for(int n=0;n<=L;n++){ binom[n][0]=1; for(int k=1;k<=n;k++) binom[n][k]=binom[n-1][k-1]+(k<=n-1?binom[n-1][k]:0); }
}
/* T[i][j] = P(offspring in class i | parent in class j), per-site mutation mu */
static void build_T(double T[L+1][L+1],double mu){
for(int i=0;i<=L;i++)for(int j=0;j<=L;j++) T[i][j]=0;
for(int j=0;j<=L;j++){
for(int c=0;c<=j;c++){ /* c of the j wrong sites corrected */
double pc=binom[j][c]*pow(mu,c)*pow(1-mu,j-c);
for(int w=0;w<=L-j;w++){ /* w of the L-j right sites newly wrong */
double pw=binom[L-j][w]*pow(mu,w)*pow(1-mu,L-j-w);
int i=j-c+w; T[i][j]+=pc*pw;
}
}
}
}
int main(void){
init_binom();
double f[L+1]; f[0]=SIGMA; for(int k=1;k<=L;k++) f[k]=1.0;
double mu_c=log(SIGMA)/L;
printf("=== RUNG 3: SEQUENCE REPLICATOR — the SHARP error catastrophe ===\n");
printf(" L=%d (2^%d forms), master fitness sigma=%.0f; predicted mu_c ~ ln(sigma)/L = %.4f\n\n",L,L,SIGMA,mu_c);
printf(" %-7s %12s %12s\n","mu","master frac","mean dist");
for(int mi=0;mi<=24;mi++){
double mu=mi*0.01;
double T[L+1][L+1]; build_T(T,mu);
double y[L+1]; for(int k=0;k<=L;k++) y[k]=1.0/(L+1);
for(int it=0;it<4000;it++){
double ny[L+1],tot=0;
for(int i=0;i<=L;i++){ ny[i]=0; for(int j=0;j<=L;j++) ny[i]+=T[i][j]*f[j]*y[j]; tot+=ny[i]; }
if(tot<1e-300)tot=1e-300;
for(int i=0;i<=L;i++) y[i]=ny[i]/tot;
}
double md=0; for(int k=0;k<=L;k++) md+=k*y[k];
int bar=(int)(y[0]*40+0.5); char b[64]; for(int k=0;k<bar&&k<50;k++)b[k]='#'; b[bar<50?bar:50]=0;
printf(" %-7.2f %12.3f %12.2f %s%s\n",mu,y[0],md,b,(mi>0 && fabs(mu-mu_c)<0.005)?" <- mu_c":"");
}
printf("\n SHARP transition near mu_c=%.3f: below it the population localizes on the master\n",mu_c);
printf(" (a length-%d information store is inherited); above it, delocalization (mean dist\n",L);
printf(" -> L/2=%.0f, information lost). This is the error catastrophe — the sharp version of\n",L/2.0);
printf(" rung 2's smooth curve, and the substrate on which open-ended evolution ignites.\n");
return 0;
}