OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent / polymer.c

110 lines · c ref:
/* polymer.c — rung 1->2 EMERGENCE attempt in a polymer soup (digital-analogy land).
 *
 * All prior models supplied the copier at the reproduction step. Here the copier is NOT supplied:
 * strands are binary sequences, 0 pairs 1 (complementarity), and the ONLY reproduction physics is
 * TEMPLATE-DIRECTED SYNTHESIS -- a template's bits are complemented with per-base fidelity f, mis-paired
 * otherwise. This is the pre-biotic given (uncatalyzed base-pairing), sequence-BLIND: it favors no
 * sequence, and replication of ANY strand's complement is generic (that is base-pairing, not a replicase).
 * The error rate EMERGES from mispairing; it is not a coded per-bit mutation.
 *
 * A random diverse soup + degradation + world-supplied selection for a FUNCTION (match a target motif,
 * replication rate proportional to fitness). MEASURED, not encoded: does a heritable FUNCTIONAL replicator
 * EMERGE from the random soup (mean match climbs 0.5 -> ~1), does it self-sustain against degradation, and
 * at what fidelity does it COLLAPSE? Sweep f at two lengths L to expose Eigen's paradox (longer function
 * needs higher fidelity, which un-catalyzed templating cannot supply -> the wall).
 *
 * A strand and its complement carry the same info: fitness is on the CANONICAL form min(s,~s), so S and ~S
 * are one functional unit. Nothing rewards a specific replicator identity; only the function, world-supplied.
 *
 * build:  cc -O2 -Wall -std=c11 -o polymer polymer.c -lm
 */
#include <math.h>
#include <stdio.h>
#include <stdint.h>

#define NMAX 800
#define D    0.30       /* per-step degradation (turnover that lets selection act) */
#define STEPS 140
#define SS   0.30       /* selection strength: fitness = exp(SS * #functional-positions-correct) */

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 L; static uint64_t MASK, FTAR_C;
static uint64_t canon(uint64_t s){ uint64_t c=(~s)&MASK; return s<c?s:c; }
static int matchC(uint64_t s){ return L - __builtin_popcountll(canon(s) ^ FTAR_C); }

static uint64_t pool[NMAX], nxt[NMAX];
static double fit[NMAX], cum[NMAX];

/* template-directed synthesis of the complement with per-base fidelity f (mispair otherwise). */
static uint64_t replicate(uint64_t tmpl, double f){
	uint64_t child=0;
	for(int i=0;i<L;i++){ int t=(int)((tmpl>>i)&1); int b=(urand()<f)?(1-t):t; if(b) child|=(1ULL<<i); }
	return child;
}

/* one run at length L, fidelity f. returns final mean functional match (fraction); writes start match. */
static double run(double f, double *start){
	MASK = (L>=64)?~0ULL:((1ULL<<L)-1);
	uint64_t ftar=0; for(int i=0;i<L;i++) if(urand()<0.5) ftar|=(1ULL<<i); FTAR_C=canon(ftar);
	for(int p=0;p<NMAX;p++){ uint64_t s=0; for(int i=0;i<L;i++) if(urand()<0.5) s|=(1ULL<<i); pool[p]=s; }

	double s0=0; for(int p=0;p<NMAX;p++) s0+=matchC(pool[p]); s0/=(double)NMAX*L; *start=s0;

	for(int g=0;g<STEPS;g++){
		/* degradation: survivors kept, compacted */
		int ns=0; for(int p=0;p<NMAX;p++) if(urand()>=D) pool[ns++]=pool[p];
		if(ns==0){ *start=s0; return 0.0; }                 /* extinction */
		double tot=0; for(int p=0;p<ns;p++){ fit[p]=exp(SS*matchC(pool[p])); tot+=fit[p]; cum[p]=tot; }
		/* refill empty slots by fitness-weighted TEMPLATE-DIRECTED replication (emergent copier) */
		int k=0; for(;k<ns;k++) nxt[k]=pool[k];
		while(k<NMAX){ double r=urand()*tot; int lo=0,hi=ns-1; while(lo<hi){int mid=(lo+hi)/2; if(cum[mid]<r)lo=mid+1; else hi=mid;} nxt[k++]=replicate(pool[lo],f); }
		for(int p=0;p<NMAX;p++) pool[p]=nxt[p];
	}
	double e=0; for(int p=0;p<NMAX;p++) e+=matchC(pool[p]); return e/((double)NMAX*L);
}

