Current task: —

E-019-zeroflow-a12.py

Experiments: E-019 · script updated 08-18-2026

E-019-zeroflow-a12.csv — 55.3 KB, updated 08-18-2026

← prev page 3 of 5 · 500/page · 2129 rows next →
# seriesajvalue
1002 zero 12 47 12.4431309676
1003 zero 12 48 12.7057569380
1004 zero 12 49 12.9687192370
1005 zero 12 50 13.2322532664
1006 zero 12 51 13.4971454339
1007 zero 12 52 13.7662256841
1008 zero 12 53 14.1145182627
1009 zero 12 54 14.1755185672
1010 zero 12 55 14.5172376148
1011 zero 12 56 14.7862837817
1012 zero 12 57 15.0512138594
1013 zero 12 58 15.3147114057
1014 zero 12 59 15.5777218676
1015 zero 12 60 15.8403310774
1016 zero 12 61 16.1028152708
1017 zero 12 62 16.3651447584
1018 zero 12 63 16.6273855612
1019 zero 12 64 16.8896078634
1020 zero 12 65 17.1517704036
1021 zero 12 66 17.4139145824
1022 zero 12 67 17.6760265733
1023 zero 12 68 17.9381440992
1024 zero 12 69 18.2002520665
1025 zero 12 70 18.4623962610
1026 zero 12 71 18.7244804785
1027 zero 12 72 18.9866667212
1028 zero 12 73 19.2488545221
1029 zero 12 74 19.5110751043
1030 zero 12 75 19.7735187024
1031 zero 12 76 20.0360855499
1032 zero 12 77 20.2992470423
1033 zero 12 78 20.5637662921
1034 zero 12 79 20.8381753230
1035 zero 12 80 21.0248600573
1036 zero 12 81 21.3349581291
1037 zero 12 82 21.6003808145
1038 zero 12 83 21.8636398158
1039 zero 12 84 22.1263143902
1040 zero 12 85 22.3887346677
1041 zero 12 86 22.6510154140
1042 zero 12 87 22.9131256553
1043 zero 12 88 23.1753074798
1044 zero 12 89 23.4373824847
1045 zero 12 90 23.6994409692
1046 zero 12 91 23.9615547938
1047 zero 12 92 24.2235806786
1048 zero 12 93 24.4856131945
1049 zero 12 94 24.7476301750
1050 zero 12 95 25.0108051404
1051 zero 12 96 25.2716314629
1052 zero 12 97 25.5336290598
1053 zero 12 98 25.7956628112
1054 zero 12 99 26.0576962189
1055 zero 12 100 26.3197395614
1056 zero 12 101 26.5817820642
1057 zero 12 102 26.8438593451
1058 zero 12 103 27.1059300472
1059 zero 12 104 27.3679637909
1060 zero 12 105 27.6300937371
1061 zero 12 106 27.8921548907
1062 zero 12 107 28.1544463647
1063 zero 12 108 28.4167188430
1064 zero 12 109 28.6790782742
1065 zero 12 110 28.9415348139
1066 zero 12 111 29.2042776519
1067 zero 12 112 29.4675041179
1068 zero 12 113 29.7316031386
1069 zero 12 114 29.9985689211
1070 zero 12 115 30.2942687483
1071 zero 12 116 30.4301822813
1072 zero 12 117 30.7593448838
1073 zero 12 118 31.0270255874
1074 zero 12 119 31.2914242538
1075 zero 12 120 31.5548802020
1076 zero 12 121 31.8182947237
1077 zero 12 122 32.0816365883
1078 zero 12 123 32.3457102770
1079 zero 12 124 32.6122959665
1080 zero 12 125 32.9313282355
1081 zero 12 126 33.0967242520
1082 zero 12 127 33.3789982402
1083 zero 12 128 33.6448298953
1084 zero 12 129 33.9084442973
1085 zero 12 130 34.1712603659
1086 zero 12 131 34.4339716313
1087 zero 12 132 34.6963000575
1088 zero 12 133 34.9587062932
1089 zero 12 134 35.2209122845
1090 zero 12 135 35.4829252191
1091 zero 12 136 35.7451559994
1092 zero 12 137 36.0072575460
1093 zero 12 138 36.2692117893
1094 zero 12 139 36.5315168707
1095 zero 12 140 36.7934716090
1096 zero 12 141 37.0556386714
1097 zero 12 142 37.3176559786
1098 zero 12 143 37.5859203007
1099 zero 12 144 37.8416168850
1100 zero 12 145 38.1035617509
1101 zero 12 146 38.3659971714
1102 zero 12 147 38.6281759948
1103 zero 12 148 38.8902866009
1104 zero 12 149 39.1524611425
1105 zero 12 150 39.4148316663
1106 zero 12 151 39.6773035541
1107 zero 12 152 39.9400009818
1108 zero 12 153 40.2034183298
1109 zero 12 154 40.4686415139
1110 zero 12 155 40.7469925495
1111 zero 12 156 40.9220214008
1112 zero 12 157 41.2369513854
1113 zero 12 158 41.5030157455
1114 zero 12 159 41.7664337065
1115 zero 12 160 42.0294081778
1116 zero 12 161 42.2918745908
1117 zero 12 162 42.5541870150
1118 zero 12 163 42.8168517873
1119 zero 12 164 43.0792698655
1120 zero 12 165 43.3276179399
1121 zero 12 166 43.6022037528
1122 zero 12 167 43.8646422884
1123 zero 12 168 44.1269307273
1124 zero 12 169 44.3888989638
1125 zero 12 170 44.6510861679
1126 zero 12 171 44.9131583379
1127 zero 12 172 45.1754950018
1128 zero 12 173 45.4373624771
1129 zero 12 174 45.6999092122
1130 zero 12 175 45.9619914942
1131 zero 12 176 46.2242102651
1132 zero 12 177 46.4863543548
1133 zero 12 178 46.7493525798
1134 zero 12 179 47.0117207122
1135 zero 12 180 47.2749612834
1136 zero 12 181 47.5394395697
1137 zero 12 182 47.8111530615
1138 zero 12 183 48.0076287024
1139 zero 12 184 48.3144253024
1140 zero 12 185 48.5801788280
1141 zero 12 186 48.8449475975
1142 zero 12 187 49.1105215900
1143 zero 12 188 49.3796099278
1144 zero 12 189 49.7098670562
1145 zero 12 190 49.7864939195
1146 zero 12 191 50.1326553587
1147 zero 12 192 50.4017734330
1148 zero 12 193 50.6668687479
1149 zero 12 194 50.9306841216
1150 zero 12 195 51.1941396018
1151 zero 12 196 51.4566705177
1152 zero 12 197 51.7196653372
1153 zero 12 198 51.9827445204
1154 zero 12 199 52.2463980059
1155 zero 12 200 52.5108781780
1156 zero 12 201 52.7852495270
1157 zero 12 202 52.9731056317
1158 zero 12 203 53.2827145827
1159 zero 12 204 53.5482605459
1160 zero 12 205 53.8117019223
1161 zero 12 206 54.0747095932
1162 zero 12 207 54.3367543787
1163 zero 12 208 54.5995637339
1164 zero 12 209 54.8615040402
1165 zero 12 210 55.1237822515
1166 zero 12 211 55.3857332770
1167 zero 12 212 55.6482990203
1168 zero 12 213 55.9104558976
1169 zero 12 214 56.1727346122
1170 zero 12 215 56.4457778111
1171 zero 12 216 56.6960042639
1172 zero 12 217 56.9581163738
1173 zero 12 218 57.2206617538
1174 zero 12 219 57.4827508596
1175 zero 12 220 57.7449671753
1176 zero 12 221 58.0069526030
1177 zero 12 222 58.2690678831
1178 zero 12 223 58.5320344886
1179 zero 12 224 58.7940766946
1180 zero 12 225 59.0575930980
1181 zero 12 226 59.3458232429
1182 zero 12 227 59.5757233314
1183 zero 12 228 59.8404232219
1184 zero 12 229 60.1041919675
1185 zero 12 230 60.3691069544
1186 zero 12 231 60.6412690555
1187 zero 12 232 60.8343617850
1188 zero 12 233 61.1418446910
1189 zero 12 234 61.4070481267
1190 zero 12 235 61.6702510189
1191 zero 12 236 61.9330741065
1192 zero 12 237 62.1954024147
1193 zero 12 238 62.4582378967
1194 zero 12 239 62.7199515048
1195 zero 12 240 62.9823019089
1196 zero 12 241 63.2450235761
1197 zero 12 242 63.5068832792
1198 zero 12 243 63.7697620804
1199 zero 12 244 64.0320871463
1200 zero 12 245 64.2937591694
1201 zero 12 246 64.5572885711
1202 zero 12 247 64.8208026158
1203 zero 12 248 65.1111619774
1204 zero 12 249 65.3373963448
1205 zero 12 250 65.6027412081
1206 zero 12 251 65.8659442070
1207 zero 12 252 66.1300967454
1208 zero 12 253 66.3945461770
1209 zero 12 254 66.6620466536
1210 zero 12 255 66.9664877057
1211 zero 12 256 67.0862819049
1212 zero 12 257 67.4207467592
1213 zero 12 258 67.6885143985
1214 zero 12 259 67.9536180076
1215 zero 12 260 68.2165753020
1216 zero 12 261 68.4792882819
1217 zero 12 262 68.7423319042
1218 zero 12 263 69.0050995990
1219 zero 12 264 69.2680113823
1220 zero 12 265 69.5457240691
1221 zero 12 266 69.7906110114
1222 zero 12 267 70.0537784829
1223 zero 12 268 70.3165877346
1224 zero 12 269 70.5798927668
1225 zero 12 270 70.8412116905
1226 zero 12 271 71.1054243894
1227 zero 12 272 71.3699125761
1228 zero 12 273 71.6357379733
1229 zero 12 274 71.9287399502
1230 zero 12 275 72.0720190435
1231 zero 12 276 72.3994286750
1232 zero 12 277 72.6654259855
1233 zero 12 278 72.9309889713
1234 zero 12 279 73.1936861848
1235 zero 12 280 73.4569981730
1236 zero 12 281 73.7196879509
1237 zero 12 282 73.9828082382
1238 zero 12 283 74.2458103653
1239 zero 12 284 74.5094664369
1240 zero 12 285 74.7725763976
1241 zero 12 286 75.0376226679
1242 zero 12 287 75.3067709036
1243 zero 12 288 75.6332610248
1244 zero 12 289 75.7159456901
1245 zero 12 290 76.0607064137
1246 zero 12 291 76.3295403413
1247 zero 12 292 76.5958029437
1248 zero 12 293 76.8594180636
1249 zero 12 294 77.1438553775
1250 zero 12 295 77.3823714444
1251 zero 12 296 77.6460403530
1252 zero 12 297 77.9102583564
1253 zero 12 298 78.1732408109
1254 zero 12 299 78.4371654539
1255 zero 12 300 78.7031910897
1256 zero 12 301 78.9718427734
1257 zero 12 302 79.3202569626
1258 zero 12 303 79.3855441665
1259 zero 12 304 79.7239790085
1260 zero 12 305 79.9930868997
1261 zero 12 306 80.2586197110
1262 zero 12 307 80.5210189351
1263 zero 12 308 80.7854174412
1264 zero 12 309 81.0476216379
1265 zero 12 310 81.3102240185
1266 zero 12 311 81.5729926865
1267 zero 12 312 81.8358392525
1268 zero 12 313 82.0985530412
1269 zero 12 314 82.3605919211
1270 zero 12 315 82.6247561393
1271 zero 12 316 82.9093035045
1272 zero 12 317 83.1436147756
1273 zero 12 318 83.4076732379
1274 zero 12 319 83.6702116283
1275 zero 12 320 83.9330806183
1276 zero 12 321 84.1942434270
1277 zero 12 322 84.4574476778
1278 zero 12 323 84.7348534479
1279 zero 12 324 84.9797906505
1280 zero 12 325 85.2435746145
1281 zero 12 326 85.5057317865
1282 zero 12 327 85.7691973509
1283 zero 12 328 86.0318286596
1284 zero 12 329 86.2950323352
1285 zero 12 330 86.5577521992
1286 zero 12 331 86.8231392996
1287 zero 12 332 87.0907015855
1288 zero 12 333 87.4200817405
1289 zero 12 334 87.5595013723
1290 zero 12 335 87.8537411242
1291 zero 12 336 88.1236351604
1292 zero 12 337 88.3935414783
1293 zero 12 338 88.7037593921
1294 zero 12 339 88.8162425824
1295 zero 12 340 89.1539549402
1296 zero 12 341 89.4230314843
1297 zero 12 342 89.6872374228
1298 zero 12 343 89.9501739501
1299 zero 12 344 90.2148802269
1300 zero 12 345 90.4768319666
1301 zero 12 346 90.7411910997
1302 zero 12 347 91.0033468382
1303 zero 12 348 91.2664390659
1304 zero 12 349 91.5304232355
1305 zero 12 350 91.7946308452
1306 zero 12 351 92.0624269798
1307 zero 12 352 92.3556260374
1308 zero 12 353 92.4970141272
1309 zero 12 354 92.8225818949
1310 zero 12 355 93.0908173530
1311 zero 12 356 93.3556801010
1312 zero 12 357 93.6192492132
1313 zero 12 358 93.8839854482
1314 zero 12 359 94.1457198486
1315 zero 12 360 94.4124715612
1316 zero 12 361 94.6521501953
1317 zero 12 362 94.9345005936
1318 zero 12 363 95.2000223950
1319 zero 12 364 95.4706501252
1320 zero 12 365 95.7895253229
1321 zero 12 366 95.8805345969
1322 zero 12 367 96.2235165842
1323 zero 12 368 96.4928669404
1324 zero 12 369 96.7573268785
1325 zero 12 370 97.0215074360
1326 zero 12 371 97.2851041760
1327 zero 12 372 97.5451715759
1328 zero 12 373 97.8105275667
1329 zero 12 374 98.0734917391
1330 zero 12 375 98.3368777209
1331 zero 12 376 98.6002313040
1332 zero 12 377 98.8323721971
1333 zero 12 378 99.1181780262
1334 zero 12 379 99.3839449163
1335 zero 12 380 99.6463809041
1336 zero 12 381 99.9101890757
1337 zero 12 382 100.1721403186
1338 zero 12 383 100.4348603367
1339 zero 12 384 100.7010521229
1340 zero 12 385 100.9711346769
1341 zero 12 386 101.3097723983
1342 zero 12 387 101.4136486392
1343 zero 12 388 101.7275761858
1344 zero 12 389 101.9962809758
1345 zero 12 390 102.2617967357
1346 zero 12 391 102.5254979195
1347 zero 12 392 102.7909088881
1348 zero 12 393 103.0567541990
1349 zero 12 394 103.3228982613
1350 zero 12 395 103.6479368709
1351 zero 12 396 103.7358504644
1352 zero 12 397 104.0807250760
1353 zero 12 398 104.3508732829
1354 zero 12 399 104.6142876554
1355 zero 12 400 104.8794809566
1356 zero 12 401 105.1452319766
1357 zero 12 402 105.4447460287
1358 zero 12 403 105.6584157942
1359 zero 12 404 105.9246429137
1360 zero 12 405 106.1897582044
1361 zero 12 406 106.4560256312
1362 zero 12 407 106.7229532077
1363 zero 12 408 107.0014633318
1364 zero 12 409 107.1721823888
1365 zero 12 410 107.4890813765
1366 zero 12 411 107.7563766235
1367 zero 12 412 108.0217125088
1368 zero 12 413 108.2818080666
1369 zero 12 414 108.5461046957
1370 zero 12 415 108.8095017504
1371 zero 12 416 109.0711297448
1372 zero 12 417 109.3368122283
1373 zero 12 418 109.5995061239
1374 zero 12 419 109.8635124526
1375 zero 12 420 110.1257509795
1376 zero 12 421 110.3908081988
1377 zero 12 422 110.6643564270
1378 zero 12 423 111.0109679885
1379 zero 12 424 111.0752898842
1380 zero 12 425 111.4203001140
1381 zero 12 426 111.7087974469
1382 zero 12 427 111.8784059504
1383 zero 12 428 112.1983213419
1384 zero 12 429 112.4666089080
1385 zero 12 430 112.7327118663
1386 zero 12 431 112.9905225383
1387 zero 12 432 113.2550418735
1388 zero 12 433 113.5180707700
1389 zero 12 434 113.7829677089
1390 zero 12 435 114.0463473604
1391 zero 12 436 114.3197142156
1392 zero 12 437 114.5729796788
1393 zero 12 438 114.8307985495
1394 zero 12 439 115.0946143017
1395 zero 12 440 115.3606847372
1396 zero 12 441 115.6257445667
1397 zero 12 442 115.8907020810
1398 zero 12 443 116.2212900445
1399 zero 12 444 116.3572227200
1400 zero 12 445 116.6565595983
1401 zero 12 446 116.9187883723
1402 zero 12 447 117.1822548863
1403 zero 12 448 117.4467633440
1404 zero 12 449 117.7091279508
1405 zero 12 450 117.9755706587
1406 zero 12 451 118.2345996467
1407 zero 12 452 118.4982143629
1408 zero 12 453 118.7894722659
1409 zero 12 454 119.0170555063
1410 zero 12 455 119.2827873082
1411 zero 12 456 119.5416379197
1412 zero 12 457 119.8071686167
1413 zero 12 458 120.0681359652
1414 zero 12 459 120.3301691912
1415 zero 12 460 120.5925063311
1416 zero 12 461 120.8564712271
1417 zero 12 462 121.1167180533
1418 zero 12 463 121.3705605964
1419 zero 12 464 121.6423142768
1420 zero 12 465 121.9003936101
1421 zero 12 466 122.1674182610
1422 zero 12 467 122.4280233163
1423 zero 12 468 122.6915202149
1424 zero 12 469 122.9469343472
1425 zero 12 470 123.2161035053
1426 zero 12 471 123.4788715972
1427 zero 12 472 123.7432174418
1428 zero 12 473 123.9996423963
1429 zero 12 474 124.2570297249
1430 zero 12 475 124.5254875229
1431 zero 12 476 124.7869231388
1432 zero 12 477 125.0503867945
1433 zero 12 478 125.3113854403
1434 zero 12 479 125.5758598999
1435 zero 12 480 125.8392467595
1436 zero 12 481 126.0953180376
1437 zero 12 482 126.3634020929
1438 zero 12 483 126.6316530470
1439 zero 12 484 126.8896597795
1440 zero 12 485 127.1603509275
1441 zero 12 486 127.5056482545
1442 zero 12 487 127.5901455171
1443 zero 12 488 127.9202269216
1444 zero 12 489 128.1798453948
1445 zero 12 490 128.4478359760
1446 zero 12 491 128.7136924971
1447 zero 12 492 128.9790649165
1448 zero 12 493 129.2467182282
1449 zero 12 494 129.5738902674
1450 zero 12 495 129.7213998743
1451 zero 12 496 130.0102421267
1452 zero 12 497 130.2788672385
1453 zero 12 498 130.5431423075
1454 zero 12 499 130.8069842661
1455 zero 12 500 131.0868974439
1456 zero 12 501 131.3286246295
1457 zero 12 502 131.5938849037
1458 zero 12 503 131.8605005564
1459 zero 12 504 132.1172149836
1460 zero 12 505 132.3809687697
1461 zero 12 506 132.6451539909
1462 zero 12 507 132.9146326585
1463 zero 12 508 133.1759419981
1464 zero 12 509 133.4940465769
1465 zero 12 510 133.6612136807
1466 zero 12 511 133.9445082258
1467 zero 12 512 134.2133764699
1468 zero 12 513 134.4657328489
1469 zero 12 514 134.7554054148
1470 zero 12 515 134.9949093751
1471 zero 12 516 135.2565635922
1472 zero 12 517 135.5203723848
1473 zero 12 518 135.7830998781
1474 zero 12 519 136.0443299363
1475 zero 12 520 136.3091979512
1476 zero 12 521 136.5723580566
1477 zero 12 522 136.8410132505
1478 zero 12 523 137.0911355796
1479 zero 12 524 137.3547280414
1480 zero 12 525 137.6207342143
1481 zero 12 526 137.8829255192
1482 zero 12 527 138.1171343824
1483 zero 12 528 138.4048429013
1484 zero 12 529 138.6665627522
1485 zero 12 530 138.9282214460
1486 zero 12 531 139.1929536460
1487 zero 12 532 139.4523270176
1488 zero 12 533 139.7355434039
1489 zero 12 534 139.9730609370
1490 zero 12 535 140.2433895151
1491 zero 12 536 140.5102676066
1492 zero 12 537 140.7777298416
1493 zero 12 538 141.1158801654
1494 zero 12 539 141.2218368089
1495 zero 12 540 141.5332125986
1496 zero 12 541 141.7984799753
1497 zero 12 542 142.0692279903
1498 zero 12 543 142.3310095156
1499 zero 12 544 142.5967626863
1500 zero 12 545 142.8475388989
1501 zero 12 546 143.1119926696

