OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent / templceil.c

118 lines · c ref:
/* templceil.c — find the TEMPLATED ceiling: push per-module copy error mu up until faithful
 * copying ALSO breaks. The companion to template.c.
 *
 * template.c held mu=0.02 fixed and swept genome size M: sampled collapsed (copy-number limit),
 * templated held. The claim was that templated copying is FIDELITY-limited, not copy-number-limited:
 * its ceiling is set by mu (~Eigen error threshold, 1/mu units), and is ~INDEPENDENT of M. This tests
 * that directly: sweep mu at FIXED M, and repeat at a second M to check the ceiling is the same.
 *
 * Predictions:
 *   - heredity signal decays smoothly with mu, -> ~0 as mu -> 0.5 (bits randomize);
 *   - selection on module-0 is HELD at low mu and LOST past a threshold mu* (the error catastrophe
 *     for the master module: mutation pressure overwhelms selection);
 *   - mu* is ~the SAME at M=10 and M=20 (fidelity-set, not copy-number-set) -- the contrast with
 *     sampling, whose collapse was M-driven.
 *
 * Same chemistry/pockets/selection/growth as template.c; only mu (a runtime global) and M vary.
 * Templated reproduction only. Honesty: the copy primitive is target-blind (copies the parent, per
 * module, flip prob mu both directions); selection favors module-0 separately; the ceiling is measured.
 *
 * build:  cc -O2 -Wall -std=c11 -o templceil templceil.c -lm
 */
#include <math.h>
#include <stdio.h>
#include <string.h>

#define MAXM 24
#define K    4
#define MAXN (MAXM*K)
#define S    200
#define POCK 150
#define GEN  40
#define MAT  800
#define RHO0 0.10

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 M, N;
static double g_mu;
static double beta[MAXN][MAXN], rate[MAXN];
static void build_chem(void){ for(int i=0;i<N;i++)for(int j=0;j<N;j++) beta[i][j] = (i!=j && i/K==j/K) ? exp(0.4*randn())*1.2 : 0.0; }
static void recompute(const int*n){ for(int i=0;i<N;i++){ double r=RHO0; for(int j=0;j<N;j++) r+=beta[i][j]*n[j]; rate[i]=r; } }
static int pick_add(void){ double t=0; for(int i=0;i<N;i++)t+=rate[i]; double u=urand()*t,a=0; for(int i=0;i<N;i++){a+=rate[i];if(u<=a)return i;} return N-1; }
static int pick_rem(const int*n,int sz){ double u=urand()*sz,a=0; for(int j=0;j<N;j++){a+=n[j];if(u<=a)return j;} return N-1; }
static void addm(int*n,int i){ n[i]++; for(int k=0;k<N;k++) rate[k]+=beta[k][i]; }
static void remm(int*n,int j){ n[j]--; for(int k=0;k<N;k++) rate[k]-=beta[k][j]; }
static void mature(int*n,int sz){ recompute(n); for(int t=0;t<MAT;t++){ int j=pick_rem(n,sz); remm(n,j); addm(n,pick_add()); } }
static void grow_to(int*n,int*sz,int tgt){ recompute(n); while(*sz<tgt){ addm(n,pick_add()); (*sz)++; } }
static int thresh(void){ return S/(2*M); }
static void genome(const int*n,int*g){ int th=thresh(); for(int m=0;m<M;m++){ int s=0; for(int t=m*K;t<(m+1)*K;t++) s+=n[t]; g[m]=(s>th); } }
static double bitmatch(const int*ga,const int*gb){ int e=0; for(int m=0;m<M;m++) if(ga[m]==gb[m]) e++; return (double)e/M; }

static int pk[POCK][MAXN], nxt[POCK][MAXN];
static double fit[POCK], cum[POCK];