int main(void){
	unsigned long long seeds[]={0x9e3779b97f4a7c15ULL,0xd1b54a32d192ed03ULL,0x2545f4914f6cdd1dULL,0x123456789abcdefULL,0xfeedface12345678ULL};
	int NS=sizeof(seeds)/sizeof(seeds[0]);
	double fs[]={0.80,0.90,0.95,0.98,0.995}; int nF=sizeof(fs)/sizeof(double);
	int Ls[]={16,32}; int nL=sizeof(Ls)/sizeof(int);

	printf("=== rung 1->2 EMERGENCE attempt: template-directed polymer soup (digital) ===\n");
	printf("  Binary strands, 0<->1 pairing. ONLY physics = template-directed synthesis w/ fidelity f.\n");
	printf("  Random soup + degradation + selection for a function. Emergence = functional match 0.5 -> ~1.\n");
	printf("  pop=%d, degrade=%.2f, %d steps, %d seeds. Sweep f at L=%d,%d.\n\n",NMAX,D,STEPS,NS,Ls[0],Ls[1]);

	for(int li=0;li<nL;li++){
		L=Ls[li];
		printf("  --- L=%d (Eigen: need ~f > %.3f to hold) ---\n", L, 1.0-1.0/L);
		printf("    f     | func match (start->end) | emerged?\n");
		printf("    ------+-------------------------+---------\n");
		double thr=-1;
		for(int i=0;i<nF;i++){
			double se=0,ss=0;
			for(int s=0;s<NS;s++){ double st; RNG=seeds[s]; se+=run(fs[i],&st); ss+=st; }
			se/=NS; ss/=NS;
			int emerged = (se>0.85 && se>ss+0.2);
			if(emerged && thr<0) thr=fs[i];
			printf("    %.3f |     %.3f -> %.3f      | %s\n", fs[i], ss, se, emerged?"YES":"no");
		}
		printf("    => emergence threshold at L=%d: f* = %s%.3f\n\n", L, thr<0?">":"", thr<0?fs[nF-1]:thr);
	}
	printf("  HONEST READING (the data corrected my pre-registered guess):\n");
	printf("  * Copying is GENERIC (base-pairing) -- the population always self-sustains; that was never the wall.\n");
	printf("  * Heritable FUNCTION emerges only above a fidelity threshold (~f=0.98 here, i.e. <=2%% error),\n");
	printf("    and it emerges GRADUALLY: at un-catalyzed template fidelity (f~0.80-0.90, 10-20%% error) only\n");
	printf("    WEAK partial function appears (match ~0.6-0.7), not a strong replicator.\n");
	printf("  * The threshold did NOT rise with L -- because this functional landscape is ADDITIVE (per-site\n");
	printf("    selection), the forgiving 'relaxed error threshold' case (Kun-Szathmary). The value ~0.98\n");
	printf("    scales with selection strength; the STRUCTURE (a fidelity wall) is what is robust.\n");
	printf("  * THE WALL, reproduced from emergent copying physics: the fidelity needed to evolve a strong\n");
	printf("    functional replicator (>=0.98) EXCEEDS what un-catalyzed templating supplies (~0.85), and the\n");
	printf("    replicase that would close the gap is itself a functional sequence needing that fidelity\n");
	printf("    FIRST -- Eigen's bootstrap paradox. rung 1->2 does NOT cross from below at realistic fidelity.\n");
	return 0;
}