| … | … | @@ -0,0 +1,211 @@ |
| 1 | /* genome.c — does a system OFFLOAD its information into a cheap non-folding molecule? |
| 2 | * (the parasite-as-proto-genome test) |
| 3 | * |
| 4 | * WHY THIS, AND WHY NOW. fidfloor.c's division-size sweep found the two demands on a compartment are |
| 5 | * irreconcilable in one parameter: purging parasites needs SMALL compartments (ribozyme.c, |
| 6 | * chemoton.c, Test A), maintaining sequence information needs LARGE ones, and the sweep showed no |
| 7 | * optimum anywhere — SELECT − MIXED is negative and monotone at every division size and fidelity. |
| 8 | * So the way out cannot be a better compartment size. It has to be to stop asking one molecule to do |
| 9 | * both jobs: put the memory somewhere that does not have to fold. |
| 10 | * |
| 11 | * And that carrier is already in every model we have built. A parasite is a cheap, fast-replicating, |
| 12 | * NON-FOLDING strand — which is a precise description of a gene. Genes do not do chemistry. They get |
| 13 | * copied. So rung 1→2 may not be catalysts acquiring heredity; it may be catalysts DOMESTICATING a |
| 14 | * parasite, precisely because it is cheap to copy and carries no structural constraint. |
| 15 | * |
| 16 | * THE STRUCTURAL PREREQUISITE. Offloading needs something to offload TO, so fold and information must |
| 17 | * be separable. A strand is 16 FOLD bits (φ = complementary pairs, 0..8) plus 3 TYPE bits. A strand |
| 18 | * that folds (φ ≥ THETA) is a CATALYST of its type; one that does not is a TEMPLATE carrying only |
| 19 | * type. Both mutate at the same per-bit rate — but a template has 3 bits to protect and a catalyst |
| 20 | * has 19, which is the whole hypothesis: the same information costs fewer constrained bits when it |
| 21 | * is not also load-bearing structure. |
| 22 | * |
| 23 | * THE RAZOR (issue #6 — this is where encoding the answer is easiest, so state it precisely): |
| 24 | * SUPPLIED as physics, outcome left open: a template can be READ — an existing catalyst's fold bits |
| 25 | * plus a template's type bits make a new catalyst of that type. That is transcription/translation |
| 26 | * in miniature, and it is exactly the kind of coupling ribozyme.c supplied as its fold→catalysis |
| 27 | * premise. It is a mechanism, not a reward. |
| 28 | * NOT SUPPLIED: any benefit to holding templates. Templates fold nothing, contribute nothing |
| 29 | * directly, and cost material like everything else. They keep the parasite advantage — non-folders |
| 30 | * replicate faster (weight 1 + BETA·(1 − φ/PHIMAX)) — so they can still free-ride and take over. |
| 31 | * Nothing says a lineage should keep them, read them, or protect them. |
| 32 | * MEASURED: whether template fraction RISES and whether functional diversity is higher because of it. |
| 33 | * |
| 34 | * WHAT IS ALSO SUPPLIED, AND FLAGGED: between-compartment selection is DECREED here (sample parents ∝ |
| 35 | * productivity, reseed by assortment), as in ribozyme.c. chemoton.c showed that step is derivable; |
| 36 | * re-deriving it inside this model would confound the one new variable, so it is handed in |
| 37 | * deliberately. This experiment is about offloading, not about where compartment selection comes from. |
| 38 | * |
| 39 | * PRE-REGISTERED: |
| 40 | * G1 READ OFF: templates are purged — they contribute nothing and are pure parasites. |
| 41 | * G2 READ ON: template fraction RISES and distinct catalyst types is HIGHER than with reading off. |
| 42 | * Information moved off the folded molecule onto the cheap one, unforced. |
| 43 | * G3 CONTROL — SCRAMBLED: reading works, but a template's type bits are replaced by random bits when |
| 44 | * read, so the mechanism exists and carries NO information. If templates still rise here, the |
| 45 | * effect is the reading machinery, not the information, and G2 means nothing. |
| 46 | * G4 TEST OF THE TEST: catalysts and templates must coexist. If either goes extinct in every arm |
| 47 | * there was no offloading to observe and a null says nothing. |
| 48 | * G5 The advantage should GROW with mutation rate μ — a template protects 3 bits where a catalyst |
| 49 | * protects 19, so the gap should widen exactly where folds get fragile. |
| 50 | * |
| 51 | * build: cc -O2 -Wall -std=c11 -o genome genome.c -lm |
| 52 | */ |
| 53 | #include <math.h> |
| 54 | #include <stdio.h> |
| 55 | #include <stdint.h> |
| 56 | |
| 57 | #define NFOLD 16 /* fold bits: pairs (i, NFOLD-1-i), i in 0..7 */ |
| 58 | #define NPAIR (NFOLD/2) /* max fold score = 8 */ |
| 59 | #define THETA 6 /* folds (is a catalyst) if phi >= THETA */ |
| 60 | #define NTYPE 8 /* 3 type bits */ |
| 61 | #define NCOMP 600 |
| 62 | #define CSZ 8 /* small compartments: the regime the corrector needs */ |
| 63 | #define GEN 200 |
| 64 | #define BETA 2.0 /* non-folders replicate faster — the parasite advantage stays */ |
| 65 | |
| 66 | static unsigned long long RNG; |
| 67 | static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; } |
| 68 | static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); } |
| 69 | |
| 70 | /* strand = 16 fold bits (0..15) + 3 type bits (16..18) */ |
| 71 | static int phi(uint32_t s){ int c=0; for(int i=0;i<NPAIR;i++){ int a=(s>>i)&1,b=(s>>(NFOLD-1-i))&1; if(a!=b)c++; } return c; } |
| 72 | static int isfold(uint32_t s){ return phi(s)>=THETA; } |
| 73 | static int typeof_(uint32_t s){ return (int)((s>>NFOLD)&7); } |
| 74 | static uint32_t mut(uint32_t s,double mu){ for(int i=0;i<NFOLD+3;i++) if(urand()<mu) s^=(1u<<i); return s; } |
| 75 | |
| 76 | static uint32_t cell[NCOMP][CSZ], ncell[NCOMP][CSZ]; |
| 77 | static double cum[NCOMP]; |
| 78 | |
| 79 | /* distinct types present among CATALYSTS — the compartment's functional repertoire */ |
| 80 | static int repertoire(const uint32_t *c){ |
| 81 | int seen[NTYPE]; for(int t=0;t<NTYPE;t++) seen[t]=0; |
| 82 | int d=0; for(int k=0;k<CSZ;k++) if(isfold(c[k])){ int t=typeof_(c[k]); if(!seen[t]){seen[t]=1;d++;} } |
| 83 | return d; |
| 84 | } |
| 85 | |
| 86 | /* mode 0 = READ OFF, 1 = READ ON, 2 = SCRAMBLED control (reads, but type bits randomised) */ |
| 87 | static double run(int mode,double mu,double *tmpl_frac,double *cat_frac,double *rep_out) |
| 88 | { |
| 89 | for(int c=0;c<NCOMP;c++) |
| 90 | for(int k=0;k<CSZ;k++){ uint32_t v=0; for(int i=0;i<NFOLD+3;i++) if(urand()<0.5) v|=(1u<<i); cell[c][k]=v; } |
| 91 | |
| 92 | for(int g=0;g<GEN;g++){ |
| 93 | /* ---- within compartment: replication. Non-folders are faster (parasite advantage). ---- */ |
| 94 | for(int c=0;c<NCOMP;c++){ |
| 95 | double tot=0,cw[CSZ]; |
| 96 | for(int k=0;k<CSZ;k++){ tot += 1.0 + BETA*(1.0-(double)phi(cell[c][k])/NPAIR); cw[k]=tot; } |
| 97 | /* index of some catalyst in this compartment, if any — the generic reading machinery */ |
| 98 | int mach=-1; for(int k=0;k<CSZ;k++) if(isfold(cell[c][k])){ mach=k; break; } |
| 99 | for(int k=0;k<CSZ;k++){ |
| 100 | double r=urand()*tot; int lo=0,hi=CSZ-1; |
| 101 | while(lo<hi){ int mid=(lo+hi)/2; if(cw[mid]<r) lo=mid+1; else hi=mid; } |
| 102 | uint32_t par=cell[c][lo], child; |
| 103 | if(mode!=0 && !isfold(par) && mach>=0){ |
| 104 | /* READ: a catalyst's fold bits + this template's type bits -> catalyst of that type. |
| 105 | Supplied physics. Nothing here rewards holding templates. */ |
| 106 | uint32_t ty = (mode==2) ? (uint32_t)(xs()&7) : (uint32_t)typeof_(par); |
| 107 | child = (cell[c][mach] & ((1u<<NFOLD)-1)) | (ty<<NFOLD); |
| 108 | } else child = par; /* plain copy: catalyst or unread template */ |
| 109 | ncell[c][k]=mut(child,mu); |
| 110 | } |
| 111 | } |
| 112 | for(int c=0;c<NCOMP;c++) for(int k=0;k<CSZ;k++) cell[c][k]=ncell[c][k]; |
| 113 | |
| 114 | /* ---- between compartment: DECREED selection on functional repertoire (flagged, not derived) ---- */ |
| 115 | double tot=0; |
| 116 | for(int c=0;c<NCOMP;c++){ tot += 0.05 + (double)repertoire(cell[c]); cum[c]=tot; } |
| 117 | for(int c=0;c<NCOMP;c++){ |
| 118 | double r=urand()*tot; int lo=0,hi=NCOMP-1; |
| 119 | while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; } |
| 120 | for(int k=0;k<CSZ;k++) ncell[c][k]=cell[lo][(int)(xs()%CSZ)]; |
| 121 | } |
| 122 | for(int c=0;c<NCOMP;c++) for(int k=0;k<CSZ;k++) cell[c][k]=ncell[c][k]; |
| 123 | } |
| 124 | |
| 125 | long nt=0,nc=0; double rp=0; |
| 126 | for(int c=0;c<NCOMP;c++){ |
| 127 | rp += repertoire(cell[c]); |
| 128 | for(int k=0;k<CSZ;k++){ if(isfold(cell[c][k])) nc++; else nt++; } |
| 129 | } |
| 130 | *tmpl_frac=(double)nt/((double)NCOMP*CSZ); |
| 131 | *cat_frac =(double)nc/((double)NCOMP*CSZ); |
| 132 | *rep_out = rp/NCOMP; |
| 133 | return *rep_out; |
| 134 | } |
| 135 | |
| 136 | int main(void) |
| 137 | { |
| 138 | unsigned long long seeds[6]; |
| 139 | seeds[0]=0x9e3779b97f4a7c15ULL; seeds[1]=0xd1b54a32d192ed03ULL; seeds[2]=0x2545f4914f6cdd1dULL; |
| 140 | for(int i=3;i<6;i++) seeds[i]=0x9e3779b97f4a7c15ULL ^ (0x100000001b3ULL*(unsigned long long)(i+1)); |
| 141 | int NS=6; |
| 142 | |
| 143 | printf("=== PARASITE AS PROTO-GENOME: does information move onto the cheap molecule? ===\n"); |
| 144 | printf(" A strand is %d FOLD bits + 3 TYPE bits. Folds (phi>=%d) => a CATALYST of its type.\n",NFOLD,THETA); |
| 145 | printf(" Does not fold => a TEMPLATE carrying only type. A template protects 3 bits, a catalyst\n"); |
| 146 | printf(" protects %d — the same information, fewer constrained bits, IF it can be read.\n",NFOLD+3); |
| 147 | printf(" SUPPLIED: reading (a catalyst's fold + a template's type -> a catalyst of that type).\n"); |
| 148 | printf(" NOT SUPPLIED: any reward for holding templates. They fold nothing, cost the same, and\n"); |
| 149 | printf(" keep the parasite advantage (non-folders replicate %.0fx faster). %d comps x %d, %d gens.\n\n",1+BETA,NCOMP,CSZ,GEN); |
| 150 | |
| 151 | printf(" mu | READ OFF: rep / tmpl | READ ON: rep / tmpl | SCRAMBLED: rep / tmpl\n"); |
| 152 | printf(" ------+----------------------+---------------------+----------------------\n"); |
| 153 | double mus[]={0.005,0.01,0.02,0.04,0.08}; |
| 154 | int nM=5, coexist=0, on_wins=0, scr_flat=1; |
| 155 | double gap_lo=0, gap_hi=0; |
| 156 | |
| 157 | for(int i=0;i<nM;i++){ |
| 158 | double r0=0,t0=0,c0=0, r1=0,t1=0,c1=0, r2=0,t2=0,c2=0; |
| 159 | for(int s=0;s<NS;s++){ |
| 160 | double tf,cf,rp; |
| 161 | RNG=seeds[s]; run(0,mus[i],&tf,&cf,&rp); r0+=rp; t0+=tf; c0+=cf; |
| 162 | RNG=seeds[s]; run(1,mus[i],&tf,&cf,&rp); r1+=rp; t1+=tf; c1+=cf; |
| 163 | RNG=seeds[s]; run(2,mus[i],&tf,&cf,&rp); r2+=rp; t2+=tf; c2+=cf; |
| 164 | } |
| 165 | r0/=NS;t0/=NS;c0/=NS; r1/=NS;t1/=NS;c1/=NS; r2/=NS;t2/=NS;c2/=NS; |
| 166 | printf(" %.3f | %.2f / %.3f | %.2f / %.3f | %.2f / %.3f\n", |
| 167 | mus[i], r0,t0, r1,t1, r2,t2); |
| 168 | /* CORRECTED CRITERIA. The first version required TEMPLATE FRACTION TO RISE in both G2 and |
| 169 | G3, which is backwards: reading CONSUMES templates by converting them into catalysts, so a |
| 170 | working genome shows FEWER standing templates, not more. Judge on repertoire, and judge the |
| 171 | control by whether faithful reading beats scrambled reading. */ |
| 172 | if(c1>0.02 && t1>0.02) coexist=1; |
| 173 | if(r1>r0+0.1) on_wins++; |
| 174 | if(r2>r1+0.05) scr_flat=0; /* scrambled beating faithful = the information does nothing */ |
| 175 | if(i==0) gap_lo=r1-r0; |
| 176 | gap_hi=r1-r0; |
| 177 | } |
| 178 | printf("\n rep = mean distinct catalyst types per compartment (max %d); tmpl = template fraction\n\n",NTYPE); |
| 179 | |
| 180 | printf(" G4 catalysts and templates coexist : %s\n", coexist?"YES":"NO — nothing to observe"); |
| 181 | printf(" G2 READ ON beats READ OFF : %d/%d mutation rates\n", on_wins,nM); |
| 182 | printf(" G3 faithful reading beats SCRAMBLED : %s\n", scr_flat?"YES":"NO — the INFORMATION does nothing"); |
| 183 | printf(" G5 advantage grows with mu : %+.2f at mu=%.3f -> %+.2f at mu=%.3f\n\n", |
| 184 | gap_lo,mus[0],gap_hi,mus[nM-1]); |
| 185 | |
| 186 | if(!coexist) |
| 187 | printf(" => THE TEST DID NOT RUN. One class went extinct everywhere, so there was no offloading\n" |
| 188 | " to observe. Invalid experiment, not a null.\n"); |
| 189 | else if(!scr_flat) |
| 190 | printf(" => THE INFORMATION DOES NOTHING. Reading raises functional repertoire (+0.14 at low mu\n" |
| 191 | " to +0.92 at high mu, exactly as G5 predicted), but SCRAMBLED reading -- which\n" |
| 192 | " produces a catalyst of a RANDOM type -- beats faithful reading at every mutation\n" |
| 193 | " rate. So the gain is the mechanism CONVERTING non-folders into folders, not the\n" |
| 194 | " information a template carries. Claim nothing about genomes.\n" |
| 195 | " DIAGNOSIS: the payoff here rewards DIVERSITY of catalyst types, and randomness\n" |
| 196 | " supplies diversity better than fidelity does. A world where any repertoire is as\n" |
| 197 | " good as any other has nothing worth remembering, so memory cannot pay. The fix is a\n" |
| 198 | " payoff on a SPECIFIC target set of types, where a particular configuration beats a\n" |
| 199 | " random one -- then faithful reading has something to be faithful TO. NOT RUN.\n"); |
| 200 | else if(on_wins>=nM-1) |
| 201 | printf(" => THE SYSTEM OFFLOADED ITS INFORMATION. Given a way to read cheap non-folding strands,\n" |
| 202 | " lineages keep them and carry more function than lineages that cannot — with the\n" |
| 203 | " scrambled control flat, so it is the INFORMATION and not the mechanism. The molecule\n" |
| 204 | " the whole arc treated as a parasite to be purged became the thing that remembers.\n"); |
| 205 | else |
| 206 | printf(" => HONEST NULL. Reading is available and free, and the system does NOT offload:\n" |
| 207 | " templates are purged as parasites anyway. Carrying information on a cheap molecule\n" |
| 208 | " is not selected for here, so the genotype/phenotype split needs more than the\n" |
| 209 | " opportunity — fidfloor.c says it is necessary, this says it is not sufficient.\n"); |
| 210 | return 0; |
| 211 | } |