E-019-zeroflow-a12.json — 2.4 KB, updated 08-18-2026

JSON sidecar (click to expand)
{
  "experiment": "E-019",
  "task": "2.8(ii): backend v2 validation + zero-flow at a=12",
  "script": "research/numerics/scripts/E-019-zeroflow-a12.py",
  "parameters": {
    "a_val": 10.0,
    "a_new": 12.0,
    "h": 0.01,
    "lambda": -1.0,
    "z_max": 300.0
  },
  "checks": {
    "VA1_backend_matches": true,
    "VA2_pipeline_a10": true,
    "B3_no_new_complex_zeros": true
  },
  "report": {
    "validation": {
      "VA1_max_dev": 2.2246968001127243e-07,
      "VA2_Q_dev": 4.3871651103644105e-08,
      "VA2_z1_dev": 6.942222297023903e-09,
      "VA2_count_diff": 0
    },
    "B1_zeroflow": {
      "a10": {
        "n": 954,
        "z1": 0.44959701245436284,
        "z1_times_a": 4.4959701245436285,
        "count_vs_lattice": 954.9296585513721,
        "gap_mean": 0.31421194329970964,
        "gap_cv": 0.19770812588191275
      },
      "a12": {
        "n": 1145,
        "z1": 0.3746087478472408,
        "z1_times_a": 4.495304974166889,
        "count_vs_lattice": 1145.9155902616465,
        "gap_mean": 0.26188092266824087,
        "gap_cv": 0.18590651886845952
      }
    },
    "B2_gamma_locking": {
      "a10": {
        "min": 0.00020978025152373903,
        "zero_idx": 245,
        "gamma_idx": 20,
        "zero": 77.14504984912632,
        "gamma": 77.1448400688748,
        "median": 48.899737666799254
      },
      "a12": {
        "min": 5.2439703061679666e-05,
        "zero_idx": 95,
        "gamma_idx": 3,
        "zero": 25.010805140442628,
        "gamma": 25.01085758014569,
        "median": 48.79267672793192
      }
    },
    "B3_strip_winding": {
      "a10": {
        "1.0": {
          "winding": 253.99999999999946,
          "real_inside": 252,
          "excess": 1.99999999999946
        },
        "0.1": {
          "winding": 253.99999999999946,
          "real_inside": 252,
          "excess": 1.99999999999946
        }
      },
      "a12": {
        "1.0": {
          "winding": 305.9999999999994,
          "real_inside": 304,
          "excess": 1.9999999999993747
        },
        "0.1": {
          "winding": 305.9999999999993,
          "real_inside": 304,
          "excess": 1.9999999999993179
        }
      }
    },
    "B4_envelope": {
      "median_M_over_R0_y0.3": 0.006526107920803935
    }
  },
  "elapsed_seconds": 672.2,
  "timestamp_utc": "2026-08-18T19:32:51.149654+00:00"
}

