Current task: —

E-002-first-zeros.py

Experiments: E-002 · script updated 08-17-2026

E-002-zeros-first-10000.csv — 310.4 KB, updated 08-17-2026

← prev page 2 of 20 · 500/page · 10000 rows next →
# ngamma_n
502 501 812.7711083891093427198013
503 502 814.0459136075109935019676
504 503 814.8705396258725677840197
505 504 816.7277377143947163165026
506 505 818.3806688663616765115868
507 506 819.204642170823862605824
508 507 820.721898443869287466431
509 508 821.713454133379401809876
510 509 822.1977574934042771435819
511 510 824.5262938716297481637665
512 511 826.0392873765743835480142
513 512 826.9058109540807719796645
514 513 828.3401743004899003705042
515 514 829.4370109683093336230476
516 515 830.8958840533174007300786
517 516 831.7997776590705830743246
518 517 833.0036409091541995383113
519 518 834.6519151478255758073453
520 519 836.6935761875918671688703
521 520 837.3473350595315147674864
522 521 838.2490219927321458365471
523 522 839.4653948102824755503103
524 523 841.0363898290134237244115
525 524 842.0413542065263713333677
526 525 844.1661966073507688213461
527 526 844.8059939757637268812848
528 527 846.1947699276939977636625
529 528 847.9717176395120066363276
530 529 848.4892811809435238248867
531 530 849.8622743486978262643447
532 531 850.6454484660040923782421
533 532 853.1631125833891553258395
534 533 854.0955117198690586200182
535 534 855.2867102444049363482284
536 535 856.4841174907916628540349
537 536 857.3107406026038260329642
538 537 858.9040264664756944128296
539 538 860.4106708960146707515941
540 539 861.1710982127153376059751
541 540 863.1897197719089342361101
542 541 864.3408239300695408556875
543 542 865.5946643265159653951069
544 543 866.4237399040426414629796
545 544 867.6931226117850062387685
546 545 868.6704942291315966678383
547 546 870.8469023257540162057953
548 547 872.1887508216132077558732
549 548 873.0989789712819814983254
550 549 873.90838923533753043963
551 550 875.9852851087803223743924
552 551 876.6008258330274423972431
553 552 877.6546983410334751440221
554 553 879.3809519697909824564618
555 554 880.8346488479393902830323
556 555 882.3866966271964612523847
557 556 883.4303318387016456845683
558 557 884.1987431145947269603843
559 558 885.2723044796171270511981
560 559 886.8528019629162983720333
561 560 888.4755666738171947737264
562 561 889.7352942940907370974122
563 562 890.8131321125280636861959
564 563 892.386433260155869341741
565 564 893.1191175672942583361755
566 565 894.8862923208687161421929
567 566 895.3979196747829650553969
568 567 896.6322515562027200335266
569 568 899.2215226683834193900956
570 569 899.8588846079374834442659
571 570 900.8497398605213961178246
572 571 902.2432075867522884616404
573 572 903.099674442630454946665
574 573 904.7029027222813207743241
575 574 905.8299407582222094048394
576 575 907.6567294689675253115567
577 576 908.3335436450609252807082
578 577 910.1863340571798425653526
579 578 911.2349514859555040925975
580 579 912.3310456000355872488072
581 580 912.8239992467433953779922
582 581 914.7300969583756133383752
583 582 916.3550008086427658914208
584 583 917.825377570426783026484
585 584 918.836535243529029571249
586 585 919.4483444396823047817651
587 586 921.1563955071548533673994
588 587 922.5006293066367702662453
589 588 923.2857198024222426739431
590 589 924.7734839334766644162465
591 590 926.5515527846030289415924
592 591 927.850858985753594147871
593 592 928.6636593289348922887563
594 593 929.8740928506477547771061
595 594 931.0092113366280729542762
596 595 931.8527407455200799216863
597 596 934.3853068372584647544145
598 597 934.9954248638464596176097
599 598 936.2286493792829272137187
600 599 937.5329257119703812729162
601 600 939.0243008992183821842184
602 601 939.6609406145281659856007
603 602 941.156999642042372607771
604 603 942.0523416433754978743899
605 604 944.1880358095727445119785
606 605 945.3335625030459461415422
607 606 946.7658422047278511567322
608 607 947.0791830962548779651195
609 608 948.3466462550449671666051
610 609 950.1516126846438408647468
611 610 951.0332487338235099744994
612 611 952.7279886198506260846675
613 612 954.129719269551415336758
614 613 954.8293089382166371195138
615 614 956.675479343289796023142
616 615 957.5100525964237224677288
617 616 958.414593390136180970004
618 617 959.4591688070681125609996
619 618 961.6695724741927533426687
620 619 963.1820866713114469971322
621 620 963.5670401916122706718621
622 621 965.0555796237511162249267
623 622 966.1107548184102040187246
624 623 967.3711537662628543151648
625 624 968.6363019060873264080899
626 625 970.1256105569411754792151
627 626 971.071491486385727940251
628 627 973.1853612943011942216491
629 628 973.8730789926535971942326
630 629 974.7746350658374298753032
631 630 976.1785024205896093441878
632 631 976.9172021170506220214173
633 632 978.766671535112974454023
634 633 980.578000639774418061339
635 634 981.2886153017589694593644
636 635 982.3964851687789784014102
637 636 983.5750760064313287555331
638 637 985.1869286557734357695286
639 638 986.130515110184526649374
640 639 986.7560084076560356217778
641 640 988.9926223706574066073662
642 641 990.2239178040279723629781
643 642 991.3742941477615054318634
644 643 992.7286963367326594436274
645 644 993.2145809574429537075231
646 645 994.4045905710944919000278
647 646 996.205336164298286483528
648 647 997.5119347519392292110298
649 648 998.8275471369296331305196
650 649 999.7915715574129404631631
651 650 1001.349482637782737122103
652 651 1002.404305488391711308159
653 652 1003.267808179453248257528
654 653 1004.675044121172894226133
655 654 1005.543420304378364196611
656 655 1008.00670430706364619814
657 656 1008.795709900742282345773
658 657 1009.806590746964629457282
659 658 1010.569757011061075898567
660 659 1012.410042515761596842853
661 660 1013.058638098408985072653
662 661 1014.689632622370404688146
663 662 1016.06017894264737813029
664 663 1017.266402364355406669715
665 664 1018.605572518620154950984
666 665 1019.912439743944038361672
667 666 1020.917475017263678316147
668 667 1021.544344499904651907124
669 668 1022.885270911716347826
670 669 1025.265724197727696366628
671 670 1025.707944371462889237728
672 671 1027.467693515587770273397
673 672 1028.12896425549751787767
674 673 1029.227297443961366731129
675 674 1030.897368790596523560727
676 675 1031.833180297407762541224
677 676 1032.812883035158851460651
678 677 1034.612915529520810066174
679 678 1036.195917358054740253983
680 679 1037.024707646281749750577
681 680 1038.087752240618836437347
682 681 1039.07740143689668872668
683 682 1040.264037937695760831153
684 683 1041.621528014542274154712
685 684 1043.62395434962149387045
686 685 1044.514975829078768114603
687 686 1045.10704235297791139065
688 687 1047.089817484294784221115
689 688 1047.987147489600471131322
690 689 1048.953785194685961633057
691 690 1049.99628425659321975563
692 691 1051.576571843205195795578
693 692 1053.245785158385757625611
694 693 1054.781039478281349906799
695 694 1055.002146475685736209353
696 695 1056.688847363828229857525
697 696 1057.100043659617783603061
698 697 1059.133769106897146229421
699 698 1060.139518561607819097239
700 699 1061.50130446506842006312
701 700 1062.915381507880563602453
702 701 1064.071551071718540425286
703 702 1065.12185510629305547858
704 703 1066.463223469242981943779
705 704 1067.418860120964558059345
706 705 1067.990000079042625467736
707 706 1070.535041996829262809353
708 707 1071.618623215089537904728
709 708 1072.543998011121555348783
710 709 1073.570353165093725437728
711 710 1074.747771044310998579294
712 711 1076.266625594177409865004
713 712 1076.924056065754446887585
714 713 1078.647198480956364694291
715 714 1079.809965429259069213572
716 715 1081.171002343467803785066
717 716 1082.952749723069668660792
718 717 1083.295466514085606768341
719 718 1084.183264310430216143164
720 719 1085.64783120863934071202
721 720 1086.911998989825093115566
722 721 1088.755724674808801471697
723 722 1089.795337924074774958424
724 723 1090.863191026248860785009
725 724 1091.728472966936828999399
726 725 1093.440873272368634680796
727 726 1094.284457523754159836339
728 727 1095.433084758661478689667
729 728 1096.401917794742528502149
730 729 1098.841015466649861787295
731 730 1099.360667178571795594617
732 731 1100.574460622462563218624
733 732 1101.839111168756013405011
734 733 1102.551779899917722746786
735 734 1103.732297174546935847596
736 735 1105.617188830762071517321
737 736 1106.774371675832775100917
738 737 1107.774531955010136933152
739 738 1109.158918856766451887805
740 739 1110.444142993613205803273
741 740 1111.443504764899896587418
742 741 1112.432995408076444580688
743 742 1113.397595114801993513614
744 743 1115.06535946156660567653
745 744 1116.787253881214524190633
746 745 1117.965919669199670945478
747 746 1118.684134861018390903878
748 747 1119.473247426178982901861
749 748 1121.155937675810569905373
750 749 1122.458621356880512254133
751 750 1123.101117387809200166664
752 751 1125.314729397846470079799
753 752 1125.763442429252559466444
754 753 1127.658023527215719230775
755 754 1128.430224613892711372106
756 755 1129.728996777065562175089
757 756 1130.391597896231670832011
758 757 1131.495085561917043222287
759 758 1133.70862566945623585141
760 759 1134.885654591533196430624
761 760 1135.562213975477545956522
762 761 1136.92929348096952978547
763 762 1138.151589779805540729234
764 763 1138.99234182049363589386
765 764 1140.721848171903359752655
766 765 1141.261022964136758329982
767 766 1142.858659607856481118499
768 767 1144.782299518625341877065
769 768 1145.485327517117106808017
770 769 1146.576814924866953406052
771 770 1147.5017765233193160913
772 771 1148.615277208834019003767
773 772 1149.982601028107097665449
774 773 1151.562814723673218149389
775 774 1152.943128530589795951639
776 775 1153.890303716271268026583
777 776 1154.697519535382382913171
778 777 1156.621567833872543410579
779 778 1157.432314575610906332865
780 779 1158.001609027294966145087
781 780 1159.480657019022297309405
782 781 1161.396644634378091498489
783 782 1162.487528602005427804018
784 783 1163.701031682778615587642
785 784 1164.73758635122760993462
786 785 1165.271227706457693605534
787 786 1166.943613409528712677106
788 787 1168.086271610138794297938
789 788 1169.698356884884906186469
790 789 1170.463638578283666041216
791 790 1172.120681865695599846401
792 791 1173.305687764048358727042
793 792 1174.232766856456302652064
794 793 1175.215452395950775247031
795 794 1176.632875809788458632994
796 795 1177.106304421656146949
797 796 1179.701223501933898032584
798 797 1180.653543787084385330874
799 798 1181.267318151680018959133
800 799 1182.582270346920390440041
801 800 1183.71277529597431534989
802 801 1185.15584284746579228302
803 802 1185.875358695356620012619
804 803 1187.345161493267309955547
805 804 1188.856444298229306788806
806 805 1189.963636497918443343749
807 806 1191.482605926413470865133
808 807 1192.218611478101545077892
809 808 1193.32402142745508027539
810 809 1193.857427135436991965941
811 810 1196.034671748671062232112
812 811 1197.071786658821966804479
813 812 1198.686569104630566476487
814 813 1199.356513707893968131881
815 814 1200.532692031219914310338
816 815 1201.81033485660604978646
817 816 1203.137350861425479452833
818 817 1203.855247594097002027003
819 818 1204.985492171466410715587
820 819 1206.870499793853068292138
821 820 1208.471459949531031462999
822 821 1208.989484167939025676653
823 822 1209.898030087545955753378
824 823 1211.416115892798123060479
825 824 1212.113153066319792624394
826 825 1213.598372680368218485135
827 826 1215.389975065045634269814
828 827 1216.183722033467416723773
829 828 1217.174482497738919039772
830 829 1219.050028177406163509277
831 830 1219.614471310858484310222
832 831 1220.816347690978131430685
833 832 1221.692242483143733211793
834 833 1222.952484095108358242564
835 834 1225.018330024168539197352
836 835 1225.855020760795715396661
837 836 1227.231827641490931924146
838 837 1227.917141614400044405946
839 838 1228.793154362981171769179
840 839 1230.584603154249275719502
841 840 1231.562273877645398164718
842 841 1232.529587040597895551034
843 842 1234.277816653431788048844
844 843 1235.502548526520997318717
845 844 1236.399017465778995865444
846 845 1237.977298513581145513426
847 846 1238.457232795661807116333
848 847 1239.490807146795754277705
849 848 1240.81347178521626689152
850 849 1243.07807639802111888152
851 850 1243.538146526114259980474
852 851 1244.851433966983858564582
853 852 1245.655866188147822478804
854 853 1247.372561969855643915704
855 854 1248.063061053208198685149
856 855 1249.159887953002983340583
857 856 1250.67239727567811715509
858 857 1251.659832004271221180038
859 858 1253.67357785210710201838
860 859 1254.431328421773449368517
861 860 1255.408230645290734638382
862 861 1256.181214198460866068256
863 862 1257.541219412644114426823
864 863 1258.779233488595053190671
865 864 1260.344548316185519868179
866 865 1261.611717161479839904325
867 866 1262.556614000356224342558
868 867 1263.6767328438617933304
869 868 1264.957223006999789287696
870 869 1266.17903776056206224283
871 870 1267.20034561184548922029
872 871 1267.570571779440223458644
873 872 1270.118921886492603925191
874 873 1271.134299631609991400292
875 874 1272.083959599332897422896
876 875 1273.261144633455752813727
877 876 1274.196220889480358828122
878 877 1275.092030315840457781671
879 878 1276.842171555569794685535
880 879 1277.76309198634682092061
881 880 1279.332843316708251394285
882 881 1280.155794409022930466591
883 882 1281.828726959699933928865
884 883 1283.000491386699676607703
885 884 1283.335032138879280600483
886 885 1284.854795154621657840431
887 886 1285.695023331138592774775
888 887 1287.410026617075316131673
889 888 1289.165351532773061481413
890 889 1290.104771519807337889522
891 890 1290.417708073042503662544
892 891 1291.945870968083198400458
893 892 1293.49398155741744506202
894 893 1294.11847437784835238611
895 894 1295.365363505358250254932
896 895 1296.801110992347291502194
897 896 1298.256527067889529432349
898 897 1299.405171250743978398316
899 898 1300.490018982447638393471
900 899 1301.495516680575058356356
901 900 1302.346742379246917920513
902 901 1303.273200228794143469156
903 902 1305.401672188004384663012
904 903 1306.508393312968836971734
905 904 1307.267242107802427097784
906 905 1308.988196517643387242108
907 906 1309.421532493255966673811
908 907 1311.056570511111896663932
909 908 1311.966940608049354868811
910 909 1313.031599369019664552443
911 910 1314.052565651726166193373
912 911 1316.21211260285404978029
913 912 1317.072986034829955001008
914 913 1318.17127913216505254858
915 914 1318.947880596566338336391
916 915 1319.931082877536473052035
917 916 1321.628138551912418057466
918 917 1322.258067123391157945194
919 918 1324.224978718844330913229
920 919 1325.237624358982335353497
921 920 1325.981969630446281223042
922 921 1327.635281108457449640352
923 922 1329.043517996518601239812
924 923 1329.205018785483634847618
925 924 1330.429937120459263182661
926 925 1331.827591385285217523542
927 926 1333.673522610284933270976
928 927 1334.747329051689776530339
929 928 1335.694974526002066589015
930 929 1336.690184653385871053535
931 930 1337.688791809669949603148
932 931 1338.923164598670349828982
933 932 1340.426400457300175789734
934 933 1341.166272252926387071935
935 934 1342.6085078837768613275
936 935 1344.156044003595790998204
937 936 1345.477106261398714427407
938 937 1345.731413255418407759007
939 938 1347.519471750899911107227
940 939 1348.017238018736410091624
941 940 1349.085194014047657980739
942 941 1351.296206374096718009838
943 942 1352.210465159175538379449
944 943 1353.483338358264576553756
945 944 1353.886781971696227684236
946 945 1355.680595320636491886858
947 946 1356.605655709807953919675
948 947 1357.771742828579464071801
949 948 1358.460160399159026437355
950 949 1360.39314476219115231209
951 950 1361.393074713639681698891
952 951 1363.022328603280756838543
953 952 1363.879190797134472437965
954 953 1364.57658489675397264128
955 954 1365.493733551295247265436
956 955 1367.104090970008230879955
957 956 1368.330193307985894894878
958 957 1369.686949077342916601034
959 958 1370.973522767783644045922
960 959 1371.68655355282739112883
961 960 1373.202914562373382103296
962 961 1374.15479865864064562652
963 962 1375.302392344748902154821
964 963 1376.161779993619352038765
965 964 1377.177633642104626322482
966 965 1379.683283028612926385772
967 966 1380.148578441692403063928
968 967 1381.073977149205634870657
969 968 1382.345662978473679887742
970 969 1383.297591007946474903317
971 970 1384.444415847760082973396
972 971 1385.663777011192686438874
973 972 1387.326647663489530605697
974 973 1387.921454127112797023169
975 974 1389.56583179839393719501
976 975 1390.705490286427665121515
977 976 1391.853200443269755384527
978 977 1392.644027788548648255831
979 978 1393.433401740793665026417
980 979 1394.884184675680354479029
981 980 1396.544163123682501770248
982 981 1397.834623321387224279315
983 982 1398.837675201385865233911
984 983 1399.839472941206481467054
985 984 1400.426946297394298261051
986 985 1402.564347250065993817191
987 986 1402.973747640919208050497
988 987 1404.006292170522757129441
989 988 1405.666975059246875092257
990 989 1407.085142776436486841204
991 990 1408.136307496189550754764
992 991 1409.320681079838957249711
993 992 1410.024810725802225833083
994 993 1411.257056815706623860024
995 994 1411.965653461773004284494
996 995 1413.843148788568852998798
997 996 1415.585784795495351208993
998 997 1415.781581303282910082772
999 998 1417.102822933822614755625
1000 999 1418.696963852452165675233
1001 1000 1419.422480945995686465989

