Current task: —

E-022-spectral-measure.py

Experiments: E-022 · script updated 08-19-2026

E-022-spectral-measure.csv — 153.1 KB, updated 08-19-2026

← prev page 8 of 8 · 500/page · 3815 rows
# akz_kw_k
3502 12 831 217.787219976862 1.2429921878e-01
3503 12 832 218.011614773114 4.9074572186e-02
3504 12 833 218.280240534659 4.5884509288e-02
3505 12 834 218.550450721568 4.8853971396e-02
3506 12 835 218.811789634111 4.5413713491e-02
3507 12 836 219.067992685146 1.0455297670e+00
3508 12 837 219.356580419848 1.2698696927e-01
3509 12 838 219.601802461820 5.4457046998e-02
3510 12 839 219.861472094332 4.5154571837e-02
3511 12 840 220.130834460545 5.1658112780e-02
3512 12 841 220.394005147535 4.8649218326e-02
3513 12 842 220.712627274755 1.1113344301e+00
3514 12 843 220.878179672193 6.3259484901e-02
3515 12 844 221.162736583103 4.6117993909e-02
3516 12 845 221.430973880534 1.0503780758e+00
3517 12 846 221.694131501030 4.7526204424e-02
3518 12 847 221.960250580164 4.8178129901e-02
3519 12 848 222.230924816303 5.0694277092e-02
3520 12 849 222.483469519863 4.6453039432e-02
3521 12 850 222.759007592721 5.0043400946e-02
3522 12 851 223.044145086225 5.9043028962e-02
3523 12 852 223.226617313269 1.2135838876e-01
3524 12 853 223.540638216521 4.9610648037e-02
3525 12 854 223.837917309873 6.9572957136e-02
3526 12 855 224.016394103971 1.1080552937e+00
3527 12 856 224.297553652340 5.4295607390e-02
3528 12 857 224.586843380245 4.9751942720e-02
3529 12 858 224.921253988882 2.5833090588e-01
3530 12 859 225.000191663431 8.3575765033e-01
3531 12 860 225.398511366225 1.1504363458e-01
3532 12 861 225.574586169946 7.5613587152e-02
3533 12 862 225.860898742872 5.3816854990e-02
3534 12 863 226.143011231384 4.7812995465e-02
3535 12 864 226.445941939867 1.3586777537e-01
3536 12 865 226.640840841632 5.5013932128e-02
3537 12 866 226.924606030469 5.3921560947e-02
3538 12 867 227.192583229200 4.8004067651e-02
3539 12 868 227.423012703758 1.0484696051e+00
3540 12 869 227.717883090505 4.7633695506e-02
3541 12 870 227.990698740715 5.0582356987e-02
3542 12 871 228.288629097180 1.3144949765e-01
3543 12 872 228.466717565595 6.8822242326e-02
3544 12 873 228.755605166265 4.9359214093e-02
3545 12 874 229.029417488979 5.4326807783e-02
3546 12 875 229.334563416491 1.0413391719e+00
3547 12 876 229.536082075144 5.1451191897e-02
3548 12 877 229.811965089879 5.0059267356e-02
3549 12 878 230.082887097588 4.6627767168e-02
3550 12 879 230.380183080345 1.5519558161e-01
3551 12 880 230.595213460423 5.6776281573e-02
3552 12 881 230.879600355714 5.2286149974e-02
3553 12 882 231.226943652609 6.9979434008e-01
3554 12 883 231.293755227406 3.8926456324e-01
3555 12 884 231.641087598210 5.2763141266e-02
3556 12 885 231.973929603797 1.0900269048e+00
3557 12 886 232.094454314520 1.1968209320e-01
3558 12 887 232.417002015028 5.1680473172e-02
3559 12 888 232.717207872596 1.6303413545e-01
3560 12 889 232.932931884445 5.6006551691e-02
3561 12 890 233.210321622627 4.9527482911e-02
3562 12 891 233.483568053666 5.1718680080e-02
3563 12 892 233.695761723979 1.0436485588e+00
3564 12 893 233.994481378403 5.0952103457e-02
3565 12 894 234.271304229062 4.9064705911e-02
3566 12 895 234.541655223454 4.9412927588e-02
3567 12 896 234.849233615534 1.4998006948e-01
3568 12 897 235.017647575701 7.4746897367e-02
3569 12 898 235.306688135711 5.0037975606e-02
3570 12 899 235.582138487873 5.0852745513e-02
3571 12 900 235.843367435349 5.1719029912e-02
3572 12 901 236.083694480667 1.8396086649e-01
3573 12 902 236.427291922288 1.2803699405e-01
3574 12 903 236.534134256953 9.6246669117e-01
3575 12 904 236.864754465248 1.8744556668e-01
3576 12 905 237.152359333624 5.2172980061e-02
3577 12 906 237.415285736036 5.2572932299e-02
3578 12 907 237.760056307762 9.6810893470e-01
3579 12 908 237.869503769875 1.2341654166e-01
3580 12 909 238.170828514855 5.6489173842e-02
3581 12 910 238.450662833490 5.1092928683e-02
3582 12 911 238.718522206635 4.7825595084e-02
3583 12 912 238.990580671029 5.1937787648e-02
3584 12 913 239.283516707933 6.6812104319e-02
3585 12 914 239.540892347503 1.1289071718e+00
3586 12 915 239.697368620853 9.4523353761e-02
3587 12 916 240.011984661136 5.0638283799e-02
3588 12 917 240.285787130793 5.5816894629e-02
3589 12 918 240.551539064049 5.3723358074e-02
3590 12 919 240.829048281171 5.6592623213e-02
3591 12 920 241.055912275193 1.1840029493e+00
3592 12 921 241.321087160909 5.4940606950e-02
3593 12 922 241.593226850763 4.9560388712e-02
3594 12 923 241.867659887331 5.2085638219e-02
3595 12 924 242.130606773846 5.2168121699e-02
3596 12 925 242.442798801628 2.0566672029e-01
3597 12 926 242.688714778823 9.0714325993e-02
3598 12 927 242.830492352235 1.0075481061e+00
3599 12 928 243.177037905623 6.1221055046e-02
3600 12 929 243.385414337713 1.9849064435e-01
3601 12 930 243.695669346685 5.8268988486e-02
3602 12 931 244.047138569561 7.1822032441e-01
3603 12 932 244.118385656097 3.7976006008e-01
3604 12 933 244.464551368835 5.3552738969e-02
3605 12 934 244.778279371904 1.0633248194e-01
3606 12 935 244.923222659528 1.5957361809e-01
3607 12 936 245.242449054347 5.2721718258e-02
3608 12 937 245.520355159349 5.7090754501e-02
3609 12 938 245.780468020373 4.9001126402e-02
3610 12 939 246.041225155562 5.5521816910e-02
3611 12 940 246.310191718462 4.9137418632e-02
3612 12 941 246.570337875947 5.1124209282e-02
3613 12 942 246.835223394889 2.3062083442e-01
3614 12 943 247.135150494614 1.0457229221e+00
3615 12 944 247.360216239448 5.4036097074e-02
3616 12 945 247.635957715183 5.6793333429e-02
3617 12 946 247.902224299982 6.0883276156e-02
3618 12 947 248.105391890146 1.0433921238e+00
3619 12 948 248.434049282250 2.3365149263e-01
3620 12 949 248.663706784688 5.7975522221e-02
3621 12 950 248.942994295712 5.2231346338e-02
3622 12 951 249.214805625446 5.6597424609e-02
3623 12 952 249.559287641324 9.0849281067e-01
3624 12 953 249.656534504870 1.9820082912e-01
3625 12 954 249.903460759983 2.2743877989e-01
3626 12 955 250.226261291034 5.3625534701e-02
3627 12 956 250.494116997899 5.2398368158e-02
3628 12 957 250.769570879067 5.2666095298e-02
3629 12 958 251.015904620757 1.0593133826e+00
3630 12 959 251.292573903180 5.2612952996e-02
3631 12 960 251.561442672700 5.4631513129e-02
3632 12 961 251.858855350020 7.6390698634e-02
3633 12 962 252.022785932878 2.2712919840e-01
3634 12 963 252.372696337131 8.8209323608e-02
3635 12 964 252.526357114865 2.2053713192e-01
3636 12 965 252.854189396204 5.7604680599e-02
3637 12 966 253.072480367579 1.0457188655e+00
3638 12 967 253.374008618517 5.6926111858e-02
3639 12 968 253.649959786796 5.3057700240e-02
3640 12 969 253.907584869362 5.3943445408e-02
3641 12 970 254.173057921991 6.0034486908e-02
3642 12 971 254.450197244283 2.6706091815e-01
3643 12 972 254.705234394848 5.3764676837e-02
3644 12 973 254.986567607740 5.7503564727e-02
3645 12 974 255.288720610044 1.1903396410e+00
3646 12 975 255.412964417785 1.3137722399e-01
3647 12 976 255.747341718705 5.9376226190e-02
3648 12 977 256.002434688973 5.8217713028e-02
3649 12 978 256.362661836095 8.2425735615e-01
3650 12 979 256.440463426883 2.7327763967e-01
3651 12 980 256.780886555282 5.8389375599e-02
3652 12 981 257.033995089454 5.9767092959e-02
3653 12 982 257.305225651860 5.3777070299e-02
3654 12 983 257.579649432406 5.5121533233e-02
3655 12 984 257.846657134437 5.7912388902e-02
3656 12 985 258.154336282987 9.5998703498e-02
3657 12 986 258.299907529724 2.4167384057e-01
3658 12 987 258.610589889626 1.0615202595e+00
3659 12 988 258.894319507171 5.6282660928e-02
3660 12 989 259.175770797332 7.0047415636e-02
3661 12 990 259.367411917418 2.8293680063e-01
3662 12 991 259.705623083338 7.2131196669e-02
3663 12 992 259.879828438926 1.0352497248e+00
3664 12 993 260.255086410420 1.7864337942e-01
3665 12 994 260.388687467542 1.8449201642e-01
3666 12 995 260.791947960157 9.3727640395e-01
3667 12 996 260.892179152001 1.6485992341e-01
3668 12 997 261.223936571466 5.9158946599e-02
3669 12 998 261.486559454983 6.1224407158e-02
3670 12 999 261.764188353497 5.5368756953e-02
3671 12 1000 262.082788251330 2.8609955790e-01
3672 12 1001 262.240575638977 8.3695936275e-02
3673 12 1002 262.531255290313 6.3680130804e-02
3674 12 1003 262.806311301579 5.5574875544e-02
3675 12 1004 263.073511951188 5.5848005811e-02
3676 12 1005 263.345130025563 5.9068062856e-02
3677 12 1006 263.576892260440 1.3272393786e+00
3678 12 1007 263.867180431847 5.9868306570e-02
3679 12 1008 264.122621565085 6.2316371030e-02
3680 12 1009 264.396425560738 5.6815876323e-02
3681 12 1010 264.671240317967 5.9030806108e-02
3682 12 1011 264.972951527705 3.2875053303e-01
3683 12 1012 265.173845130236 7.1643651434e-02
3684 12 1013 265.531012337360 6.7670779087e-01
3685 12 1014 265.602299919655 4.2609344256e-01
3686 12 1015 265.950761579902 5.8456555512e-02
3687 12 1016 266.231205201292 5.8365472154e-02
3688 12 1017 266.562165577084 3.6834988799e-01
3689 12 1018 266.638100729248 7.4512664609e-01
3690 12 1019 267.022268926710 3.6324429865e-01
3691 12 1020 267.254435217557 5.8984500504e-02
3692 12 1021 267.535579791750 6.3175356229e-02
3693 12 1022 267.869091435613 3.3543956940e-01
3694 12 1023 267.943343471534 7.6791557947e-01
3695 12 1024 268.291220054662 6.5956303921e-02
3696 12 1025 268.573147146179 3.7161209508e-01
3697 12 1026 268.831121080791 5.4947201717e-02
3698 12 1027 269.102687705276 5.8165146108e-02
3699 12 1028 269.361470628277 5.6182699485e-02
3700 12 1029 269.635691932382 5.9168246619e-02
3701 12 1030 269.962614316960 1.0158164535e+00
3702 12 1031 270.102701110157 9.8682812683e-02
3703 12 1032 270.372130630695 3.8239764641e-01
3704 12 1033 270.658428782206 6.1940981607e-02
3705 12 1034 270.927907184912 6.4848663511e-02
3706 12 1035 271.171772886513 3.8883451179e-01
3707 12 1036 271.491537025752 1.0664988204e+00
3708 12 1037 271.710306603868 6.1237196637e-02
3709 12 1038 271.985173412651 6.0397279838e-02
3710 12 1039 272.292019849365 3.9127465957e-01
3711 12 1040 272.499231348420 7.0213052846e-02
3712 12 1041 272.766028996073 5.9905543158e-02
3713 12 1042 273.039968907577 6.6858701295e-02
3714 12 1043 273.352144637612 1.2119039225e-01
3715 12 1044 273.469013998532 9.8627952211e-01
3716 12 1045 273.809651315986 6.4400601864e-02
3717 12 1046 274.069235280929 6.4066339670e-02
3718 12 1047 274.334591245150 6.3676968466e-02
3719 12 1048 274.607015839450 6.1470757427e-02
3720 12 1049 274.834197113366 4.2987922059e-01
3721 12 1050 275.130673041289 5.9432668331e-02
3722 12 1051 275.400727465074 7.5332303049e-02
3723 12 1052 275.591514055311 1.0433794712e+00
3724 12 1053 275.913440433989 6.5170501827e-02
3725 12 1054 276.164832352326 6.2754983067e-02
3726 12 1055 276.447863138197 1.4446618543e+00
3727 12 1056 276.694238249364 6.4787973491e-02
3728 12 1057 276.969237880395 5.6279815465e-02
3729 12 1058 277.236704839998 6.4286286528e-02
3730 12 1059 277.498735748997 6.7801758258e-02
3731 12 1060 277.812184672257 1.3326495071e-01
3732 12 1061 277.935394058338 3.8027075727e-01
3733 12 1062 278.251625387088 1.0639590280e+00
3734 12 1063 278.548367021189 6.4488012933e-02
3735 12 1064 278.843276630560 8.9289329964e-02
3736 12 1065 279.023510313266 4.6083223971e-01
3737 12 1066 279.237149994458 1.0353233479e+00
3738 12 1067 279.564321368725 6.7642075104e-02
3739 12 1068 279.833553654885 6.6007519870e-02
3740 12 1069 280.091111042201 6.9159586850e-02
3741 12 1070 280.369587382013 6.8715469621e-02
3742 12 1071 280.639392267949 6.3725197065e-02
3743 12 1072 280.947333663640 1.3393475492e-01
3744 12 1073 281.070408002211 4.0935234670e-01
3745 12 1074 281.399103655138 6.2990888740e-02
3746 12 1075 281.677367266073 6.9304408706e-02
3747 12 1076 281.963273743420 5.0281119671e-01
3748 12 1077 282.188511014243 7.0400936300e-02
3749 12 1078 282.464825213561 1.0617861695e+00
3750 12 1079 282.739327538879 7.4638820094e-02
3751 12 1080 282.996562212696 7.4172028152e-02
3752 12 1081 283.215005899077 1.0585042705e+00
3753 12 1082 283.559347549517 1.5735340139e-01
3754 12 1083 283.684245014207 4.2181292463e-01
3755 12 1084 284.014765779536 7.7400008874e-02
3756 12 1085 284.292988515988 6.1881577743e-02
3757 12 1086 284.546024482496 7.2227275094e-02
3758 12 1087 284.834856689378 1.0650881926e+00
3759 12 1088 285.087039656018 6.3366548113e-02
3760 12 1089 285.350976077322 6.7290033803e-02
3761 12 1090 285.612865537074 6.9557351754e-02
3762 12 1091 285.889248312290 6.8494486089e-02
3763 12 1092 286.222517298746 3.6149180728e-01
3764 12 1093 286.330029635154 2.5703965768e-01
3765 12 1094 286.665238183965 1.0714599951e+00
3766 12 1095 286.917335015065 6.7760814291e-02
3767 12 1096 287.254110555408 4.8787622062e-01
3768 12 1097 287.378793894092 1.3838369377e-01
3769 12 1098 287.701715726074 7.4251331968e-02
3770 12 1099 287.915993255078 1.0695282016e+00
3771 12 1100 288.212696576692 6.9679054032e-02
3772 12 1101 288.462094933706 5.8491126312e-01
3773 12 1102 288.745476358711 6.7019200732e-02
3774 12 1103 289.014414075106 6.5224075870e-02
3775 12 1104 289.280580694147 7.6644701305e-02
3776 12 1105 289.576782250941 1.0713742237e+00
3777 12 1106 289.826241417323 9.1314872450e-02
3778 12 1107 289.990422243314 5.7700121669e-01
3779 12 1108 290.316948931885 6.7571804730e-02
3780 12 1109 290.576138001396 8.9290931501e-02
3781 12 1110 290.846724702013 6.3291870127e-02
3782 12 1111 291.125238858825 8.4027106877e-02
3783 12 1112 291.455472852867 5.3952232157e-01
3784 12 1113 291.580311547852 1.5461117291e-01
3785 12 1114 291.849332215608 1.0677814884e+00
3786 12 1115 292.148529984892 6.6694876558e-02
3787 12 1116 292.419121365436 7.1698124426e-02
3788 12 1117 292.692776423481 7.2598939022e-02
3789 12 1118 292.950883859380 7.6831746866e-02
3790 12 1119 293.215259708696 7.5996949466e-02
3791 12 1120 293.549190231176 1.0275734524e+00
3792 12 1121 293.699784381678 1.1262487633e-01
3793 12 1122 294.073955470684 4.8360827288e-01
3794 12 1123 294.179234401743 2.5906649379e-01
3795 12 1124 294.548172298229 1.2895427888e-01
3796 12 1125 294.690464914195 6.1614362579e-01
3797 12 1126 294.968860142778 1.0847198952e+00
3798 12 1127 295.279562908397 7.1373658834e-02
3799 12 1128 295.571545628110 1.0718678658e+00
3800 12 1129 295.812138169641 6.9395416193e-02
3801 12 1130 296.077374112790 7.3037266580e-02
3802 12 1131 296.353537310585 7.5499520431e-02
3803 12 1132 296.599687859984 7.5417110834e-02
3804 12 1133 296.846951443009 7.1355315777e-01
3805 12 1134 297.137800901771 7.8732184566e-02
3806 12 1135 297.401145550831 7.5937560653e-02
3807 12 1136 297.671924172717 6.9572052543e-02
3808 12 1137 297.975344603448 1.0673773584e+00
3809 12 1138 298.210400896677 1.2001173988e-01
3810 12 1139 298.375835062696 7.1031324964e-01
3811 12 1140 298.703695146110 7.6675707224e-02
3812 12 1141 298.976251839038 7.6184640111e-02
3813 12 1142 299.278487376702 7.4930404909e-01
3814 12 1143 299.494289281790 9.9599797060e-02
3815 12 1144 299.830599123074 1.0055206033e+00
3816 12 1145 299.966384280315 1.3821216624e-01

