| … | … | @@ -85,10 +85,15 @@ static int lnk[TOTAL][LINKS]; |
| 85 | 85 | static double ww[TOTAL][LINKS], inflow[TOTAL][LINKS]; |
| 86 | 86 | static double recv[TOTAL], fid[TOTAL], cumw[TOTAL]; |
| 87 | 87 | static int phic[TOTAL]; |
| 88 | static int lnk_o[TOTAL][LINKS]; static double ww_o[TOTAL][LINKS]; |
| 89 | static int par[TOTAL], ocount[TOTAL], ostart[TOTAL], olist[TOTAL]; |
| 88 | 90 | |
| 89 | 91 | /* mode: 0 = k frozen at kfix; 1 = k evolvable. shuffled: apply conductance updates to a permuted |
| 90 | 92 | set of the unit's own junctions (same arithmetic, decoupled from who actually sent flow). */ |
| 91 | | static double run(int evolve_k,double kfix,int shuffled,double *k_end,double *f_end,double *phi_start) |
| 93 | /* persist: 0 = fresh random wiring every generation (original) |
| 94 | 1 = offspring INHERIT the parent's junctions, remapped to the partners' own offspring |
| 95 | 2 = offspring inherit a RANDOM unit's junctions (control: persistence without lineage) */ |
| 96 | static double run(int evolve_k,double kfix,int shuffled,int persist,double *k_end,double *f_end,double *phi_start) |
| 92 | 97 | { |
| 93 | 98 | for(int i=0;i<TOTAL;i++){ |
| 94 | 99 | uint32_t s=0; for(int b=0;b<L;b++) if(urand()<0.5) s|=(1u<<b); |
| … | … | @@ -96,14 +101,22 @@ static double run(int evolve_k,double kfix,int shuffled,double *k_end,double *f_ |
| 96 | 101 | } |
| 97 | 102 | { double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(seq[i]); *phi_start=sp/TOTAL; } |
| 98 | 103 | |
| 104 | if(persist){ /* seed the network once; it then persists */ |
| 105 | for(int i=0;i<TOTAL;i++) for(int l=0;l<LINKS;l++){ |
| 106 | int j; do { j=(int)(xs()%TOTAL); } while(j==i); |
| 107 | lnk[i][l]=j; ww[i][l]=1.0/LINKS; |
| 108 | } |
| 109 | } |
| 110 | |
| 99 | 111 | for(int g=0;g<GEN;g++){ |
| 100 | 112 | for(int i=0;i<TOTAL;i++) phic[i]=phi(seq[i]); |
| 101 | 113 | |
| 102 | | /* fresh random wiring each generation: no persistent social structure is supplied */ |
| 103 | | for(int i=0;i<TOTAL;i++){ |
| 104 | | for(int l=0;l<LINKS;l++){ |
| 105 | | int j; do { j=(int)(xs()%TOTAL); } while(j==i); |
| 106 | | lnk[i][l]=j; ww[i][l]=1.0/LINKS; |
| 114 | if(!persist){ /* fresh random wiring each generation: no persistent structure supplied */ |
| 115 | for(int i=0;i<TOTAL;i++){ |
| 116 | for(int l=0;l<LINKS;l++){ |
| 117 | int j; do { j=(int)(xs()%TOTAL); } while(j==i); |
| 118 | lnk[i][l]=j; ww[i][l]=1.0/LINKS; |
| 119 | } |
| 107 | 120 | } |
| 108 | 121 | } |
| 109 | 122 | for(int i=0;i<TOTAL;i++) recv[i]=0.0; |
| … | … | @@ -149,6 +162,7 @@ static double run(int evolve_k,double kfix,int shuffled,double *k_end,double *f_ |
| 149 | 162 | for(int i=0;i<TOTAL;i++){ |
| 150 | 163 | double r=urand()*tot; int lo=0,hi=TOTAL-1; |
| 151 | 164 | while(lo<hi){ int mid=(lo+hi)/2; if(cumw[mid]<r) lo=mid+1; else hi=mid; } |
| 165 | par[i]=lo; |
| 152 | 166 | nseq[i]=replicate(seq[lo],fid[lo]); |
| 153 | 167 | double k2 = evolve_k ? kk[lo]+MUTK*randn() : kk[lo]; |
| 154 | 168 | if(k2<0)k2=0; |
| … | … | @@ -156,6 +170,34 @@ static double run(int evolve_k,double kfix,int shuffled,double *k_end,double *f_ |
| 156 | 170 | nkk[i]=k2; |
| 157 | 171 | } |
| 158 | 172 | for(int i=0;i<TOTAL;i++){ seq[i]=nseq[i]; kk[i]=nkk[i]; } |
| 173 | |
| 174 | if(persist){ |
| 175 | /* A junction persists by pointing at a DESCENDANT of the old partner. If that partner |
| 176 | left no descendants the junction is dead and is replaced by a random new one. */ |
| 177 | for(int i=0;i<TOTAL;i++) for(int l=0;l<LINKS;l++){ lnk_o[i][l]=lnk[i][l]; ww_o[i][l]=ww[i][l]; } |
| 178 | for(int q=0;q<TOTAL;q++) ocount[q]=0; |
| 179 | for(int i=0;i<TOTAL;i++) ocount[par[i]]++; |
| 180 | int acc=0; for(int q=0;q<TOTAL;q++){ ostart[q]=acc; acc+=ocount[q]; } |
| 181 | { static int fill[TOTAL]; for(int q=0;q<TOTAL;q++) fill[q]=0; |
| 182 | for(int i=0;i<TOTAL;i++){ int q=par[i]; olist[ostart[q]+fill[q]]=i; fill[q]++; } } |
| 183 | for(int i=0;i<TOTAL;i++){ |
| 184 | int src = (persist==2) ? (int)(xs()%TOTAL) : par[i]; /* mode 2: lineage decoupled */ |
| 185 | double s2=0; |
| 186 | for(int l=0;l<LINKS;l++){ |
| 187 | int oldj=lnk_o[src][l]; |
| 188 | if(ocount[oldj]>0){ |
| 189 | int pick=olist[ostart[oldj]+(int)(xs()%(unsigned long long)ocount[oldj])]; |
| 190 | lnk[i][l] = (pick==i)? (int)(xs()%TOTAL) : pick; |
| 191 | ww[i][l] = ww_o[src][l]; |
| 192 | } else { |
| 193 | int j; do { j=(int)(xs()%TOTAL); } while(j==i); |
| 194 | lnk[i][l]=j; ww[i][l]=1.0/LINKS; /* dead partner -> new random junction */ |
| 195 | } |
| 196 | s2+=ww[i][l]; |
| 197 | } |
| 198 | if(s2>0) for(int l=0;l<LINKS;l++) ww[i][l]/=s2; |
| 199 | } |
| 200 | } |
| 159 | 201 | } |
| 160 | 202 | |
| 161 | 203 | double sp=0,sk=0,sf=0; |
| … | … | @@ -181,60 +223,67 @@ int main(void) |
| 181 | 223 | printf(" arm | mean phi (start->end of %2d) | k end | fidelity end\n",PHIMAX); |
| 182 | 224 | printf(" ---------------------------------+-----------------------------+-------+-------------\n"); |
| 183 | 225 | |
| 184 | | double base_s=0,base_e=0; |
| 185 | | struct { const char*name; int ev; double kf; int sh; } arms[]={ |
| 186 | | {"k=0 frozen (public good) ", 0, 0.0, 0}, |
| 187 | | {"k=1 frozen (full reciprocity) ", 0, 1.0, 0}, |
| 188 | | {"k free to evolve (start 0.10) ", 1, 0.0, 0}, |
| 189 | | {"k=1 SHUFFLED (control) ", 0, 1.0, 1}, |
| 226 | |
| 227 | struct { const char*name; int ev; double kf; int sh; int pe; } arms[]={ |
| 228 | {"FRESH k=0 (public good) ", 0, 0.0, 0, 0}, |
| 229 | {"FRESH k=1 (reciprocity) ", 0, 1.0, 0, 0}, |
| 230 | {"FRESH k free (start 0.10) ", 1, 0.0, 0, 0}, |
| 231 | {"FRESH k=1 SHUFFLED (ctrl) ", 0, 1.0, 1, 0}, |
| 232 | {"PERSIST k=0 (public good) ", 0, 0.0, 0, 1}, |
| 233 | {"PERSIST k=1 (reciprocity) ", 0, 1.0, 0, 1}, |
| 234 | {"PERSIST k free (start 0.10) ", 1, 0.0, 0, 1}, |
| 235 | {"PERSIST k=1 SHUFFLED (ctrl) ", 0, 1.0, 1, 1}, |
| 236 | {"PERSIST-RANDOM k=1 (ctrl) ", 0, 1.0, 0, 2}, |
| 190 | 237 | }; |
| 191 | 238 | int NA=(int)(sizeof(arms)/sizeof(arms[0])); |
| 192 | | double endphi[8], startphi[8], endk[8]; |
| 239 | double endphi[16], startphi[16], endk[16]; |
| 193 | 240 | for(int a=0;a<NA;a++){ |
| 194 | 241 | double S=0,E=0,K=0,F=0; double ev[16]; |
| 195 | 242 | for(int s=0;s<NS;s++){ |
| 196 | 243 | double ke,fe,ps; RNG=seeds[s]; |
| 197 | | double e=run(arms[a].ev,arms[a].kf,arms[a].sh,&ke,&fe,&ps); |
| 244 | double e=run(arms[a].ev,arms[a].kf,arms[a].sh,arms[a].pe,&ke,&fe,&ps); |
| 198 | 245 | ev[s]=e; E+=e; S+=ps; K+=ke; F+=fe; |
| 199 | 246 | } |
| 200 | 247 | S/=NS;E/=NS;K/=NS;F/=NS; |
| 201 | 248 | double sd=0; for(int s=0;s<NS;s++) sd+=(ev[s]-E)*(ev[s]-E); sd=sqrt(sd/(NS-1)); |
| 202 | 249 | endphi[a]=E; startphi[a]=S; endk[a]=K; |
| 203 | | if(a==0){ base_s=S; base_e=E; } |
| 250 | |
| 204 | 251 | printf(" %s | %.2f -> %5.2f +- %.2f | %.3f | %.4f\n",arms[a].name,S,E,sd,K,F); |
| 205 | 252 | } |
| 206 | 253 | printf("\n"); |
| 207 | 254 | |
| 255 | printf(" FRESH k=0 %.2f | k=1 %.2f | k free %.2f (k->%.3f) | shuffled %.2f\n", |
| 256 | endphi[0],endphi[1],endphi[2],endk[2],endphi[3]); |
| 257 | printf(" PERSIST k=0 %.2f | k=1 %.2f | k free %.2f (k->%.3f) | shuffled %.2f | from-RANDOM %.2f\n\n", |
| 258 | endphi[4],endphi[5],endphi[6],endk[6],endphi[7],endphi[8]); |
| 259 | |
| 208 | 260 | int pub_fell = endphi[0] < startphi[0]-0.3; |
| 209 | | int recip_rose = endphi[1] > startphi[1]+0.5; |
| 210 | | int evo_rose = endphi[2] > startphi[2]+0.5; |
| 211 | | int k_climbed = endk[2] > 0.30; |
| 212 | | int shuf_rose = endphi[3] > startphi[3]+0.5; |
| 213 | | |
| 214 | | printf(" P1 public good (k=0) : phi %s (%.2f -> %.2f)\n", pub_fell?"FELL — tragedy reproduced":"did NOT fall", base_s, base_e); |
| 215 | | printf(" P2 reciprocity (k=1) : phi %s (%.2f -> %.2f)\n", recip_rose?"ROSE":"did NOT rise", startphi[1], endphi[1]); |
| 216 | | printf(" P3 k evolvable : phi %s (%.2f -> %.2f), k %s (0.10 -> %.3f)\n", |
| 217 | | evo_rose?"ROSE":"did NOT rise", startphi[2], endphi[2], k_climbed?"CLIMBED":"did not climb", endk[2]); |
| 218 | | printf(" P4 shuffled control : phi %s (%.2f -> %.2f)\n", shuf_rose?"ROSE — CONFOUND":"did NOT rise (good)", startphi[3], endphi[3]); |
| 219 | | printf("\n"); |
| 261 | int recip_gain = endphi[1] > endphi[0]+0.3; |
| 262 | int shuf_flat = endphi[3] < endphi[0]+0.3; |
| 263 | int persist_helps = endphi[5] > endphi[1]+0.15; |
| 264 | int lineage_matters = endphi[5] > endphi[8]+0.15; |
| 265 | int any_rose = endphi[5] > startphi[5]+0.5; |
| 266 | |
| 267 | printf(" P1 public good falls : %s (%.2f -> %.2f)\n", pub_fell?"YES":"no", startphi[0], endphi[0]); |
| 268 | printf(" P2 reciprocity beats public good : %s (%.2f vs %.2f)\n", recip_gain?"YES":"no", endphi[1], endphi[0]); |
| 269 | printf(" P3 shuffled control stays flat : %s (%.2f vs %.2f)\n", shuf_flat?"YES — effect is reciprocity":"NO — confounded", endphi[3], endphi[0]); |
| 270 | printf(" P5 persistence beats fresh wiring : %s (%.2f vs %.2f)\n", persist_helps?"YES":"NO", endphi[5], endphi[1]); |
| 271 | printf(" P7 lineage matters vs from-RANDOM : %s (%.2f vs %.2f)\n", lineage_matters?"YES":"NO", endphi[5], endphi[8]); |
| 272 | printf(" P6 phi RISES anywhere (a crossing) : %s\n\n", any_rose?"YES":"NO"); |
| 220 | 273 | |
| 221 | | if(recip_rose && pub_fell && !shuf_rose) |
| 222 | | printf(" => COUPLING PRIVATIZES THE PUBLIC GOOD WITH NO CONTAINER. Cutting a junction to a\n" |
| 223 | | " freeloader costs nothing because it was sending nothing back, so conditional\n" |
| 224 | | " conductance starves parasites of fidelity while catalysts fund each other. The\n" |
| 225 | | " shuffled control did NOT rise, so this is reciprocity and not merely concentrating\n" |
| 226 | | " conductance. %s\n", |
| 227 | | evo_rose&&k_climbed ? "AND k evolved up on its own — the wiring rule is itself selected." |
| 228 | | : "NOTE: k did NOT evolve up on its own, so conditioning works but is not self-installing."); |
| 229 | | else if(recip_rose && shuf_rose) |
| 230 | | printf(" => CONFOUNDED. phi rose in the shuffled control too, so the effect is about\n" |
| 231 | | " concentrating conductance onto few partners, NOT about reciprocity. Do not claim\n" |
| 232 | | " a coupling result from this.\n"); |
| 233 | | else if(!recip_rose) |
| 234 | | printf(" => HONEST NULL. Wiring did not privatize catalysis here: parasites harvest enough\n" |
| 235 | | " before conductances sort, or catalysts never find each other in a random network.\n" |
| 236 | | " Containers remain the only thing in the arc that privatizes. Accept the null.\n"); |
| 274 | if(!any_rose && !persist_helps && !lineage_matters) |
| 275 | printf(" => NULL, AND THE PERSISTENCE HYPOTHESIS IS FALSIFIED. Making junctions persist does not\n" |
| 276 | " help, and inheriting a RANDOM unit\'s junctions works just as well as inheriting your\n" |
| 277 | " parent\'s -- so nothing about lineage consolidation is doing work. Reciprocity is real\n" |
| 278 | " (P2/P3 hold) but it only slows the tragedy.\n" |
| 279 | " STRUCTURAL READING: the network never PARTITIONS. Every unit keeps %d junctions into one\n" |
| 280 | " giant component, so \"the individual\" is always the whole population and there is nothing\n" |
| 281 | " to privatize. Also, conductance is renormalised to sum to 1: a unit can choose WHOM to\n" |
| 282 | " give to but never HOW MUCH -- it always exports its full output. Catalysts can redirect,\n" |
| 283 | " never withhold.\n", LINKS); |
| 284 | else if(any_rose) |
| 285 | printf(" => phi ROSE. Check the controls before claiming anything.\n"); |
| 237 | 286 | else |
| 238 | | printf(" => Mixed/ambiguous — report the numbers as-is, claim nothing.\n"); |
| 287 | printf(" => Mixed -- report the numbers as-is, claim nothing.\n"); |
| 239 | 288 | return 0; |
| 240 | 289 | } |