/* 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;
}