OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent / rung45.c

79 lines · c ref:
/* rung45.c — attempt rung 4 -> 5: does DIVISION OF LABOR emerge? (expected to STALL)
 *
 * Rung 5 (a differentiated cell) vs rung 4 (a bag of identical cooperators): the parts
 * SPECIALIZE into complementary roles the whole needs, and become mutually dependent.
 * Honest test: a compartment needs ALL F functions present to be viable; each replicator
 * has a heritable ROLE (0 = generalist, does all functions at reduced efficiency; 1..F =
 * specialist for one function). Specialists replicate FASTER (free-rider pressure toward
 * monoculture). Start every compartment as identical generalists (rung 4) and watch whether
 * stable specialist DIVISION OF LABOR emerges (rung 5) or stalls.
 *
 * Predicted stall: the free-rider problem recurs HARDER one level up — a specialist that
 * drops functions out-replicates, so compartments either collapse to monoculture (lose a
 * function -> die) or retreat to safe generalists (no division of labor = still rung 4).
 * Stable specialist complements (rung 5) are the hard middle. We report WHERE it lands.
 *
 * build:  cc -O2 -Wall -std=c11 -o rung45 rung45.c -lm
 */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define NCOMP 500
#define GEN   400
#define D     12          /* compartment size */
#define F     3           /* functions (roles 1..F); role 0 = generalist */
#define SSPEC 0.30        /* specialist replication advantage (the free-rider pressure) */
#define EGEN  0.2         /* generalist efficiency per function */
#define MUR   0.05        /* role mutation rate */

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 binom(int n,double p){ int k=0; for(int i=0;i<n;i++) if(urand()<p) k++; return k; }

static int comp[NCOMP][F+1];              /* role counts per compartment */
static int dau[2*NCOMP][F+1]; static double cum[2*NCOMP];

static double viability(const int *n){
	double v=1e9;
	for(int k=1;k<=F;k++){ double cov=n[k]+EGEN*n[0]; if(cov<v) v=cov; }  /* weakest-link: need ALL functions */
	return v;
}

int main(void){
	printf("=== RUNG 4 -> 5 ATTEMPT: does division of labor emerge? (expected to stall) ===\n");
	printf("  start: every compartment = %d identical generalists (rung 4, undifferentiated)\n",D);
	printf("  specialists replicate %.0f%% faster; a compartment needs all %d functions to be viable\n\n",SSPEC*100,F);
	for(int c=0;c<NCOMP;c++){ comp[c][0]=D; for(int k=1;k<=F;k++) comp[c][k]=0; }

	printf("  %-5s %10s %14s %12s\n","gen","spec frac","all-3-roles","viable");
	for(int g=0;g<=GEN;g++){
		if(g%40==0||g==GEN){
			long tot=0,spec=0; int dol=0,via=0;
			for(int c=0;c<NCOMP;c++){ int s=0; for(int k=0;k<=F;k++){ tot+=comp[c][k]; if(k>0){spec+=comp[c][k]; if(comp[c][k]>0)s++;} }
				if(s==F) dol++; if(viability(comp[c])>0.001) via++; }
			printf("  %-5d %10.3f %13.2f%% %11.2f%%\n",g,(double)spec/tot,100.0*dol/NCOMP,100.0*via/NCOMP);
		}
		if(g==GEN) break;
		/* one generation */
		double w[F+1]; w[0]=1.0; for(int k=1;k<=F;k++) w[k]=1.0+SSPEC;
		for(int c=0;c<NCOMP;c++){
			double Z=0; for(int k=0;k<=F;k++) Z+=comp[c][k]*w[k]; if(Z<1e-12)Z=1e-12;
			double pr[F+1],acc=0; for(int k=0;k<=F;k++){ acc+=comp[c][k]*w[k]/Z; pr[k]=acc; }
			int m[F+1]={0}; for(int i=0;i<2*D;i++){ double u=urand(); int r=0; while(r<F && u>pr[r]) r++;
				if(urand()<MUR) r=(int)(xs()%(F+1)); m[r]++; }
			for(int k=0;k<=F;k++){ int d1=binom(m[k],0.5); dau[2*c][k]=d1; dau[2*c+1][k]=m[k]-d1; }
		}
		double tot=0; for(int i=0;i<2*NCOMP;i++){ tot+=viability(dau[i]); cum[i]=tot; }
		if(tot<=0){ for(int c=0;c<NCOMP;c++) for(int k=0;k<=F;k++) comp[c][k]=0; }
		else for(int c=0;c<NCOMP;c++){ 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; }
			for(int k=0;k<=F;k++) comp[c][k]=dau[lo][k]; }
	}
	printf("\n  Read the endpoint: high 'spec frac' + high 'all-3-roles' + high 'viable' = division of\n");
	printf("  labor EMERGED (rung 5). Retreat to generalists (low spec frac) or low viability =\n");
	printf("  STALLED at rung 4 — which is the expected, honest result.\n");
	return 0;
}