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 4 of 5 · 500/page · 2129 rows next →
# seriesajvalue
1502 zero 12 547 143.3793410571
1503 zero 12 548 143.6420177306
1504 zero 12 549 143.9053378934
1505 zero 12 550 144.1675901991
1506 zero 12 551 144.4361035908
1507 zero 12 552 144.6906459018
1508 zero 12 553 144.9519490464
1509 zero 12 554 145.2178018368
1510 zero 12 555 145.4803082382
1511 zero 12 556 145.7448693536
1512 zero 12 557 146.0011958951
1513 zero 12 558 146.2667760166
1514 zero 12 559 146.5262655574
1515 zero 12 560 146.7941962154
1516 zero 12 561 147.0659120405
1517 zero 12 562 147.4117334767
1518 zero 12 563 147.4974304462
1519 zero 12 564 147.8222357276
1520 zero 12 565 148.0914874426
1521 zero 12 566 148.3558516001
1522 zero 12 567 148.6233988522
1523 zero 12 568 148.8862061373
1524 zero 12 569 149.1478144127
1525 zero 12 570 149.4092003317
1526 zero 12 571 149.6862022682
1527 zero 12 572 150.0370112959
1528 zero 12 573 150.1105277337
1529 zero 12 574 150.4327576292
1530 zero 12 575 150.7139248509
1531 zero 12 576 150.9272622097
1532 zero 12 577 151.2293060582
1533 zero 12 578 151.5043165184
1534 zero 12 579 151.7556356590
1535 zero 12 580 152.0196774973
1536 zero 12 581 152.2869176571
1537 zero 12 582 152.5561865953
1538 zero 12 583 152.8046750842
1539 zero 12 584 153.0265580890
1540 zero 12 585 153.3271428103
1541 zero 12 586 153.5938983265
1542 zero 12 587 153.8562138545
1543 zero 12 588 154.1206546180
1544 zero 12 589 154.3966507629
1545 zero 12 590 154.6367279257
1546 zero 12 591 154.9038449512
1547 zero 12 592 155.1737819623
1548 zero 12 593 155.4485203621
1549 zero 12 594 155.6977538782
1550 zero 12 595 156.0147315281
1551 zero 12 596 156.1208971404
1552 zero 12 597 156.4640293352
1553 zero 12 598 156.7319473468
1554 zero 12 599 156.9999482401
1555 zero 12 600 157.2734929037
1556 zero 12 601 157.5920480085
1557 zero 12 602 157.7412594486
1558 zero 12 603 158.0362268940
1559 zero 12 604 158.3014854357
1560 zero 12 605 158.5685864469
1561 zero 12 606 158.8482339623
1562 zero 12 607 159.0852760688
1563 zero 12 608 159.3481040795
1564 zero 12 609 159.6135151640
1565 zero 12 610 159.8763458616
1566 zero 12 611 160.1399774145
1567 zero 12 612 160.4033523196
1568 zero 12 613 160.6693138343
1569 zero 12 614 160.9156874807
1570 zero 12 615 161.1888613273
1571 zero 12 616 161.4518762775
1572 zero 12 617 161.7224896302
1573 zero 12 618 161.9781830798
1574 zero 12 619 162.2423268236
1575 zero 12 620 162.5146841070
1576 zero 12 621 162.7484708389
1577 zero 12 622 163.0303453962
1578 zero 12 623 163.2865102599
1579 zero 12 624 163.5485998830
1580 zero 12 625 163.8141488274
1581 zero 12 626 164.0819238804
1582 zero 12 627 164.3204792813
1583 zero 12 628 164.5978881601
1584 zero 12 629 164.8665157484
1585 zero 12 630 165.1357120729
1586 zero 12 631 165.4597267322
1587 zero 12 632 165.5476651350
1588 zero 12 633 165.8944360286
1589 zero 12 634 166.1763649240
1590 zero 12 635 166.4132588160
1591 zero 12 636 166.6854454664
1592 zero 12 637 166.9517652798
1593 zero 12 638 167.1858481092
1594 zero 12 639 167.4720397021
1595 zero 12 640 167.7380040187
1596 zero 12 641 167.9995044354
1597 zero 12 642 168.2543982512
1598 zero 12 643 168.5277536072
1599 zero 12 644 168.7966893605
1600 zero 12 645 169.0924007274
1601 zero 12 646 169.3039608764
1602 zero 12 647 169.5811124773
1603 zero 12 648 169.9074443220
1604 zero 12 649 170.0610110559
1605 zero 12 650 170.3649117269
1606 zero 12 651 170.6094996629
1607 zero 12 652 170.8732617475
1608 zero 12 653 171.1414485014
1609 zero 12 654 171.4032929699
1610 zero 12 655 171.6676818609
1611 zero 12 656 171.9469823472
1612 zero 12 657 172.1909885600
1613 zero 12 658 172.4563487379
1614 zero 12 659 172.7208815576
1615 zero 12 660 172.9916859236
1616 zero 12 661 173.2969846750
1617 zero 12 662 173.4175252218
1618 zero 12 663 173.7516249243
1619 zero 12 664 174.0189282419
1620 zero 12 665 174.3020428437
1621 zero 12 666 174.5606575494
1622 zero 12 667 174.7569827658
1623 zero 12 668 175.0625775926
1624 zero 12 669 175.3283733873
1625 zero 12 670 175.5944918248
1626 zero 12 671 175.8613353521
1627 zero 12 672 176.1289207492
1628 zero 12 673 176.4387202918
1629 zero 12 674 176.6327842259
1630 zero 12 675 176.9078472260
1631 zero 12 676 177.1712402167
1632 zero 12 677 177.4373314719
1633 zero 12 678 177.7005777104
1634 zero 12 679 177.9771099022
1635 zero 12 680 178.2621295625
1636 zero 12 681 178.3855119395
1637 zero 12 682 178.7316902957
1638 zero 12 683 179.0145624589
1639 zero 12 684 179.2413630810
1640 zero 12 685 179.5342027326
1641 zero 12 686 179.8803668770
1642 zero 12 687 179.9415798265
1643 zero 12 688 180.2965353227
1644 zero 12 689 180.5645164733
1645 zero 12 690 180.8471990373
1646 zero 12 691 181.0971497804
1647 zero 12 692 181.3810873665
1648 zero 12 693 181.6047166352
1649 zero 12 694 181.8780440458
1650 zero 12 695 182.2032567838
1651 zero 12 696 182.3728858214
1652 zero 12 697 182.6566939108
1653 zero 12 698 182.9199908591
1654 zero 12 699 183.1903513257
1655 zero 12 700 183.4516143964
1656 zero 12 701 183.7202818004
1657 zero 12 702 183.9912548257
1658 zero 12 703 184.2514539742
1659 zero 12 704 184.5167272348
1660 zero 12 705 184.8652754088
1661 zero 12 706 184.9681652807
1662 zero 12 707 185.3128593408
1663 zero 12 708 185.5931673643
1664 zero 12 709 185.7591859627
1665 zero 12 710 186.0574250826
1666 zero 12 711 186.3265555282
1667 zero 12 712 186.6096732443
1668 zero 12 713 186.8590234108
1669 zero 12 714 187.2148145222
1670 zero 12 715 187.2888593237
1671 zero 12 716 187.6221965503
1672 zero 12 717 187.8929748141
1673 zero 12 718 188.1610933201
1674 zero 12 719 188.4148080794
1675 zero 12 720 188.6885734378
1676 zero 12 721 188.9546309850
1677 zero 12 722 189.2308494314
1678 zero 12 723 189.4190702524
1679 zero 12 724 189.7167167107
1680 zero 12 725 189.9969418572
1681 zero 12 726 190.2647012216
1682 zero 12 727 190.5317604531
1683 zero 12 728 190.7673096697
1684 zero 12 729 191.0496951011
1685 zero 12 730 191.3171383791
1686 zero 12 731 191.5892330714
1687 zero 12 732 191.8949681673
1688 zero 12 733 192.0357479760
1689 zero 12 734 192.3283064327
1690 zero 12 735 192.6033153015
1691 zero 12 736 192.8854607798
1692 zero 12 737 193.0825194906
1693 zero 12 738 193.3934445557
1694 zero 12 739 193.6620541891
1695 zero 12 740 193.9213184373
1696 zero 12 741 194.1870787376
1697 zero 12 742 194.4410384677
1698 zero 12 743 194.7133693427
1699 zero 12 744 194.9802812775
1700 zero 12 745 195.2643324141
1701 zero 12 746 195.5028049612
1702 zero 12 747 195.7687334547
1703 zero 12 748 196.0545766829
1704 zero 12 749 196.2550305092
1705 zero 12 750 196.5500467845
1706 zero 12 751 196.8729547656
1707 zero 12 752 197.0367451035
1708 zero 12 753 197.3282117052
1709 zero 12 754 197.6062168975
1710 zero 12 755 197.9165375301
1711 zero 12 756 198.0227514977
1712 zero 12 757 198.3611932553
1713 zero 12 758 198.6318059360
1714 zero 12 759 198.8947054019
1715 zero 12 760 199.1666221409
1716 zero 12 761 199.4293888204
1717 zero 12 762 199.6896996638
1718 zero 12 763 199.9574494048
1719 zero 12 764 200.2033794092
1720 zero 12 765 200.4766327731
1721 zero 12 766 200.7481626063
1722 zero 12 767 201.0451001185
1723 zero 12 768 201.2632220071
1724 zero 12 769 201.5231711282
1725 zero 12 770 201.7869385318
1726 zero 12 771 202.0541893072
1727 zero 12 772 202.3599020873
1728 zero 12 773 202.4994285529
1729 zero 12 774 202.8314348366
1730 zero 12 775 203.1229678823
1731 zero 12 776 203.3200469402
1732 zero 12 777 203.6081029098
1733 zero 12 778 203.8801094782
1734 zero 12 779 204.1874568293
1735 zero 12 780 204.4015798940
1736 zero 12 781 204.6365308485
1737 zero 12 782 204.9267026908
1738 zero 12 783 205.2024938933
1739 zero 12 784 205.3974629217
1740 zero 12 785 205.7088312182
1741 zero 12 786 205.9769623075
1742 zero 12 787 206.2456805670
1743 zero 12 788 206.5022664900
1744 zero 12 789 206.7689326260
1745 zero 12 790 207.0338326281
1746 zero 12 791 207.3086466941
1747 zero 12 792 207.6144678986
1748 zero 12 793 207.8933735163
1749 zero 12 794 207.9949725748
1750 zero 12 795 208.3552879371
1751 zero 12 796 208.5450700907
1752 zero 12 797 208.8463671824
1753 zero 12 798 209.1090189201
1754 zero 12 799 209.3920956515
1755 zero 12 800 209.5798416515
1756 zero 12 801 209.9128986818
1757 zero 12 802 210.1524587209
1758 zero 12 803 210.4243124913
1759 zero 12 804 210.6874881949
1760 zero 12 805 210.9525863654
1761 zero 12 806 211.2123633633
1762 zero 12 807 211.4902788139
1763 zero 12 808 211.6932334454
1764 zero 12 809 211.9981350091
1765 zero 12 810 212.2669424697
1766 zero 12 811 212.5406309345
1767 zero 12 812 212.8242435663
1768 zero 12 813 213.0423162301
1769 zero 12 814 213.3427901792
1770 zero 12 815 213.5550881124
1771 zero 12 816 213.8241998874
1772 zero 12 817 214.0984949587
1773 zero 12 818 214.3885982280
1774 zero 12 819 214.5515755951
1775 zero 12 820 214.8910139865
1776 zero 12 821 215.0916464253
1777 zero 12 822 215.3960596543
1778 zero 12 823 215.6650813594
1779 zero 12 824 215.9330414732
1780 zero 12 825 216.1722736593
1781 zero 12 826 216.3972300887
1782 zero 12 827 216.7008380896
1783 zero 12 828 216.9663776671
1784 zero 12 829 217.2312664497
1785 zero 12 830 217.5039610160
1786 zero 12 831 217.7872199769
1787 zero 12 832 218.0116147731
1788 zero 12 833 218.2802405347
1789 zero 12 834 218.5504507216
1790 zero 12 835 218.8117896341
1791 zero 12 836 219.0679926851
1792 zero 12 837 219.3565804198
1793 zero 12 838 219.6018024618
1794 zero 12 839 219.8614720943
1795 zero 12 840 220.1308344605
1796 zero 12 841 220.3940051475
1797 zero 12 842 220.7126272748
1798 zero 12 843 220.8781796722
1799 zero 12 844 221.1627365831
1800 zero 12 845 221.4309738805
1801 zero 12 846 221.6941315010
1802 zero 12 847 221.9602505802
1803 zero 12 848 222.2309248163
1804 zero 12 849 222.4834695199
1805 zero 12 850 222.7590075927
1806 zero 12 851 223.0441450862
1807 zero 12 852 223.2266173133
1808 zero 12 853 223.5406382165
1809 zero 12 854 223.8379173099
1810 zero 12 855 224.0163941040
1811 zero 12 856 224.2975536523
1812 zero 12 857 224.5868433802
1813 zero 12 858 224.9212539889
1814 zero 12 859 225.0001916634
1815 zero 12 860 225.3985113662
1816 zero 12 861 225.5745861699
1817 zero 12 862 225.8608987429
1818 zero 12 863 226.1430112314
1819 zero 12 864 226.4459419399
1820 zero 12 865 226.6408408416
1821 zero 12 866 226.9246060305
1822 zero 12 867 227.1925832292
1823 zero 12 868 227.4230127038
1824 zero 12 869 227.7178830905
1825 zero 12 870 227.9906987407
1826 zero 12 871 228.2886290972
1827 zero 12 872 228.4667175656
1828 zero 12 873 228.7556051663
1829 zero 12 874 229.0294174890
1830 zero 12 875 229.3345634165
1831 zero 12 876 229.5360820751
1832 zero 12 877 229.8119650899
1833 zero 12 878 230.0828870976
1834 zero 12 879 230.3801830803
1835 zero 12 880 230.5952134604
1836 zero 12 881 230.8796003557
1837 zero 12 882 231.2269436526
1838 zero 12 883 231.2937552274
1839 zero 12 884 231.6410875982
1840 zero 12 885 231.9739296038
1841 zero 12 886 232.0944543145
1842 zero 12 887 232.4170020150
1843 zero 12 888 232.7172078726
1844 zero 12 889 232.9329318844
1845 zero 12 890 233.2103216226
1846 zero 12 891 233.4835680537
1847 zero 12 892 233.6957617240
1848 zero 12 893 233.9944813784
1849 zero 12 894 234.2713042291
1850 zero 12 895 234.5416552235
1851 zero 12 896 234.8492336155
1852 zero 12 897 235.0176475757
1853 zero 12 898 235.3066881357
1854 zero 12 899 235.5821384879
1855 zero 12 900 235.8433674353
1856 zero 12 901 236.0836944807
1857 zero 12 902 236.4272919223
1858 zero 12 903 236.5341342570
1859 zero 12 904 236.8647544652
1860 zero 12 905 237.1523593336
1861 zero 12 906 237.4152857360
1862 zero 12 907 237.7600563078
1863 zero 12 908 237.8695037699
1864 zero 12 909 238.1708285149
1865 zero 12 910 238.4506628335
1866 zero 12 911 238.7185222066
1867 zero 12 912 238.9905806710
1868 zero 12 913 239.2835167079
1869 zero 12 914 239.5408923475
1870 zero 12 915 239.6973686209
1871 zero 12 916 240.0119846611
1872 zero 12 917 240.2857871308
1873 zero 12 918 240.5515390640
1874 zero 12 919 240.8290482812
1875 zero 12 920 241.0559122752
1876 zero 12 921 241.3210871609
1877 zero 12 922 241.5932268508
1878 zero 12 923 241.8676598873
1879 zero 12 924 242.1306067738
1880 zero 12 925 242.4427988016
1881 zero 12 926 242.6887147788
1882 zero 12 927 242.8304923522
1883 zero 12 928 243.1770379056
1884 zero 12 929 243.3854143377
1885 zero 12 930 243.6956693467
1886 zero 12 931 244.0471385696
1887 zero 12 932 244.1183856561
1888 zero 12 933 244.4645513688
1889 zero 12 934 244.7782793719
1890 zero 12 935 244.9232226595
1891 zero 12 936 245.2424490543
1892 zero 12 937 245.5203551593
1893 zero 12 938 245.7804680204
1894 zero 12 939 246.0412251556
1895 zero 12 940 246.3101917185
1896 zero 12 941 246.5703378759
1897 zero 12 942 246.8352233949
1898 zero 12 943 247.1351504946
1899 zero 12 944 247.3602162394
1900 zero 12 945 247.6359577152
1901 zero 12 946 247.9022243000
1902 zero 12 947 248.1053918901
1903 zero 12 948 248.4340492822
1904 zero 12 949 248.6637067847
1905 zero 12 950 248.9429942957
1906 zero 12 951 249.2148056254
1907 zero 12 952 249.5592876413
1908 zero 12 953 249.6565345049
1909 zero 12 954 249.9034607600
1910 zero 12 955 250.2262612910
1911 zero 12 956 250.4941169979
1912 zero 12 957 250.7695708791
1913 zero 12 958 251.0159046208
1914 zero 12 959 251.2925739032
1915 zero 12 960 251.5614426727
1916 zero 12 961 251.8588553500
1917 zero 12 962 252.0227859329
1918 zero 12 963 252.3726963371
1919 zero 12 964 252.5263571149
1920 zero 12 965 252.8541893962
1921 zero 12 966 253.0724803676
1922 zero 12 967 253.3740086185
1923 zero 12 968 253.6499597868
1924 zero 12 969 253.9075848694
1925 zero 12 970 254.1730579220
1926 zero 12 971 254.4501972443
1927 zero 12 972 254.7052343948
1928 zero 12 973 254.9865676077
1929 zero 12 974 255.2887206100
1930 zero 12 975 255.4129644178
1931 zero 12 976 255.7473417187
1932 zero 12 977 256.0024346890
1933 zero 12 978 256.3626618361
1934 zero 12 979 256.4404634269
1935 zero 12 980 256.7808865553
1936 zero 12 981 257.0339950895
1937 zero 12 982 257.3052256519
1938 zero 12 983 257.5796494324
1939 zero 12 984 257.8466571344
1940 zero 12 985 258.1543362830
1941 zero 12 986 258.2999075297
1942 zero 12 987 258.6105898896
1943 zero 12 988 258.8943195072
1944 zero 12 989 259.1757707973
1945 zero 12 990 259.3674119174
1946 zero 12 991 259.7056230833
1947 zero 12 992 259.8798284389
1948 zero 12 993 260.2550864104
1949 zero 12 994 260.3886874675
1950 zero 12 995 260.7919479602
1951 zero 12 996 260.8921791520
1952 zero 12 997 261.2239365715
1953 zero 12 998 261.4865594550
1954 zero 12 999 261.7641883535
1955 zero 12 1000 262.0827882513
1956 zero 12 1001 262.2405756390
1957 zero 12 1002 262.5312552903
1958 zero 12 1003 262.8063113016
1959 zero 12 1004 263.0735119512
1960 zero 12 1005 263.3451300256
1961 zero 12 1006 263.5768922604
1962 zero 12 1007 263.8671804318
1963 zero 12 1008 264.1226215651
1964 zero 12 1009 264.3964255607
1965 zero 12 1010 264.6712403180
1966 zero 12 1011 264.9729515277
1967 zero 12 1012 265.1738451302
1968 zero 12 1013 265.5310123374
1969 zero 12 1014 265.6022999197
1970 zero 12 1015 265.9507615799
1971 zero 12 1016 266.2312052013
1972 zero 12 1017 266.5621655771
1973 zero 12 1018 266.6381007292
1974 zero 12 1019 267.0222689267
1975 zero 12 1020 267.2544352176
1976 zero 12 1021 267.5355797918
1977 zero 12 1022 267.8690914356
1978 zero 12 1023 267.9433434715
1979 zero 12 1024 268.2912200547
1980 zero 12 1025 268.5731471462
1981 zero 12 1026 268.8311210808
1982 zero 12 1027 269.1026877053
1983 zero 12 1028 269.3614706283
1984 zero 12 1029 269.6356919324
1985 zero 12 1030 269.9626143170
1986 zero 12 1031 270.1027011102
1987 zero 12 1032 270.3721306307
1988 zero 12 1033 270.6584287822
1989 zero 12 1034 270.9279071849
1990 zero 12 1035 271.1717728865
1991 zero 12 1036 271.4915370258
1992 zero 12 1037 271.7103066039
1993 zero 12 1038 271.9851734127
1994 zero 12 1039 272.2920198494
1995 zero 12 1040 272.4992313484
1996 zero 12 1041 272.7660289961
1997 zero 12 1042 273.0399689076
1998 zero 12 1043 273.3521446376
1999 zero 12 1044 273.4690139985
2000 zero 12 1045 273.8096513160
2001 zero 12 1046 274.0692352809

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())