E-022-spectral-measure.json — 4.3 KB, updated 08-19-2026

JSON sidecar (click to expand)
{
  "experiment": "E-022",
  "task": "2.10 (D-035 D2): spectral-measure convergence",
  "script": "research/numerics/scripts/E-022-spectral-measure.py",
  "parameters": {
    "a_list": [
      4.0,
      6.0,
      8.0,
      10.0,
      12.0
    ],
    "h": 0.01,
    "lam": -1.0,
    "z_max": 300.0,
    "z_metric": 280.0,
    "sigma_bump": 8.0,
    "n_grid": 40000
  },
  "checks": {
    "V0_schur_vs_solve_v": true,
    "V1_weights_positive": true,
    "V2_refinement": true,
    "V3_lattice_and_z1law": true
  },
  "key_values": {
    "4": {
      "n_zeros": 381,
      "z1": 1.1260734006983593,
      "z1_times_a": 4.504293602793437,
      "lattice_expected": 381.9718634205488,
      "mass_total_Zmetric": 184.02432245308052,
      "O1_cumulative_Linf": 0.030472775278319375,
      "O1_cumulative_L2": 0.015369322417422383,
      "O2_logw_slope": 0.004773175983096674,
      "O2_logw_R2": 0.17155831473911887,
      "O2_logw_std_resid": 0.8476672146023767,
      "O3_weak_metric": 0.010527875427328966,
      "O5_mass_near_gamma": 1.6069393990772483,
      "O5_mass_near_random": 1.239913792291073,
      "O5_ratio": 1.2960089718076262,
      "elapsed_s": 2.9
    },
    "6": {
      "n_zeros": 572,
      "z1": 0.7499016225074712,
      "z1_times_a": 4.499409735044827,
      "lattice_expected": 572.9577951308232,
      "mass_total_Zmetric": 184.01489106241632,
      "O1_cumulative_Linf": 0.02723380344436621,
      "O1_cumulative_L2": 0.015298102993183555,
      "O2_logw_slope": 0.004573680792971365,
      "O2_logw_R2": 0.13177706690264612,
      "O2_logw_std_resid": 0.9483241546589634,
      "O3_weak_metric": 0.010569164981132785,
      "O5_mass_near_gamma": 1.6173747450375149,
      "O5_mass_near_random": 1.257329769139859,
      "O5_ratio": 1.2863568371120038,
      "elapsed_s": 4.8
    },
    "8": {
      "n_zeros": 763,
      "z1": 0.5621012628096893,
      "z1_times_a": 4.4968101024775144,
      "lattice_expected": 763.9437268410976,
      "mass_total_Zmetric": 184.13312237431055,
      "O1_cumulative_Linf": 0.027258094320286474,
      "O1_cumulative_L2": 0.015486596743652112,
      "O2_logw_slope": 0.004185396789595135,
      "O2_logw_R2": 0.10532818940743971,
      "O2_logw_std_resid": 0.986518773772079,
      "O3_weak_metric": 0.010568959142405882,
      "O5_mass_near_gamma": 1.6196075350475192,
      "O5_mass_near_random": 1.2561234028070363,
      "O5_ratio": 1.2893697636937673,
      "elapsed_s": 8.2
    },
    "10": {
      "n_zeros": 954,
      "z1": 0.44959701245436284,
      "z1_times_a": 4.4959701245436285,
      "lattice_expected": 954.9296585513721,
      "mass_total_Zmetric": 184.1239991524169,
      "O1_cumulative_Linf": 0.024844169503423608,
      "O1_cumulative_L2": 0.015446208652370818,
      "O2_logw_slope": 0.0038097364559334847,
      "O2_logw_R2": 0.08653440341105123,
      "O2_logw_std_resid": 1.0006504172097648,
      "O3_weak_metric": 0.010581710686957842,
      "O5_mass_near_gamma": 1.6290317856739722,
      "O5_mass_near_random": 1.2562149964535079,
      "O5_ratio": 1.2967778527345915,
      "elapsed_s": 13.4
    },
    "12": {
      "n_zeros": 1145,
      "z1": 0.3746087478472408,
      "z1_times_a": 4.495304974166889,
      "lattice_expected": 1145.9155902616465,
      "mass_total_Zmetric": 184.10483484645468,
      "O1_cumulative_Linf": 0.028584131798192303,
      "O1_cumulative_L2": 0.015417413187446537,
      "O2_logw_slope": 0.003682406300531162,
      "O2_logw_R2": 0.08233450272296328,
      "O2_logw_std_resid": 0.9935774298804366,
      "O3_weak_metric": 0.010592268896428007,
      "O5_mass_near_gamma": 1.6165573705799765,
      "O5_mass_near_random": 1.2532365071394718,
      "O5_ratio": 1.2899060643148588,
      "elapsed_s": 20.9
    },
    "O4_trend": {
      "a": [
        4.0,
        6.0,
        8.0,
        10.0,
        12.0
      ],
      "d_a": [
        0.010527875427328966,
        0.010569164981132785,
        0.010568959142405882,
        0.010581710686957842,
        0.010592268896428007
      ],
      "monotone_decreasing": false
    },
    "V0_max_dev": 3.560323900663321e-14,
    "V2_rel": 0.0011243096862693027
  },
  "elapsed_seconds": 743.1,
  "timestamp_utc": "2026-08-19T17:19:38.162052+00:00"
}