E-002-zeros-first-10000.json — 712 bytes, updated 08-17-2026

JSON sidecar (click to expand)
{
  "experiment": "E-002",
  "task": "0.6a",
  "description": "First 10000 nontrivial zero ordinates via mpmath.zetazero (multiprocess)",
  "script": "research/numerics/scripts/E-002-first-zeros.py",
  "parameters": {
    "n_zeros": 10000,
    "dps": 25,
    "workers": 15
  },
  "checks": {
    "strictly_monotone": true,
    "gamma_1_matches_known": true,
    "riemann_von_mangoldt_abs_error": "0.3207309991"
  },
  "gap_statistics": {
    "min_gap": "0.03769849773",
    "max_gap": "6.887314497",
    "mean_gap": "0.9864634392",
    "local_mean_spacing_at_end": "0.8536743703"
  },
  "elapsed_seconds": 0.0,
  "timestamp_utc": "2026-08-17T20:09:20.100449+00:00",
  "row_count": 10000
}

Source code

Python script (click to expand)
"""E-002 — Task 0.6a: first 10^4 nontrivial zero ordinates of zeta.

Computes γ_n = Im(ρ_n) for n = 1..N via mpmath.zetazero at dps 25.
Parallel: multiprocessing over contiguous n-blocks (zetazero(n) is
independent per n); each worker writes its own part file with per-row
flush (crash-safe), main merges. Resumable: existing complete part files
are skipped.

Sanity checks: strict monotonicity; γ_1 = 14.134725141734693790…;
Riemann–von Mangoldt N(T) agreement at T = γ_N.

Outputs: research/numerics/data/E-002-zeros-first-10000.csv (+ .json)
Parts:   research/numerics/data/E-002-parts/part-NNN.csv
Cached:  does not recompute if final CSV is complete (use --force).
"""
import json
import os
import sys
import time
from datetime import datetime, timezone
from multiprocessing import Pool
from pathlib import Path

