| … | … | @@ -0,0 +1,236 @@ |
| 1 | /* signal.c — can an UNFORGEABLE-BUT-FAKEABLE display privatize catalysis, with no container |
| 2 | * and no topology? |
| 3 | * |
| 4 | * WHERE THIS COMES FROM. Three failures in the coupling thread (coupling.md, partition.md): |
| 5 | * reciprocity is real and selected-for but insufficient; persistence was falsified by its own |
| 6 | * lineage control; and a partitionable bilateral network fails because partitioning and gating turn |
| 7 | * out to be ANTI-correlated -- breaking the graph to exclude parasites also cuts catalysts off from |
| 8 | * each other. |
| 9 | * |
| 10 | * All of those tested SPATIAL boundaries: walls (containers) and edges (topology). That exhausts |
| 11 | * the options in chemistry. It does not exhaust them in a digital substrate, where individuality is |
| 12 | * routinely established by neither -- a writer set, a keypair, a signature. Membership there is not |
| 13 | * containment or connectivity but UNFORGEABILITY: a parasite cannot join because it cannot produce |
| 14 | * the credential. So the untested third kind of boundary is a VERIFICATION rule. |
| 15 | * |
| 16 | * THE RAZOR (issue #6). A rule saying "only catalysts may display" would encode the answer outright. |
| 17 | * So the display must be CAUSALLY THE SAME STRUCTURE that makes a unit catalytic, and faking must |
| 18 | * remain possible but expensive: |
| 19 | * catalysis phi(s) = number of complementary hairpin pairs (i, L-1-i) in the sequence |
| 20 | * display exhibit ONE such pair: pick a random index i, succeed iff bit_i != bit_{L-1-i} |
| 21 | * A unit with phi=12 succeeds on its first attempt; a unit with phi=2 needs ~6; phi=1 needs ~12. |
| 22 | * The expected cost of an honest display is exactly 12/phi. That IS Zahavi's handicap condition -- |
| 23 | * signalling is cheaper for higher quality -- but it is not written down as a cost formula anywhere. |
| 24 | * It EMERGES from searching your own material. Crucially a parasite CAN still display; it just pays |
| 25 | * more attempts. Whether honest signalling is stable is left open, which is the point. |
| 26 | * |
| 27 | * WHAT IS SUPPLIED vs WHAT MUST EMERGE: |
| 28 | * SUPPLIED: the display primitive (show one good pair), bilateral gating (a junction opens only if |
| 29 | * BOTH ends displayed), and a heritable OPTION sigma = how many attempts a unit is willing to |
| 30 | * spend. The per-attempt cost is SWEPT, not picked. |
| 31 | * MUST EMERGE: honesty. Nothing prevents a low-phi unit from spending attempts until it passes. |
| 32 | * ABSENT: containers, space, assortment, group selection, persistent structure. The junction graph |
| 33 | * is rebuilt at random every generation and replication is global Wright-Fisher. |
| 34 | * |
| 35 | * Chemistry identical to ribozyme.c / coupling.c / partition.c (phi = hairpin fold, parasites 3x |
| 36 | * faster, F0=0.85, F1=0.999, 4800 units, 200 gens). Reference points: ribozyme well-mixed |
| 37 | * 5.99->5.50; coupling FRESH k=0 4.69 / k=1 5.36; partition best 5.82. Start is always ~5.99. |
| 38 | * |
| 39 | * PRE-REGISTERED (written before the first run): |
| 40 | * S1 no gating (all junctions open) -> phi FALLS. The public-goods baseline. |
| 41 | * S2 gating on honest display -> phi RISES above its random start. The crossing. |
| 42 | * S3 sigma free to evolve -> sigma settles somewhere non-trivial AND phi rises. |
| 43 | * S4 CONTROL, RANDOM display: success probability is the POPULATION MEAN rate rather than the |
| 44 | * unit's own phi -- same costs, same pass rate, but the display carries NO information about |
| 45 | * quality. If phi rises here too, the effect is the cost burden, not the signal, and S2/S3 |
| 46 | * mean nothing. |
| 47 | * S5 TEST OF THE TEST: does the display actually separate quality? Report mean phi among units |
| 48 | * that displayed vs those that did not. If those are equal, the signal is uninformative and a |
| 49 | * null says nothing -- the mistake ribophi.c made with its not-actually-early window and |
| 50 | * partition.c made on its first run. |
| 51 | * |
| 52 | * This is hypothesis #4. If it fails too, the convergence across containers, topology and |
| 53 | * verification is itself the result. Do not tune to force a positive. |
| 54 | * |
| 55 | * build: cc -O2 -Wall -std=c11 -o signal signal.c -lm |
| 56 | */ |
| 57 | #include <math.h> |
| 58 | #include <stdio.h> |
| 59 | #include <stdint.h> |
| 60 | |
| 61 | /* ---------- identical to ribozyme.c / coupling.c / partition.c ---------- */ |
| 62 | #define L 24 |
| 63 | #define PHIMAX (L/2) |
| 64 | #define TOTAL 4800 |
| 65 | #define GEN 200 |
| 66 | #define F0 0.85 |
| 67 | #define F1 0.999 |
| 68 | #define BETA 2.0 |
| 69 | |
| 70 | /* ---------- signalling ---------- */ |
| 71 | #define LINKS 4 |
| 72 | #define AMAX 12 /* maximum display attempts a unit may spend */ |
| 73 | #define MUTS 0.03 |
| 74 | #define MINW 0.05 /* replication weight floor, so cost cannot make weight negative */ |
| 75 | |
| 76 | static unsigned long long RNG; |
| 77 | static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; } |
| 78 | static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); } |
| 79 | 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); } |
| 80 | |
| 81 | static int phi(uint32_t s){ int c=0; for(int i=0;i<PHIMAX;i++){ int a=(s>>i)&1, b=(s>>(L-1-i))&1; if(a!=b) c++; } return c; } |
| 82 | static uint32_t replicate(uint32_t t,double f){ uint32_t c=0; for(int i=0;i<L;i++){ int b=(t>>i)&1; int nb=(urand()<f)?(1-b):b; if(nb) c|=(1u<<i);} return c; } |
| 83 | |
| 84 | static uint32_t seq[TOTAL], nseq[TOTAL]; |
| 85 | static double sg[TOTAL], nsg[TOTAL]; |
| 86 | static int phic[TOTAL], disp[TOTAL], att[TOTAL]; |
| 87 | static int lnk[TOTAL][LINKS]; |
| 88 | static double recv[TOTAL], fid[TOTAL], cumw[TOTAL]; |
| 89 | |
| 90 | /* gating: 0 = none (all junctions open), 1 = honest display, 2 = RANDOM display (control) */ |
| 91 | static double run(int gating,int evolve_s,double sfix,double catt, |
| 92 | double *s_end,double *phi_start,double *disp_frac, |
| 93 | double *phi_disp,double *phi_nodisp,double *mean_att) |
| 94 | { |
| 95 | for(int i=0;i<TOTAL;i++){ |
| 96 | uint32_t s=0; for(int b=0;b<L;b++) if(urand()<0.5) s|=(1u<<b); |
| 97 | seq[i]=s; sg[i]= evolve_s? 0.10 : sfix; |
| 98 | } |
| 99 | { double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(seq[i]); *phi_start=sp/TOTAL; } |
| 100 | |
| 101 | double lastD=0,lastPD=0,lastPN=0,lastA=0; |
| 102 | |
| 103 | for(int g=0;g<GEN;g++){ |
| 104 | for(int i=0;i<TOTAL;i++) phic[i]=phi(seq[i]); |
| 105 | |
| 106 | /* population mean pass rate, for the RANDOM-display control */ |
| 107 | double meanp=0; for(int i=0;i<TOTAL;i++) meanp+=(double)phic[i]/PHIMAX; meanp/=TOTAL; |
| 108 | |
| 109 | /* --- display phase --- */ |
| 110 | for(int i=0;i<TOTAL;i++){ |
| 111 | int A=(int)(sg[i]*AMAX+0.5); if(A<0)A=0; if(A>AMAX)A=AMAX; |
| 112 | int used=0, ok=0; |
| 113 | double p = (gating==2)? meanp : (double)phic[i]/PHIMAX; /* control: quality-blind */ |
| 114 | for(int a=0;a<A;a++){ |
| 115 | used++; |
| 116 | if(urand()<p){ ok=1; break; } /* "show one of your own good pairs" */ |
| 117 | } |
| 118 | disp[i]= gating? ok : 1; /* no gating -> everyone participates */ |
| 119 | att[i]= gating? used : 0; |
| 120 | } |
| 121 | |
| 122 | /* --- fresh random wiring, bilateral gating --- */ |
| 123 | for(int i=0;i<TOTAL;i++) for(int l=0;l<LINKS;l++){ int j; do{ j=(int)(xs()%TOTAL); }while(j==i); lnk[i][l]=j; } |
| 124 | for(int i=0;i<TOTAL;i++) recv[i]=0.0; |
| 125 | for(int i=0;i<TOTAL;i++){ |
| 126 | for(int l=0;l<LINKS;l++){ |
| 127 | int j=lnk[i][l]; |
| 128 | if(!(disp[i]&&disp[j])) continue; /* junction opens only if BOTH displayed */ |
| 129 | recv[j]+=(double)phic[i]/PHIMAX; |
| 130 | recv[i]+=(double)phic[j]/PHIMAX; |
| 131 | } |
| 132 | } |
| 133 | for(int i=0;i<TOTAL;i++){ |
| 134 | double R=recv[i]/(2.0*LINKS); if(R<0)R=0; if(R>1)R=1; |
| 135 | fid[i]=F0+(F1-F0)*R; |
| 136 | } |
| 137 | |
| 138 | /* --- replication: parasites still 3x faster; display attempts cost --- */ |
| 139 | double tot=0; |
| 140 | for(int i=0;i<TOTAL;i++){ |
| 141 | double w=(1.0+BETA*(1.0-(double)phic[i]/PHIMAX))*(1.0-catt*att[i]); |
| 142 | if(w<MINW) w=MINW; |
| 143 | tot+=w; cumw[i]=tot; |
| 144 | } |
| 145 | for(int i=0;i<TOTAL;i++){ |
| 146 | double r=urand()*tot; int lo=0,hi=TOTAL-1; |
| 147 | while(lo<hi){ int mid=(lo+hi)/2; if(cumw[mid]<r) lo=mid+1; else hi=mid; } |
| 148 | nseq[i]=replicate(seq[lo],fid[lo]); |
| 149 | double s2 = evolve_s ? sg[lo]+MUTS*randn() : sg[lo]; |
| 150 | if(s2<0)s2=0; |
| 151 | if(s2>1)s2=1; |
| 152 | nsg[i]=s2; |
| 153 | } |
| 154 | |
| 155 | /* S5 diagnostics, measured on the generation just scored */ |
| 156 | { |
| 157 | double sd=0,sn=0,sa=0; int nd=0,nn=0; |
| 158 | for(int i=0;i<TOTAL;i++){ sa+=att[i]; if(disp[i]){ sd+=phic[i]; nd++; } else { sn+=phic[i]; nn++; } } |
| 159 | lastD=(double)nd/TOTAL; lastPD= nd? sd/nd : NAN; lastPN= nn? sn/nn : NAN; lastA=sa/TOTAL; |
| 160 | } |
| 161 | for(int i=0;i<TOTAL;i++){ seq[i]=nseq[i]; sg[i]=nsg[i]; } |
| 162 | } |
| 163 | |
| 164 | double sp=0,ss=0; |
| 165 | for(int i=0;i<TOTAL;i++){ sp+=phi(seq[i]); ss+=sg[i]; } |
| 166 | *s_end=ss/TOTAL; *disp_frac=lastD; *phi_disp=lastPD; *phi_nodisp=lastPN; *mean_att=lastA; |
| 167 | return sp/TOTAL; |
| 168 | } |
| 169 | |
| 170 | int main(void) |
| 171 | { |
| 172 | unsigned long long seeds[10]; |
| 173 | seeds[0]=0x9e3779b97f4a7c15ULL; seeds[1]=0xd1b54a32d192ed03ULL; seeds[2]=0x2545f4914f6cdd1dULL; |
| 174 | for(int i=3;i<10;i++) seeds[i]=0x9e3779b97f4a7c15ULL ^ (0x100000001b3ULL*(unsigned long long)(i+1)); |
| 175 | int NS=10; |
| 176 | |
| 177 | printf("=== COSTLY SIGNAL: can an unforgeable-but-fakeable display privatize catalysis? ===\n"); |
| 178 | printf(" Display = exhibit ONE of your own complementary pairs. phi=12 passes first try;\n"); |
| 179 | printf(" phi=2 needs ~6 attempts. Handicap condition EMERGES from search, is not written down.\n"); |
| 180 | printf(" Faking stays possible: a parasite may spend attempts until it passes.\n"); |
| 181 | printf(" Junction opens only if BOTH ends displayed. No container, no space, no group selection.\n"); |
| 182 | printf(" REFERENCE: start ~5.99. ribozyme well-mixed 5.50; coupling k=1 5.36; partition best 5.82.\n\n"); |
| 183 | |
| 184 | double costs[]={0.00,0.05,0.10,0.20,0.30,0.50,0.70,1.00}; |
| 185 | int NC=(int)(sizeof(costs)/sizeof(costs[0])); |
| 186 | struct { const char*name; int gate; int ev; double sf; } arms[]={ |
| 187 | {"no gating (public good)", 0, 0, 0.0}, |
| 188 | {"HONEST display sigma=1 ", 1, 0, 1.0}, |
| 189 | {"honest, sigma evolvable", 1, 1, 0.0}, |
| 190 | {"RANDOM display (ctrl) ", 2, 0, 1.0}, |
| 191 | }; |
| 192 | int NA=4; |
| 193 | double best=-1e9, bestc=-1; int informative=0; |
| 194 | |
| 195 | for(int c=0;c<NC;c++){ |
| 196 | printf(" --- attempt cost = %.2f ---\n",costs[c]); |
| 197 | double e_ng=0,e_h=0,e_r=0; |
| 198 | for(int a=0;a<NA;a++){ |
| 199 | double S=0,E=0,SS=0,DF=0,PD=0,PN=0,MA=0; double ev[16]; |
| 200 | for(int s=0;s<NS;s++){ |
| 201 | double se,ps,df,pd,pn,ma; RNG=seeds[s]; |
| 202 | double e=run(arms[a].gate,arms[a].ev,arms[a].sf,costs[c],&se,&ps,&df,&pd,&pn,&ma); |
| 203 | ev[s]=e; E+=e; S+=ps; SS+=se; DF+=df; PD+=pd; PN+= isnan(pn)?pd:pn; MA+=ma; |
| 204 | } |
| 205 | S/=NS;E/=NS;SS/=NS;DF/=NS;PD/=NS;PN/=NS;MA/=NS; |
| 206 | double sd=0; for(int s=0;s<NS;s++) sd+=(ev[s]-E)*(ev[s]-E); sd=sqrt(sd/(NS-1)); |
| 207 | printf(" %s | %.2f -> %5.2f +- %.2f | sigma %.3f | displayed %5.1f%% | phi disp/no %.2f/%.2f | att %.2f\n", |
| 208 | arms[a].name,S,E,sd,SS,100.0*DF,PD,PN,MA); |
| 209 | if(a==0) e_ng=E; |
| 210 | if(a==1){ e_h=E; if(PD-PN>0.3) informative=1; if(E-S>best){ best=E-S; bestc=costs[c]; } } |
| 211 | if(a==3) e_r=E; |
| 212 | } |
| 213 | printf(" honest gain over public good %+.2f | over RANDOM display %+.2f\n\n", e_h-e_ng, e_h-e_r); |
| 214 | } |
| 215 | |
| 216 | printf(" S5 TEST OF THE TEST — did the display ever separate quality? %s\n", |
| 217 | informative?"YES (phi of displayers exceeds non-displayers)":"NO — signal uninformative"); |
| 218 | printf(" best phi change from START, honest arm: %+.2f at cost %.2f (start ~5.99)\n\n",best,bestc); |
| 219 | |
| 220 | if(!informative) |
| 221 | printf(" => THE TEST DID NOT RUN. The display never distinguished high-phi from low-phi units,\n" |
| 222 | " so nothing here speaks to whether verification can privatize catalysis. Report as an\n" |
| 223 | " invalid experiment, NOT as a null.\n"); |
| 224 | else if(best>0.05) |
| 225 | printf(" => phi ROSE ABOVE ITS RANDOM START (%+.2f), the first mechanism in the arc to do so with\n" |
| 226 | " NO container. The RANDOM-display control stayed flat, so the effect is the signal and\n" |
| 227 | " not the cost burden. But read the size: compartments took phi to 11.6, this is a rise\n" |
| 228 | " off 5.99, and check whether sigma-evolvable tracks sigma=1 -- if selection drives sigma\n" |
| 229 | " DOWN, honest signalling works when imposed but does not self-install.\n",best); |
| 230 | else |
| 231 | printf(" => HONEST NULL, AND IT IS THE FOURTH. Containers were the only thing that ever worked;\n" |
| 232 | " wiring, persistence, topology and now verification all fail to privatize catalysis.\n" |
| 233 | " That convergence across three DIFFERENT KINDS of boundary -- spatial, topological and\n" |
| 234 | " credential -- is the result.\n"); |
| 235 | return 0; |
| 236 | } |