Source code

Python script (click to expand)
"""E-019 — task 2.8(ii): backend v2 validation (A) + zero-flow at a=12 (B).

Sub-stage A (validation gate, all must pass before a=12 is trusted):
  V-A1. prime_backend_v2 vs E-016 in-memory cumsums: max |dev| on 1e4
        random t in (0,20] < 1e-6 abs (float64 summation-reordering
        noise floor ~2e-7 measured; both backends carry the same
        rounding level, so agreement at this level = exact).
  V-A2. full pipeline at a=10 with the v2 backend: stiffness matrix Q
        vs E16.build(10) entrywise max dev < 1e-8; located zeros at
        a=10 match the E-016 family (z1 dev < 1e-6; count equal).

Sub-stage B (measurements at a=12, theta=pi):
  B1. zero-flow: located real zeros (0,300]: count vs aT/pi, z1*a law,
      gap statistics vs a=10 (inflow continues? any bounce?).
  B2. gamma-locking metric: min |z_j - gamma_k| over first 30 Riemann
      zeros (mpmath zetazero, safe per STATE) vs a=10 value.
  B3. strip winding counts: W-zeros in |Re z| <= 40, |Im z| <= y0 for
      y0 in {1, 0.1} (argument principle; detects any non-real
      deviation beyond the known origin pair).
  B4. envelope spot check: median |M|/|R_0| at y0 = 0.3 (E-018 family).

Outputs: research/numerics/data/E-019-zeroflow-a12.csv (+ .json)
"""
import importlib.util
import json
import sys
import time
from datetime import datetime, timezone
from pathlib import Path