import mpmath as mp
import numpy as np

REPO = Path(__file__).resolve().parents[3]
DATA = REPO / "research" / "numerics" / "data"
PARTS = DATA / "E-002-parts"
N_ZEROS = 10_000
DPS = 25
N_WORKERS = min(15, os.cpu_count() or 4)  # leave one core for the OS

CSV = DATA / "E-002-zeros-first-10000.csv"
JSON = DATA / "E-002-zeros-first-10000.json"


def block_bounds(n_blocks: int):
    bounds = []
    per = N_ZEROS // n_blocks
    lo = 1
    for b in range(n_blocks):
        hi = N_ZEROS if b == n_blocks - 1 else lo + per - 1
        bounds.append((lo, hi))
        lo = hi + 1
    return bounds


def part_path(lo: int) -> Path:
    return PARTS / f"part-{lo:05d}.csv"


def compute_block(lo: int, hi: int) -> str:
    mp.mp.dps = DPS
    p = part_path(lo)
    tmp = p.with_suffix(".tmp")
    with tmp.open("w", encoding="utf-8", newline="") as f:
        for n in range(lo, hi + 1):
            g = mp.im(mp.zetazero(n))
            f.write(f"{n},{mp.nstr(g, DPS)}\n")
            f.flush()  # crash-safe: no buffered loss on kill
    os.replace(tmp, p)  # atomic: complete parts only
    return str(p)