/* templated run at the current M and g_mu. returns heredity signal; writes selection start/end. */
static double run(double *f_start, double *f_end)
{
	for(int p=0;p<POCK;p++){ memset(pk[p],0,sizeof pk[p]); int present[MAXM],np=0;
		for(int m=0;m<M;m++){present[m]=(urand()<0.5); if(present[m])np++;} if(np==0){present[0]=1;np=1;}
		for(int s=0;s<S;s++){ int m; do{ m=(int)(xs()%M); }while(!present[m]); pk[p][m*K+(int)(xs()%K)]++; }
		mature(pk[p],S); }

	double dig=0; int hc=0; double tgt_start=0,tgt_end=0;
	for(int g=0;g<GEN;g++){
		double tot=0; for(int p=0;p<POCK;p++){ int gp[MAXM]; genome(pk[p],gp); fit[p]=0.3+(gp[0]?1.0:0.0); tot+=fit[p]; cum[p]=tot; }
		if(g==1){ double f=0; for(int p=0;p<POCK;p++){int gp[MAXM];genome(pk[p],gp);f+=gp[0];} tgt_start=f/POCK; }
		for(int p=0;p<POCK;p++){
			double r=urand()*tot; int lo=0,hi=POCK-1; while(lo<hi){int mid=(lo+hi)/2; if(cum[mid]<r)lo=mid+1; else hi=mid;} int par=lo;
			int D[MAXN]; memset(D,0,sizeof D); int ds=0;
			int gpar[MAXM]; genome(pk[par],gpar);
			for(int m=0;m<M;m++){ int bit=gpar[m]; if(urand()<g_mu) bit^=1;   /* templated copy, per-unit flip both ways */
				if(bit){ for(int t=m*K;t<(m+1)*K;t++){ D[t]++; ds++; } } }
			if(ds<1){ for(int t=0;t<K;t++){D[t]++;ds++;} }
			grow_to(D,&ds,S); mature(D,S);
			memcpy(nxt[p],D,sizeof D);
			if(g>GEN/2){ int rp=(int)(xs()%POCK); int gd[MAXM],gp2[MAXM],grn[MAXM]; genome(D,gd); genome(pk[par],gp2); genome(pk[rp],grn);
				dig += bitmatch(gd,gp2)-bitmatch(gd,grn); hc++; }
		}
		memcpy(pk,nxt,sizeof pk);
	}
	{ double f=0; for(int p=0;p<POCK;p++){int gp[MAXM];genome(pk[p],gp);f+=gp[0];} tgt_end=f/POCK; }
	*f_start=tgt_start; *f_end=tgt_end;
	return hc?dig/hc:0;
}

int main(void){
	double mus[]={0.02,0.05,0.10,0.15,0.20,0.30,0.40,0.50}; int nMU=sizeof(mus)/sizeof(double);
	int Ms[]={10,20}; int nMs=sizeof(Ms)/sizeof(int);

	printf("=== TEMPLATED ceiling: sweep per-module copy error mu (fidelity limit / Eigen threshold) ===\n");
	printf("  Templated copy, fixed budget S=%d. Ceiling defined here: heredity>0.10 AND selDelta>+0.03.\n",S);
	printf("  Prediction: ceiling set by mu (~1/mu units), ~INDEPENDENT of M (unlike sampling).\n\n");

	for(int mj=0;mj<nMs;mj++){
		M=Ms[mj]; N=M*K;
		printf("  --- M=%d (tokens/module=%d) ---\n",M,S/M);
		printf("    mu   | heredity | sel(start->end)  | held?\n");
		printf("    -----+----------+------------------+------\n");
		double ceil_mu=0;
		for(int i=0;i<nMU;i++){
			g_mu=mus[i];
			RNG=0x9e3779b97f4a7c15ULL; build_chem();   /* same seed+chem per point */
			double s0,s1; double h=run(&s0,&s1); double d=s1-s0;
			int held = (h>0.10 && d>0.03);
			if(held) ceil_mu=mus[i];
			printf("    %.2f |  %+.3f  | %.2f->%.2f (%+.3f) | %s\n", mus[i], h, s0,s1, d, held?"yes":"NO");
		}
		printf("    => templated ceiling at M=%d: mu* = %.2f (last mu that held heredity+selection)\n\n",M,ceil_mu);
	}
	printf("  Read the two mu* values: if they AGREE, the templated ceiling is fidelity-set (mu), not\n");
	printf("  copy-number-set (M) -- confirming templated copying is Eigen/fidelity-limited. If the M=20\n");
	printf("  ceiling is much lower than M=10, then even templated copy is partly copy-number-limited here.\n");
	return 0;
}