Source code

Python script (click to expand)
"""E-022 — task 2.10 (D-035 deliverable D2): spectral-measure
convergence of Suzuki's D_{a,pi} toward the gamma-target measure.

For each a in {4,6,8,10,12} (theta=pi, all zeros real, E-016 F1):
  - locate zeros z_k of W(a,pi;z) on (0, Z_MAX] (E-016/E-019 route:
    grid sign-changes of g(z) = z Im V+ - Re V+ + brentq);
  - compute the Clark/de Branges spectral weights
        w_k = 1 / K_a(z_k, z_k),
    K_a(z,z) = Re(b_z^H v),  v solves the BORDERED (mean-zero, L^2_0)
    Galerkin system  T v + mu e = b_z,  e.v = 0,
    T = Q - lam M (lam = -1),  b_z = h sinc^2(zh/2pi) e^{-i z x}
    (exact hat-basis quadrature), via Schur reduction on shared
    u1 = T^{-1} e: v = T^{-1}(b_z - mu e), mu = (e.u0)/(e.u1).
    Toeplitz solves (scipy solve_toeplitz); V0 validates the Schur
    solve against E16.solve_v (bordered dense) for b[+1].

Target measure: unit atoms at the Riemann zeros gamma_k (mpmath
zetazero, dps 30, float64 sufficient for statistics).

Observables:
  O1. normalized cumulative mass M_a(x)/M_a(Z') vs N_gamma(x)/N(Z'),
      Z' = 280 (Linfty + L2 discrepancy).
  O2. weight profile: linear fit log w_k vs z_k (slope, spread R^2).
  O3. weak metric: Gaussian bumps f_j (30 log-spaced centers in
      [15,250], sigma=8): d_a = max_j |mu~_a(f_j) - nu~(f_j)|,
      normalized by total mass in (0, Z'].
  O4. d_a vs a  -> convergence-rate estimate (headline).
  O5. gamma-concentration: mean mu_a-mass within +/-1 of each gamma
      vs within +/-1 of random points (does the WEIGHT carry gamma
      information even though positions don't lock? — E-019 B2 found
      chance-level POSITION proximity).

Checks:
  V0. Schur-Toeplitz bordered solve vs E16.solve_v (b[+1]): < 1e-8.
  V1. all weights > 0.
  V2. refinement a=4, h=0.005: weight rel dev on first 50 zeros < 5e-3.
  V3. z1*a in [4.3, 4.7] (stiff law, E-019) and count = maximal
      lattice (a*Z_MAX/pi +/- 2) at every a.
  V4. total mass M_a(Z') recorded vs a (scaling documented).

Outputs: research/numerics/data/E-022-spectral-measure.csv (+ .json)
LONG RUN: detached + log file (per STATE.md protocol).
"""
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.linalg
import scipy.optimize