def part_complete(lo: int, hi: int) -> bool:
    p = part_path(lo)
    if not p.exists():
        return False
    with p.open(encoding="utf-8") as f:
        return sum(1 for _ in f) == hi - lo + 1


def main() -> int:
    force = "--force" in sys.argv
    if CSV.exists() and JSON.exists() and not force:
        with CSV.open(encoding="utf-8") as f:
            if sum(1 for _ in f) - 1 >= N_ZEROS:
                print(f"cached: {CSV} complete (use --force to recompute)")
                return 0
    DATA.mkdir(parents=True, exist_ok=True)
    PARTS.mkdir(parents=True, exist_ok=True)

    blocks = block_bounds(N_WORKERS)
    todo = [(lo, hi) for lo, hi in blocks
            if force or not part_complete(lo, hi)]
    print(f"blocks: {len(blocks)} total, {len(todo)} to compute "
          f"({N_WORKERS} workers)")

    t0 = time.time()
    if todo:
        with Pool(N_WORKERS) as pool:
            for i, path in enumerate(pool.starmap(compute_block, todo), 1):
                print(f"  part done {i}/{len(todo)}: {Path(path).name} "
                      f"({time.time()-t0:.0f}s)", flush=True)

    # merge
    rows = []
    for lo, hi in blocks:
        with part_path(lo).open(encoding="utf-8") as f:
            rows.extend(f.read().strip().splitlines())
    rows.sort(key=lambda r: int(r.split(",", 1)[0]))
    with CSV.open("w", encoding="utf-8", newline="") as f:
        f.write("n,gamma_n\n")
        f.write("\n".join(rows) + "\n")
    elapsed = time.time() - t0

    # sanity checks
    mp.mp.dps = DPS
    # full-precision values straight from the CSV text (not float64 reload)
    with CSV.open(encoding="utf-8") as f:
        next(f)
        gammas = [mp.mpf(line.split(",", 1)[1]) for line in f]
    mono = all(gammas[i] < gammas[i + 1] for i in range(len(gammas) - 1))
    g1_known = mp.mpf("14.134725141734693790457251983562470270784257115699")
    g1_ok = abs(gammas[0] - g1_known) < mp.mpf("1e-20")
    T = gammas[-1]
    rvm = (T / (2 * mp.pi)) * (mp.log(T / (2 * mp.pi)) - 1) + mp.mpf("0.875")
    rvm_err = abs(N_ZEROS - rvm)
    gaps = [gammas[i + 1] - gammas[i] for i in range(len(gammas) - 1)]
    stats = {
        "min_gap": mp.nstr(min(gaps), 10),
        "max_gap": mp.nstr(max(gaps), 10),
        "mean_gap": mp.nstr(sum(gaps) / len(gaps), 10),
        "local_mean_spacing_at_end": mp.nstr(2 * mp.pi / mp.log(T / (2 * mp.pi)), 10),
    }
    print(f"monotone: {mono} | g1 ok: {g1_ok} | RvM err: "
          f"{mp.nstr(rvm_err, 5)} (should be << log T = "
          f"{mp.nstr(mp.log(T), 3)})")
    print("gap stats:", stats)

    meta = {
        "experiment": "E-002",
        "task": "0.6a",
        "description": f"First {N_ZEROS} nontrivial zero ordinates via "
                       "mpmath.zetazero (multiprocess)",
        "script": "research/numerics/scripts/E-002-first-zeros.py",
        "parameters": {"n_zeros": N_ZEROS, "dps": DPS,
                       "workers": N_WORKERS},
        "checks": {
            "strictly_monotone": bool(mono),
            "gamma_1_matches_known": bool(g1_ok),
            "riemann_von_mangoldt_abs_error": mp.nstr(rvm_err, 10),
        },
        "gap_statistics": stats,
        "elapsed_seconds": round(elapsed, 1),
        "timestamp_utc": datetime.now(timezone.utc).isoformat(),
        "row_count": N_ZEROS,
    }
    JSON.write_text(json.dumps(meta, indent=2), encoding="utf-8")
    ok = mono and g1_ok and rvm_err < 2 * mp.log(T)
    print(f"wrote {CSV.name}, {JSON.name} in {elapsed:.0f}s — "
          f"{'ALL CHECKS PASS' if ok else 'CHECK FAILURE'}")
    return 0 if ok else 1


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