import mpmath as mp
import numpy as np
import scipy.optimize

REPO = Path(__file__).resolve().parents[3]
DATA = REPO / "research" / "numerics" / "data"
CSV = DATA / "E-019-zeroflow-a12.csv"
JSON = DATA / "E-019-zeroflow-a12.json"

_spec = importlib.util.spec_from_file_location(
    "E16", Path(__file__).with_name("E-016-herglotz-fine-structure.py"))
E16 = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(E16)                     # runs the e^20 sieve

sys.path.insert(0, str(Path(__file__).parent))
from prime_backend_v2 import PrimeBackendV2       # noqa: E402

H = E16.H_MAIN
LAM = E16.LAM_SHIFT
A_VAL = 10.0
A_NEW = 12.0
Z_MAX = 300.0
N_GRID = 40000
mp.mp.dps = 40

XN, XW = E16.XN, E16.XW


def collect_t_points(a, h):
    """Replicates E-016 S_full/quad segment structure (no g evaluation)
    to enumerate every quadrature abscissa t in (0, 2a)."""
    n_elem = int(round(2 * a / h))
    pts = []

    def add_quad(lo, hi, peak):
        n_lo = int(np.ceil(np.exp(lo)))
        n_hi = int(np.floor(np.exp(hi)))
        if n_hi - n_lo > 64:
            for aa, bb in ((lo, peak), (peak, hi)):
                if bb - aa > 0:
                    mid, half = 0.5 * (aa + bb), 0.5 * (bb - aa)
                    pts.extend(mid + half * XN)
            return
        segs = sorted({lo, peak, hi} |
                      {float(np.log(n))
                       for n in range(max(n_lo, 2), n_hi + 1)
                       if lo < np.log(n) < hi})
        for p0, p1 in zip(segs, segs[1:]):
            if p1 - p0 > 0:
                mid, half = 0.5 * (p0 + p1), 0.5 * (p1 - p0)
                pts.extend(mid + half * XN)

    for k in range(n_elem):
        if k == 0:
            add_quad(0.0, h, 0.0)
        else:
            add_quad((k - 1) * h, (k + 1) * h, k * h)
    return np.array(pts)


