OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent / gardenv.c

101 lines · c ref:
/* 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;
}