/* gardenv.c — ENVIRONMENTAL compartments for rung 1->2 (digital, not organic).
*
* gard.c (one self-splitting assembly) gave a NULL: the autocatalytic dynamics converged to a
* single chemistry-determined attractor, so composition wasn't transmitted. The research says the
* fix is not a self-made membrane but ENVIRONMENTAL compartmentalization — many pockets the WORLD
* supplies (mineral pores / transient droplets), with between-pocket selection. It restores
* SELECTABILITY; it does not by itself create heritable variation.
*
* Digital analogy (NO chemistry): tokens 0..N-1; a catalysis matrix beta[i][j] (present token j
* promotes entry of token i); a pocket = a composition vector. TWO conditions the literature says
* are necessary and that gard lacked:
* (a) EXCESS MUTUAL catalysis (cross > self; beta[i][i]=0) so MULTIPLE attractors can exist
* — I supply the substrate condition; the attractors (composomes) still arise on their own.
* (b) MANY environmental pockets + between-pocket selection + split/regrow (the world's compartments).
* Then MEASURE (not encode): are distinct composomes maintained? is composition transmitted across
* the pocket cycle (daughter ~ parent >> random)? can an external selection preference shift the
* population and make it stick (heritable adaptation)?
*
* Honest prior: environmental compartments should restore SOME selectability/transmission that the
* single assembly lacked, but heredity stays LIMITED (few composomes) — not open-ended. Report it.
*
* build: cc -O2 -Wall -std=c11 -o gardenv gardenv.c -lm
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#define N 40
#define S 150
#define POCK 200
#define GEN 60
#define MAT 1500
#define PCAT 0.15
#define RHO0 0.4
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 double beta[N][N], rate[N];
static void build_chem(void){ for(int i=0;i<N;i++)for(int j=0;j<N;j++) beta[i][j]=(i!=j&&urand()<PCAT)? exp(1.8*randn())*0.30 : 0.0; } /* EXCESS MUTUAL: no self-catalysis */
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 double cosv(const int*a,const int*b){ double d=0,na=0,nb=0; for(int i=0;i<N;i++){ d+=(double)a[i]*b[i]; na+=(double)a[i]*a[i]; nb+=(double)b[i]*b[i]; } if(na<=0||nb<=0)return 0; return d/(sqrt(na)*sqrt(nb)); }
static int pk[POCK][N], nxt[POCK][N];
static double fit[POCK], cum[POCK];
/* run POCK environmental pockets for GEN generations. select_on: favor target tokens 0..3. */
static void run(int select_on,double *hered_out,double *sel_start,double *sel_end,int *composomes){
for(int p=0;p<POCK;p++){ memset(pk[p],0,sizeof pk[p]); for(int s=0;s<S;s++) pk[p][(int)(xs()%N)]++; mature(pk[p],S); }
double heredity=0; int hcount=0;
for(int g=0;g<GEN;g++){
double tot=0; for(int p=0;p<POCK;p++){ int tgt=pk[p][0]+pk[p][1]+pk[p][2]+pk[p][3]; fit[p]= select_on? (0.01+(double)tgt/S) : 1.0; tot+=fit[p]; cum[p]=tot; }
if(g==1){ double m=0; for(int p=0;p<POCK;p++) m+=(double)(pk[p][0]+pk[p][1]+pk[p][2]+pk[p][3])/S; *sel_start=m/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[N]; memset(D,0,sizeof D); int ds=0; /* split: each token -> daughter w.p. 0.5 */
for(int i=0;i<N;i++) for(int c=0;c<pk[par][i];c++) if(urand()<0.5){ D[i]++; ds++; }
if(ds<1){D[0]=1;ds=1;}
grow_to(D,&ds,S); mature(D,S); /* regrow in the (world-supplied) pocket */
memcpy(nxt[p],D,sizeof D);
if(g>GEN/2){ int rp=(int)(xs()%POCK); heredity += cosv(D,pk[par]) - cosv(D,pk[rp]); hcount++; }
}
memcpy(pk,nxt,sizeof pk);
}
double m=0; for(int p=0;p<POCK;p++) m+=(double)(pk[p][0]+pk[p][1]+pk[p][2]+pk[p][3])/S; *sel_end=m/POCK;
/* count distinct composomes */
int nc=0,rep[POCK]; for(int p=0;p<POCK;p++){ int f=0; for(int c=0;c<nc;c++) if(cosv(pk[p],pk[rep[c]])>0.85){f=1;break;} if(!f&&nc<POCK) rep[nc++]=p; }
*hered_out = hcount? heredity/hcount : 0; *composomes=nc;
}
int main(void){
RNG=0x9e3779b97f4a7c15ULL; build_chem();
printf("=== ENVIRONMENTAL COMPARTMENTS for rung 1->2 (digital; excess mutual catalysis) ===\n");
printf(" %d pockets the environment supplies; between-pocket selection + split/regrow.\n",POCK);
printf(" gard (ONE self-splitting assembly) gave heredity signal ~0 (single attractor).\n\n");
double h0,ss0,se0; int c0; run(0,&h0,&ss0,&se0,&c0);
double h1,ss1,se1; int c1; run(1,&h1,&ss1,&se1,&c1);
printf(" SELECTION OFF (drift): heredity signal %+.3f | distinct composomes %d\n",h0,c0);
printf(" SELECTION ON (favor tokens 0-3): heredity signal %+.3f | composomes %d\n",h1,c1);
printf(" target-token fraction start %.3f -> end %.3f (%+.3f = selectable adaptation?)\n",ss1,se1,se1-ss1);
printf("\n heredity signal = cosine(daughter,parent) - cosine(daughter,random). >0.1 = composition\n");
printf(" TRANSMITTED across the environmental-pocket cycle (heredity that the single assembly lacked).\n");
if(h0>0.1 && se1-ss1>0.05)
printf(" => environmental compartments RESTORED transmission AND selectability. Limited (%d composomes),\n not open-ended — but the container the WORLD supplies unblocks what the lone assembly could not.\n",c1);
else if(h0>0.05 || se1-ss1>0.03)
printf(" => PARTIAL: some transmission/selectability restored, but weak/limited (matches the literature).\n");
else
printf(" => still NULL: environmental compartments alone did not restore heredity here (single attractor persists).\n");
return 0;
}