def locate_zeros(cp, x, h, z_max=Z_MAX, n_grid=N_GRID):
    zg = np.linspace(1e-3, z_max, n_grid)
    Vpr, _ = E16.V_and_dV(zg, cp, x, h)
    g = zg * Vpr.imag - Vpr.real

    def g_direct(zz):
        V = E16.hat_FT(np.array([zz]), h)[0] * complex(
            np.exp(1j * zz * x) @ cp)
        return zz * V.imag - V.real

    idx = np.flatnonzero(np.sign(g[:-1]) * np.sign(g[1:]) < 0)
    zeros = []
    for i in idx:
        try:
            zeros.append(scipy.optimize.brentq(g_direct, zg[i], zg[i + 1],
                                               xtol=1e-13, rtol=1e-13))
        except ValueError:
            pass
    return np.array(zeros)


def winding_rect(cp, cm, x, h, half_re, half_im, n_per_edge=4000):
    """Zeros of W(theta=pi) inside |Re z|<=half_re, |Im z|<=half_im via
    the argument principle (direct evaluation, e^{+-a*y0} range OK at
    y0 <= 1, a <= 12)."""
    edges = []
    xr = np.linspace(-half_re, half_re, n_per_edge)
    yr = np.linspace(-half_im, half_im, max(8, n_per_edge // 10))
    edges.append(xr - 1j * half_im)          # bottom, left->right
    edges.append(half_re + 1j * yr)          # right, bottom->top
    edges.append(xr[::-1] + 1j * half_im)    # top, right->left
    edges.append(-half_re + 1j * yr[::-1])   # left, top->bottom
    total = 0.0
    for z in edges:
        Vp, _ = E16.V_and_dV(z, cp, x, h)
        Vm, _ = E16.V_and_dV(z, cm, x, h)
        W = (z - 1j) * Vp - (z + 1j) * Vm
        total += np.diff(np.unwrap(np.angle(W))).sum()
    return total / (2 * np.pi)


def solve_ab(a, h):
    x, hh, Q, M, b = E16.build(a, h)
    n = len(x)
    cp, T = E16.solve_v(Q, M, b[+1.0], LAM, n)
    cm, _ = E16.solve_v(Q, M, b[-1.0], LAM, n)
    np_ = float(cp @ T @ cp)
    nm = float(cm @ T @ cm)
    return x, hh, cp, cm * np.sqrt(np_ / nm), Q


def main() -> int:
    if CSV.exists() and "--force" not in sys.argv:
        print(f"cached: {CSV} (use --force to recompute)")
        return 0
    t0 = time.time()
    report = {}

    # ---------------- backend v2: collect queries & build -------------
    print("collecting quadrature t-points (a=10 & a=12) ...", flush=True)
    rng = np.random.default_rng(19)
    t_rand = np.sort(rng.uniform(0.01, 20.0, 10000))
    tq = np.concatenate([collect_t_points(A_VAL, H),
                         collect_t_points(A_NEW, H), t_rand])
    print(f"  {tq.size} points; building backend to e^24 ...", flush=True)
    CACHE = DATA / "E-019-backend-cache.npz"
    be = PrimeBackendV2(tq)
    if CACHE.exists() and "--force" not in sys.argv:
        be.load_cache(CACHE)
        print("  backend loaded from cache", flush=True)
    else:
        be.build(verbose=True)
        be.save_cache(CACHE)

    # ---------------- A: validation -----------------------------------
    print("V-A1: backend vs E-016 in-memory cumsums ...", flush=True)
    p_ref = E16.prime_sum_vec(t_rand)
    p_new = be.prime_sum(t_rand)
    va1 = float(np.max(np.abs(p_ref - p_new)))
    print(f"  V-A1 max |dev|: {va1:.2e}", flush=True)

    print("V-A2: full pipeline at a=10 (v2 backend) ...", flush=True)
    orig_psv = E16.prime_sum_vec
    # reference build with the ORIGINAL backend first
    x10r, hh10r, cp10r, cm10r, Q_ref = solve_ab(A_VAL, H)
    zeros10r = locate_zeros(cp10r, x10r, hh10r)
    # rebuild with v2 backend (cache must be cleared — keyed on (a,h))
    E16._BUILD.clear()
    E16.prime_sum_vec = be.prime_sum
    x10, hh10, cp10, cm10, Q_new = solve_ab(A_VAL, H)
    E16.prime_sum_vec = orig_psv
    va2_q = float(np.max(np.abs(Q_new - Q_ref)))
    zeros10 = locate_zeros(cp10, x10, hh10)
    z1_10 = float(zeros10[0])
    va2_z1 = abs(z1_10 - float(zeros10r[0]))
    va2_cnt = abs(len(zeros10) - len(zeros10r))
    print(f"  V-A2 Q dev {va2_q:.2e}; z1 dev {va2_z1:.2e}; "
          f"count diff {va2_cnt}", flush=True)
    report["validation"] = {"VA1_max_dev": va1, "VA2_Q_dev": va2_q,
                            "VA2_z1_dev": va2_z1, "VA2_count_diff": va2_cnt}

    # ---------------- B: a=12 measurements ----------------------------
    print("B: a=12 build + zeros + winding ...", flush=True)
    E16.prime_sum_vec = be.prime_sum
    x12, hh12, cp12, cm12, _ = solve_ab(A_NEW, H)
    E16.prime_sum_vec = orig_psv
    zeros12 = locate_zeros(cp12, x12, hh12)

    # B1 zero-flow
    gaps10 = np.diff(zeros10)
    gaps12 = np.diff(zeros12)
    b1 = {
        "a10": {"n": int(len(zeros10)), "z1": z1_10,
                "z1_times_a": z1_10 * A_VAL,
                "count_vs_lattice": A_VAL * Z_MAX / np.pi,
                "gap_mean": float(gaps10.mean()),
                "gap_cv": float(gaps10.std() / gaps10.mean())},
        "a12": {"n": int(len(zeros12)), "z1": float(zeros12[0]),
                "z1_times_a": float(zeros12[0]) * A_NEW,
                "count_vs_lattice": A_NEW * Z_MAX / np.pi,
                "gap_mean": float(gaps12.mean()),
                "gap_cv": float(gaps12.std() / gaps12.mean())},
    }
    print(f"  B1 a=12: n={b1['a12']['n']} (lattice "
          f"{b1['a12']['count_vs_lattice']:.0f}) z1*a="
          f"{b1['a12']['z1_times_a']:.4f} gap_cv={b1['a12']['gap_cv']:.4f}",
          flush=True)

    # B2 gamma-locking
    gammas = np.array([float(mp.zetazero(k).imag) for k in range(1, 31)])
    def lock_metric(zeros):
        d = np.abs(zeros[:, None] - gammas[None, :])
        j, k = np.unravel_index(np.argmin(d), d.shape)
        dmin = np.min(d, axis=1)
        return (float(d[j, k]), int(j + 1), int(k + 1),
                float(zeros[j]), float(gammas[k]),
                float(np.median(dmin)))
    lm10 = lock_metric(zeros10)
    lm12 = lock_metric(zeros12)
    b2 = {"a10": {"min": lm10[0], "zero_idx": lm10[1], "gamma_idx": lm10[2],
                  "zero": lm10[3], "gamma": lm10[4], "median": lm10[5]},
          "a12": {"min": lm12[0], "zero_idx": lm12[1], "gamma_idx": lm12[2],
                  "zero": lm12[3], "gamma": lm12[4], "median": lm12[5]}}
    print(f"  B2 lock: a=10 min {lm10[0]:.5f} (z_{lm10[1]}={lm10[3]:.4f} "
          f"vs g_{lm10[2]}={lm10[4]:.4f}); a=12 min {lm12[0]:.5f} "
          f"(z_{lm12[1]}={lm12[3]:.4f} vs g_{lm12[2]}={lm12[4]:.4f})",
          flush=True)

    # B3 strip winding (a=12 and a=10 for comparison)
    b3 = {}
    for tag, cp, cm, x, hh in (("a10", cp10, cm10, x10, hh10),
                               ("a12", cp12, cm12, x12, hh12)):
        real_in = {}
        for y0 in (1.0, 0.1):
            w = winding_rect(cp, cm, x, hh, 40.0, y0)
            zz = zeros10 if tag == "a10" else zeros12
            n_real = int(2 * np.sum(zz <= 40.0))
            real_in[str(y0)] = {"winding": w, "real_inside": n_real,
                                "excess": w - n_real}
        b3[tag] = real_in
    print(f"  B3: {b3}", flush=True)

    # B4 envelope spot check at y0 = 0.3 (E-018 family), a=12
    def R0_exact(a, th, z):
        z = np.asarray(z, dtype=complex)
        t1 = -2j * (np.sinh(a * (1 + 1j * z))
                    + np.exp(1j * th) * np.sinh(a * (1j * z - 1)))
        t2 = (2j * np.sin(a * z) / z) * ((z - 1j) - np.exp(1j * th)
                                         * (z + 1j))
        return t1 + t2
    xg = np.linspace(-20, 20, 41) + 0.3j
    xm = x12.min()
    u = x12 - xm
    E = np.exp(1j * np.outer(xg, u))
    hat = E16.hat_FT(xg, hh12)
    W = np.exp(1j * xm * xg) * ((xg - 1j) * (hat * (E @ cp12))
                                - (xg + 1j) * (hat * (E @ cm12)))
    Fv = np.array([])
    def F_complex(z):
        s = mp.mpc(0.5 + z.imag, -z.real)
        val = 0.5 * s * (s - 1) * mp.pi ** (-s / 2) * mp.gamma(s / 2) \
            * mp.zeta(s)
        dval = mp.diff(lambda t: 0.5 * t * (t - 1) * mp.pi ** (-t / 2)
                       * mp.gamma(t / 2) * mp.zeta(t), s)
        return complex(z**2 * val / dval)
    Fv = np.array([F_complex(z) for z in xg])
    ratio = np.abs(W / Fv) / np.abs(R0_exact(A_NEW, np.pi, xg))
    b4 = {"median_M_over_R0_y0.3": float(np.median(ratio))}
    print(f"  B4 median |M/R0| at y0=0.3: {b4['median_M_over_R0_y0.3']:.3e}",
          flush=True)

    report.update({"B1_zeroflow": b1, "B2_gamma_locking": b2,
                   "B3_strip_winding": b3, "B4_envelope": b4})

    checks = {
        "VA1_backend_matches": va1 < 1e-6,
        "VA2_pipeline_a10": va2_q < 1e-6 and va2_z1 < 1e-6
        and va2_cnt == 0,
        "B3_no_new_complex_zeros": all(
            abs(b3[t][y]["excess"]) < 2.5 for t in b3 for y in b3[t]),
    }
    with CSV.open("w", encoding="utf-8", newline="") as f:
        f.write("series,a,j,value\n")
        for j, z in enumerate(zeros10):
            f.write(f"zero,10,{j+1},{z:.10f}\n")
        for j, z in enumerate(zeros12):
            f.write(f"zero,12,{j+1},{z:.10f}\n")
        for k, g in enumerate(gammas):
            f.write(f"gamma,-,{k+1},{g:.10f}\n")
    meta = {
        "experiment": "E-019",
        "task": "2.8(ii): backend v2 validation + zero-flow at a=12",
        "script": "research/numerics/scripts/E-019-zeroflow-a12.py",
        "parameters": {"a_val": A_VAL, "a_new": A_NEW, "h": H,
                       "lambda": LAM, "z_max": Z_MAX},
        "checks": checks,
        "report": report,
        "elapsed_seconds": round(time.time() - t0, 1),
        "timestamp_utc": datetime.now(timezone.utc).isoformat(),
    }
    JSON.write_text(json.dumps(meta, indent=2), encoding="utf-8")
    ok = all(checks.values())
    print(f"wrote {CSV.name}, {JSON.name} — "
          f"{'ALL CHECKS PASS' if ok else 'CHECK FAILURE: ' + str(checks)}")
    return 0 if ok else 1


if __name__ == "__main__":
    raise SystemExit(main())