| … | … | @@ -0,0 +1,109 @@ |
| 1 | /* polymer.c — rung 1->2 EMERGENCE attempt in a polymer soup (digital-analogy land). |
| 2 | * |
| 3 | * All prior models supplied the copier at the reproduction step. Here the copier is NOT supplied: |
| 4 | * strands are binary sequences, 0 pairs 1 (complementarity), and the ONLY reproduction physics is |
| 5 | * TEMPLATE-DIRECTED SYNTHESIS -- a template's bits are complemented with per-base fidelity f, mis-paired |
| 6 | * otherwise. This is the pre-biotic given (uncatalyzed base-pairing), sequence-BLIND: it favors no |
| 7 | * sequence, and replication of ANY strand's complement is generic (that is base-pairing, not a replicase). |
| 8 | * The error rate EMERGES from mispairing; it is not a coded per-bit mutation. |
| 9 | * |
| 10 | * A random diverse soup + degradation + world-supplied selection for a FUNCTION (match a target motif, |
| 11 | * replication rate proportional to fitness). MEASURED, not encoded: does a heritable FUNCTIONAL replicator |
| 12 | * EMERGE from the random soup (mean match climbs 0.5 -> ~1), does it self-sustain against degradation, and |
| 13 | * at what fidelity does it COLLAPSE? Sweep f at two lengths L to expose Eigen's paradox (longer function |
| 14 | * needs higher fidelity, which un-catalyzed templating cannot supply -> the wall). |
| 15 | * |
| 16 | * A strand and its complement carry the same info: fitness is on the CANONICAL form min(s,~s), so S and ~S |
| 17 | * are one functional unit. Nothing rewards a specific replicator identity; only the function, world-supplied. |
| 18 | * |
| 19 | * build: cc -O2 -Wall -std=c11 -o polymer polymer.c -lm |
| 20 | */ |
| 21 | #include <math.h> |
| 22 | #include <stdio.h> |
| 23 | #include <stdint.h> |
| 24 | |
| 25 | #define NMAX 800 |
| 26 | #define D 0.30 /* per-step degradation (turnover that lets selection act) */ |
| 27 | #define STEPS 140 |
| 28 | #define SS 0.30 /* selection strength: fitness = exp(SS * #functional-positions-correct) */ |
| 29 | |
| 30 | static unsigned long long RNG; |
| 31 | static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; } |
| 32 | static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); } |
| 33 | |
| 34 | static int L; static uint64_t MASK, FTAR_C; |
| 35 | static uint64_t canon(uint64_t s){ uint64_t c=(~s)&MASK; return s<c?s:c; } |
| 36 | static int matchC(uint64_t s){ return L - __builtin_popcountll(canon(s) ^ FTAR_C); } |
| 37 | |
| 38 | static uint64_t pool[NMAX], nxt[NMAX]; |
| 39 | static double fit[NMAX], cum[NMAX]; |
| 40 | |
| 41 | /* template-directed synthesis of the complement with per-base fidelity f (mispair otherwise). */ |
| 42 | static uint64_t replicate(uint64_t tmpl, double f){ |
| 43 | uint64_t child=0; |
| 44 | for(int i=0;i<L;i++){ int t=(int)((tmpl>>i)&1); int b=(urand()<f)?(1-t):t; if(b) child|=(1ULL<<i); } |
| 45 | return child; |
| 46 | } |
| 47 | |
| 48 | /* one run at length L, fidelity f. returns final mean functional match (fraction); writes start match. */ |
| 49 | static double run(double f, double *start){ |
| 50 | MASK = (L>=64)?~0ULL:((1ULL<<L)-1); |
| 51 | uint64_t ftar=0; for(int i=0;i<L;i++) if(urand()<0.5) ftar|=(1ULL<<i); FTAR_C=canon(ftar); |
| 52 | for(int p=0;p<NMAX;p++){ uint64_t s=0; for(int i=0;i<L;i++) if(urand()<0.5) s|=(1ULL<<i); pool[p]=s; } |
| 53 | |
| 54 | double s0=0; for(int p=0;p<NMAX;p++) s0+=matchC(pool[p]); s0/=(double)NMAX*L; *start=s0; |
| 55 | |
| 56 | for(int g=0;g<STEPS;g++){ |
| 57 | /* degradation: survivors kept, compacted */ |
| 58 | int ns=0; for(int p=0;p<NMAX;p++) if(urand()>=D) pool[ns++]=pool[p]; |
| 59 | if(ns==0){ *start=s0; return 0.0; } /* extinction */ |
| 60 | double tot=0; for(int p=0;p<ns;p++){ fit[p]=exp(SS*matchC(pool[p])); tot+=fit[p]; cum[p]=tot; } |
| 61 | /* refill empty slots by fitness-weighted TEMPLATE-DIRECTED replication (emergent copier) */ |
| 62 | int k=0; for(;k<ns;k++) nxt[k]=pool[k]; |
| 63 | while(k<NMAX){ double r=urand()*tot; int lo=0,hi=ns-1; while(lo<hi){int mid=(lo+hi)/2; if(cum[mid]<r)lo=mid+1; else hi=mid;} nxt[k++]=replicate(pool[lo],f); } |
| 64 | for(int p=0;p<NMAX;p++) pool[p]=nxt[p]; |
| 65 | } |
| 66 | double e=0; for(int p=0;p<NMAX;p++) e+=matchC(pool[p]); return e/((double)NMAX*L); |
| 67 | } |
| 68 | |
| 69 | int main(void){ |
| 70 | unsigned long long seeds[]={0x9e3779b97f4a7c15ULL,0xd1b54a32d192ed03ULL,0x2545f4914f6cdd1dULL,0x123456789abcdefULL,0xfeedface12345678ULL}; |
| 71 | int NS=sizeof(seeds)/sizeof(seeds[0]); |
| 72 | double fs[]={0.80,0.90,0.95,0.98,0.995}; int nF=sizeof(fs)/sizeof(double); |
| 73 | int Ls[]={16,32}; int nL=sizeof(Ls)/sizeof(int); |
| 74 | |
| 75 | printf("=== rung 1->2 EMERGENCE attempt: template-directed polymer soup (digital) ===\n"); |
| 76 | printf(" Binary strands, 0<->1 pairing. ONLY physics = template-directed synthesis w/ fidelity f.\n"); |
| 77 | printf(" Random soup + degradation + selection for a function. Emergence = functional match 0.5 -> ~1.\n"); |
| 78 | printf(" pop=%d, degrade=%.2f, %d steps, %d seeds. Sweep f at L=%d,%d.\n\n",NMAX,D,STEPS,NS,Ls[0],Ls[1]); |
| 79 | |
| 80 | for(int li=0;li<nL;li++){ |
| 81 | L=Ls[li]; |
| 82 | printf(" --- L=%d (Eigen: need ~f > %.3f to hold) ---\n", L, 1.0-1.0/L); |
| 83 | printf(" f | func match (start->end) | emerged?\n"); |
| 84 | printf(" ------+-------------------------+---------\n"); |
| 85 | double thr=-1; |
| 86 | for(int i=0;i<nF;i++){ |
| 87 | double se=0,ss=0; |
| 88 | for(int s=0;s<NS;s++){ double st; RNG=seeds[s]; se+=run(fs[i],&st); ss+=st; } |
| 89 | se/=NS; ss/=NS; |
| 90 | int emerged = (se>0.85 && se>ss+0.2); |
| 91 | if(emerged && thr<0) thr=fs[i]; |
| 92 | printf(" %.3f | %.3f -> %.3f | %s\n", fs[i], ss, se, emerged?"YES":"no"); |
| 93 | } |
| 94 | printf(" => emergence threshold at L=%d: f* = %s%.3f\n\n", L, thr<0?">":"", thr<0?fs[nF-1]:thr); |
| 95 | } |
| 96 | printf(" HONEST READING (the data corrected my pre-registered guess):\n"); |
| 97 | printf(" * Copying is GENERIC (base-pairing) -- the population always self-sustains; that was never the wall.\n"); |
| 98 | printf(" * Heritable FUNCTION emerges only above a fidelity threshold (~f=0.98 here, i.e. <=2%% error),\n"); |
| 99 | printf(" and it emerges GRADUALLY: at un-catalyzed template fidelity (f~0.80-0.90, 10-20%% error) only\n"); |
| 100 | printf(" WEAK partial function appears (match ~0.6-0.7), not a strong replicator.\n"); |
| 101 | printf(" * The threshold did NOT rise with L -- because this functional landscape is ADDITIVE (per-site\n"); |
| 102 | printf(" selection), the forgiving 'relaxed error threshold' case (Kun-Szathmary). The value ~0.98\n"); |
| 103 | printf(" scales with selection strength; the STRUCTURE (a fidelity wall) is what is robust.\n"); |
| 104 | printf(" * THE WALL, reproduced from emergent copying physics: the fidelity needed to evolve a strong\n"); |
| 105 | printf(" functional replicator (>=0.98) EXCEEDS what un-catalyzed templating supplies (~0.85), and the\n"); |
| 106 | printf(" replicase that would close the gap is itself a functional sequence needing that fidelity\n"); |
| 107 | printf(" FIRST -- Eigen's bootstrap paradox. rung 1->2 does NOT cross from below at realistic fidelity.\n"); |
| 108 | return 0; |
| 109 | } |