REPO = Path(__file__).resolve().parents[3]
DATA = REPO / "research" / "numerics" / "data"
CSV = DATA / "E-022-spectral-measure.csv"
JSON = DATA / "E-022-spectral-measure.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_MAIN = E16.H_MAIN          # 0.01
LAM = E16.LAM_SHIFT          # -1.0
A_LIST = [4.0, 6.0, 8.0, 10.0, 12.0]
Z_MAX = 300.0
Z_METRIC = 280.0
N_GRID = 40000
SIGMA_BUMP = 8.0
mp.mp.dps = 40

XN, XW = E16.XN, E16.XW
hat_FT = E16.hat_FT


def collect_t_points(a, h):
    """Copy of E-019's collector (E-016 S_full/quad segment structure)."""
    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 = 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)


class ToeplitzBordered:
    """Schur-reduced bordered solve for T = toeplitz(tc), constraint
    e.v = 0 (e = ones):  v = u0 - mu u1, mu = sum(u0)/sum(u1)."""

    def __init__(self, tc):
        self.tc = tc
        n = len(tc)
        self.u1 = scipy.linalg.solve_toeplitz((tc, tc), np.ones(n))
        self.s1 = float(self.u1.sum())

    def solve(self, b):
        u0 = scipy.linalg.solve_toeplitz((self.tc, self.tc), b)
        return u0 - (u0.sum() / self.s1) * self.u1


def weights_for(a, h, zeros, x):
    """K_k and w_k for the given zero list (build(a,h) cached)."""
    _, _, Q, M, _b = E16.build(a, h)
    n = Q.shape[0]
    mc = np.zeros(n)
    mc[0] = 2 * h / 3
    if n > 1:
        mc[1] = h / 6
    tc = Q[:, 0] - LAM * mc
    solver = ToeplitzBordered(tc)
    Ks = np.empty(len(zeros))
    for i, z in enumerate(zeros):
        bz = hat_FT(np.array([z]), h)[0] * np.exp(-1j * z * x)
        v = solver.solve(bz)
        Ks[i] = float(np.real(np.conj(bz) @ v))
    return Ks


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

    # ---- backend v2 (e^24) ------------------------------------------
    print("collecting quadrature t-points ...", flush=True)
    tq = np.concatenate([collect_t_points(a, H_MAIN) for a in A_LIST]
                        + [collect_t_points(4.0, 0.005)])
    print(f"  {tq.size} points; building/loading backend ...", flush=True)
    CACHE = DATA / "E-022-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)
    E16._BUILD.clear()
    E16.prime_sum_vec = be.prime_sum

    # ---- gamma target ------------------------------------------------
    print("target: first 200 Riemann zeros (zetazero) ...", flush=True)
    mp.mp.dps = 30
    gam = np.array([float(mp.zetazero(k).imag) for k in range(1, 201)])
    gam = gam[gam <= Z_METRIC]

    # ---- main sweep --------------------------------------------------
    rows = []
    report = {"per_a": {}}
    v0_max = 0.0
    v1_ok = True
    v3_ok = True
    zc = np.linspace(10.0, Z_METRIC, 800)
    centers = np.geomspace(15.0, 250.0, 30)

    for a in A_LIST:
        ta = time.time()
        x, h, Q, M, b = E16.build(a, H_MAIN)
        n = len(x)
        # V0: Schur-Toeplitz vs E16.solve_v on b[+1]
        mc = np.zeros(n)
        mc[0] = 2 * h / 3
        mc[1] = h / 6
        tc = Q[:, 0] - LAM * mc
        solver = ToeplitzBordered(tc)
        cp_ref, _T = E16.solve_v(Q, M, b[+1.0], LAM, n)
        cp_schur = solver.solve(b[+1.0])
        dev = float(np.max(np.abs(cp_ref - cp_schur))
                    / max(1.0, float(np.max(np.abs(cp_ref)))))
        v0_max = max(v0_max, dev)

        cp, _ = E16.solve_v(Q, M, b[+1.0], LAM, n)
        cm, _ = E16.solve_v(Q, M, b[-1.0], LAM, n)
        zeros = locate_zeros(cp, x, h)

        Ks = weights_for(a, H_MAIN, zeros, x)
        ws = 1.0 / Ks
        if np.any(Ks <= 0):
            v1_ok = False

        z1 = float(zeros[0])
        lat = a * Z_MAX / np.pi
        if not (4.3 < z1 * a < 4.7) or abs(len(zeros) - lat) > 2:
            v3_ok = False

        # --- metrics (zeros in (0, Z_METRIC])
        zm = zeros[zeros <= Z_METRIC]
        wm = ws[zeros <= Z_METRIC]
        Mtot = float(wm.sum())
        # O1: cumulative shape vs unit-weight gamma measure
        Ma = np.array([wm[zm <= t].sum() for t in zc]) / Mtot
        Ng = np.array([np.sum(gam <= t) for t in zc]) / len(gam)
        o1_linf = float(np.max(np.abs(Ma - Ng)))
        o1_l2 = float(np.sqrt(np.mean((Ma - Ng) ** 2)))
        # O2: weight profile
        A_ = np.vstack([zm, np.ones_like(zm)]).T
        slope, intercept = np.linalg.lstsq(A_, np.log(wm), rcond=None)[0]
        pred = slope * zm + intercept
        ss_res = float(np.sum((np.log(wm) - pred) ** 2))
        ss_tot = float(np.sum((np.log(wm) - np.log(wm).mean()) ** 2))
        r2 = 1.0 - ss_res / max(ss_tot, 1e-300)
        # O3: Gaussian-bump weak metric
        def bump(z, c):
            return np.exp(-0.5 * ((z - c) / SIGMA_BUMP) ** 2)
        mu_f = np.array([np.dot(wm, bump(zm, c)) for c in centers]) / Mtot
        nu_f = np.array([bump(gam, c).sum() for c in centers]) / len(gam)
        o3 = float(np.max(np.abs(mu_f - nu_f)))
        # O5: gamma-concentration of mass
        mass_near_g = float(np.mean([wm[np.abs(zm - g) <= 1.0].sum()
                                     for g in gam]))
        rng = np.random.default_rng(7)
        rpts = rng.uniform(15.0, 250.0, len(gam))
        mass_near_r = float(np.mean([wm[np.abs(zm - r) <= 1.0].sum()
                                     for r in rpts]))

        for k, (zz, ww) in enumerate(zip(zeros, ws), 1):
            rows.append((a, k, zz, ww))
        report["per_a"][f"{a:g}"] = {
            "n_zeros": int(len(zeros)), "z1": z1, "z1_times_a": z1 * a,
            "lattice_expected": lat,
            "mass_total_Zmetric": Mtot,
            "O1_cumulative_Linf": o1_linf, "O1_cumulative_L2": o1_l2,
            "O2_logw_slope": float(slope), "O2_logw_R2": r2,
            "O2_logw_std_resid": float(np.sqrt(ss_res / max(len(zm) - 2, 1))),
            "O3_weak_metric": o3,
            "O5_mass_near_gamma": mass_near_g,
            "O5_mass_near_random": mass_near_r,
            "O5_ratio": mass_near_g / max(mass_near_r, 1e-300),
            "elapsed_s": round(time.time() - ta, 1),
        }
        print(f"a={a:g}: {len(zeros)} zeros, z1a={z1 * a:.3f}, "
              f"mass={Mtot:.3e}, O3={o3:.4f}, "
              f"O5={mass_near_g:.3e}/{mass_near_r:.3e} "
              f"({report['per_a'][f'{a:g}']['elapsed_s']}s)", flush=True)

    # ---- V2: refinement at a=4, h=0.005 ------------------------------
    print("V2: refinement a=4 h=0.005 (first 50 zeros) ...", flush=True)
    x5, h5, Q5, M5, b5 = E16.build(4.0, 0.005)
    cp5, _ = E16.solve_v(Q5, M5, b5[+1.0], LAM, len(x5))
    zeros5 = locate_zeros(cp5, x5, h5)
    K5 = weights_for(4.0, 0.005, zeros5[:50], x5)
    x01, _, _, _, _ = E16.build(4.0, H_MAIN)
    K4 = weights_for(4.0, H_MAIN, zeros5[:50], x01)  # same z's, h=0.01
    v2_rel = float(np.max(np.abs(K5 - K4) / np.abs(K5)))
    print(f"  V2 max rel dev K(h=0.005) vs K(h=0.01): {v2_rel:.2e}",
          flush=True)

    # ---- O4: convergence trend --------------------------------------
    avals = np.array(A_LIST)
    dvals = np.array([report["per_a"][f"{a:g}"]["O3_weak_metric"]
                      for a in A_LIST])
    o4 = {"a": list(avals), "d_a": list(dvals),
          "monotone_decreasing": bool(np.all(np.diff(dvals) < 0))}

    checks = {
        "V0_schur_vs_solve_v": bool(v0_max < 1e-8),
        "V1_weights_positive": bool(v1_ok),
        "V2_refinement": bool(v2_rel < 5e-3),
        "V3_lattice_and_z1law": bool(v3_ok),
    }
    print("checks:", checks, flush=True)

    import csv as csvmod
    with open(CSV, "w", newline="") as f:
        w = csvmod.writer(f)
        w.writerow(["a", "k", "z_k", "w_k"])
        for a, k, zz, ww in rows:
            w.writerow([f"{a:g}", k, f"{zz:.12f}", f"{ww:.10e}"])

    meta = {
        "experiment": "E-022",
        "task": "2.10 (D-035 D2): spectral-measure convergence",
        "script": "research/numerics/scripts/E-022-spectral-measure.py",
        "parameters": {"a_list": A_LIST, "h": H_MAIN, "lam": LAM,
                       "z_max": Z_MAX, "z_metric": Z_METRIC,
                       "sigma_bump": SIGMA_BUMP, "n_grid": N_GRID},
        "checks": checks,
        "key_values": {**report["per_a"], "O4_trend": o4,
                       "V0_max_dev": v0_max, "V2_rel": v2_rel},
        "elapsed_seconds": round(time.time() - t0, 1),
        "timestamp_utc": datetime.now(timezone.utc).isoformat(),
    }
    JSON.write_text(json.dumps(meta, indent=2))
    print(f"wrote {CSV.name}, {JSON.name}; elapsed "
          f"{meta['elapsed_seconds']}s", flush=True)
    return 0 if all(checks.values()) else 1


if __name__ == "__main__":
    sys.exit(main())