From b7d56cd87f8e97c3c28cb150dc89995490ba6a0c Mon Sep 17 00:00:00 2001 From: rohanarun Date: Sun, 11 Oct 2026 03:52:37 -0400 Subject: [PATCH 1/2] Add conditional signed-prefix donor gauge construction and standalone audits --- .github/workflows/e8-signed-donor-gauge.yml | 32 + research/e8-signed-donor-gauge/.gitattributes | 1 + research/e8-signed-donor-gauge/MANIFEST.json | 189 + research/e8-signed-donor-gauge/README.txt | 4 + research/e8-signed-donor-gauge/SOURCE.json | 6 + .../code/pricing/base_two_moment.py | 63 + .../pr370-e8-screen/code/pricing/moment.py | 113 + .../pr370-e8-screen/code/pricing/outer.py | 58 + .../code/pricing/prime_witnesses.py | 99 + .../candidate-guard/candidate-pins.json | 60 + .../candidate-source-pins.json | 482 + .../candidate-guard/code/bridged.py | 105 + .../candidate-guard/code/complex_basis.py | 35 + .../candidate-guard/code/complex_gx.py | 77 + .../candidate-guard/code/complex_labels.py | 185 + .../candidate-guard/code/complex_scalars.py | 219 + .../candidate-guard/code/complex_splice.py | 284 + .../candidate-guard/code/p10pins.py | 15 + .../candidate-guard/code/scatter.py | 33 + .../candidate-guard/derived-pins.json | 32 + .../candidate-guard/inputs/complex/LICENSE | 201 + .../candidate-guard/inputs/complex/NOTICE | 290 + .../inputs/complex/retained/FINITE_BRIDGE.txt | 141 + .../retained/compact-control-layout.tex | 118 + .../retained/compact-control-movement.tex | 167 + .../retained/copied-centers-assembly.tex | 118 + .../complex/retained/copied-centers-lemma.tex | 103 + .../retained/endpoint-gauge-complex.tex | 225 + .../retained/general-clifford-frames.tex | 102 + .../retained/stopped-product-complex.tex | 137 + .../inputs/complex/source-pins.json | 482 + .../complex/sources/Work__Bridge__Cert.lean | 241 + .../complex/sources/Work__Bridge__Net.lean | 345 + .../complex/sources/Work__Carrier__Live.lean | 232 + .../sources/Work__Carrier__Phases.lean | 192 + .../complex/sources/Work__Fourier__Main.lean | 176 + .../sources/Work__GCert__Chain__Geom.lean | 210 + .../sources/Work__GCert__Chain__InvThm.lean | 164 + .../sources/Work__GCert__Chain__NetCert.lean | 157 + .../sources/Work__GCert__Chain__NetDef.lean | 157 + .../sources/Work__GCert__Chain__NetStage.lean | 186 + .../sources/Work__GCert__Chain__Phased.lean | 199 + .../sources/Work__GCert__Chain__WinB.lean | 132 + .../Work__GCert__Data__B2Gp193Main.lean | 33 + .../sources/Work__GCert__Data__Glue.lean | 97 + .../Work__GCert__Data__InstB2Gp193.lean | 55 + .../sources/Work__GCert__Data__P193Cert.lean | 81 + .../sources/Work__GCert__Data__P193Price.lean | 54 + .../Work__GCert__Data__P193ScalOK.lean | 17 + .../Work__GCert__Data__RateB2Gp193x.lean | 327 + .../sources/Work__GCert__Data__Raw.lean | 93 + .../Work__GCert__Data__SolutionB2Gp193x.lean | 38 + .../sources/Work__GFrame__Engine__Adapt.lean | 183 + .../Work__GFrame__Engine__Letters.lean | 199 + .../sources/Work__GFrame__Engine__Level.lean | 163 + .../complex/sources/tools__gx__ORIGIN.md | 64 + .../inputs/complex/sources/tools__gx__gx.py | 296 + .../complex/sources/tools__gx__gxbind.py | 438 + .../complex/sources/tools__gx__gxconv.py | 131 + .../complex/sources/tools__gx__gxcore.py | 375 + .../candidate-guard/inputs/e8/LICENSE | 201 + .../candidate-guard/inputs/e8/NOTICE | 489 + .../inputs/e8/Work/GCert/Data/B2Ge8.lean | 103 + .../inputs/e8/Work/GCert/Data/B2Ge8Main.lean | 33 + .../e8/Work/GCert/Data/ChallengeB2Ge8x.lean | 331 + .../inputs/e8/Work/GCert/Data/E8Cert.lean | 78 + .../inputs/e8/Work/GCert/Data/E8Price.lean | 54 + .../inputs/e8/Work/GCert/Data/E8ScalOK.lean | 15 + .../inputs/e8/Work/GCert/Data/Gen/E8.lean | 12 + .../inputs/e8/Work/GCert/Data/Gen/E8/S0.lean | 128 + .../inputs/e8/Work/GCert/Data/Gen/E8End.lean | 10 + .../inputs/e8/Work/GCert/Data/Gen/E8Hist.lean | 46 + .../inputs/e8/Work/GCert/Data/Gen/E8Par.lean | 8 + .../e8/Work/GCert/Data/Gen/E8Scal0.lean | 10 + .../inputs/e8/Work/GCert/Data/Gen/E8Seg0.lean | 9 + .../inputs/e8/Work/GCert/Data/Gen/E8Seg1.lean | 9 + .../inputs/e8/Work/GCert/Data/Gen/E8SegF.lean | 9 + .../inputs/e8/Work/GCert/Data/Gen/E8Tab0.lean | 10 + .../inputs/e8/Work/GCert/Data/Gen/E8Tab1.lean | 10 + .../inputs/e8/Work/GCert/Data/Gen/E8Tab2.lean | 10 + .../inputs/e8/Work/GCert/Data/Gen/E8Tab3.lean | 10 + .../inputs/e8/Work/GCert/Data/Gen/E8YChk.lean | 10 + .../inputs/e8/Work/GCert/Data/InstB2Ge8.lean | 55 + .../inputs/e8/Work/GCert/Data/RateB2Ge8.lean | 207 + .../inputs/e8/Work/GCert/Data/RateB2Ge8x.lean | 207 + .../e8/Work/GCert/Data/SolutionB2Ge8x.lean | 38 + .../inputs/e8/comparator/B2Ge8x.json | 14 + .../tools/certificate/gcert1-e8-r783.json.gz | Bin 0 -> 22008 bytes .../inputs/e8/tools/e8/replay.py | 797 + .../inputs/e8/tools/gen/foldgen.py | 128 + .../inputs/e8/tools/gen/foldlib.py | 146 + .../inputs/e8/tools/gen/gen_rates.py | 30 + .../inputs/e8/tools/gen/gen_sharp.py | 33 + .../gen/templates/ChallengeB2L16x.lean.txt | 331 + .../gen/templates/SolutionB2L16x.lean.txt | 38 + .../inputs/e8/tools/gx/gsmirror.py | 332 + .../inputs/e8/tools/gx/gxbind.py | 438 + .../inputs/e8/tools/gx/gxcore.py | 375 + .../inputs/e8/tools/gx/gxgen.py | 256 + .../inputs/e8/tools/gx/gxpaths.py | 21 + .../inputs/e8/tools/gx/gxrate.py | 195 + .../inputs/e8/tools/gx/gxunit.py | 47 + .../inputs/e8/tools/gx/regen_check.py | 80 + .../inputs/e8/tools/gx/regen_check_e8.py | 41 + .../candidate-guard/new-derived-pins.json | 42 + .../candidate-guard/pins-e8-b3.json | 59 + .../candidate-guard/pins-e8.json | 58 + .../candidate-guard/portable_complex.py | 170 + .../complex-nine-native/CLIFFORD-RECIPES.json | 1 + .../complex-nine-native/CLIFFORD-REVIEW.json | 47 + .../work/complex-nine-native/DATA-PHASES.json | 73604 ++++++++++++++++ .../complex-nine-native/GLOBAL-REVIEW.json | 70 + .../GLOBAL-TEMPLATE.json.gz | Bin 0 -> 415340 bytes .../INDEPENDENT-TEMPLATE-AUDIT.json | 32 + .../OUTER-REPORTED-382-BIT.json | 58 + .../local-admission/INDEPENDENT-AUDIT.json | 31 + .../local-admission/UPSTREAM-GUARD.json | 1024 + .../odd-stages/COMPLEX-NINE-CANDIDATE.json | 3077 + .../compressed/work/odd-stages/RECIPE-9.json | 114 + .../work/odd-stages/audit_nine_template.py | 76 + .../work/odd-stages/clifford_exact.py | 149 + .../work/odd-stages/complex_candidate.py | 109 + .../compressed/work/odd-stages/data_phases.py | 98 + .../compressed/work/odd-stages/global_nine.py | 115 + .../compressed/work/odd-stages/outer_fixed.py | 16 + .../work/odd-stages/verify_clifford_frames.py | 64 + .../pr378-complex-screen/package/LICENSE | 201 + .../package/MANIFEST.sha256 | 26 + .../pr378-complex-screen/package/NOTICE.md | 21 + .../pr378-complex-screen/package/PROOF.md | 34 + .../pr378-complex-screen/package/README.md | 111 + .../package/code/cxcheck.py | 23 + .../package/code/cxfar.py | 85 + .../package/code/cxfinal.py | 29 + .../package/code/cxkernel.py | 222 + .../pr378-complex-screen/package/code/cxop.py | 32 + .../package/code/cxpiece.py | 64 + .../package/code/cxretime.py | 169 + .../package/code/cxsplit.py | 92 + .../package/code/e8core.py | 203 + .../package/code/engines/base_two_moment.py | 63 + .../package/code/engines/moment.py | 113 + .../package/code/engines/outer.py | 58 + .../package/code/kappa.py | 52 + .../package/code/layout_bk.py | 63 + .../complex/LICENSE-wht-power-saving-lean | 201 + .../complex/NOTICE-wht-power-saving-lean | 489 + .../package/complex/gcert1-e8-r783.json.gz | Bin 0 -> 21883 bytes .../package/complex/gx/gx.py | 296 + .../package/complex/gx/gxcore.py | 375 + .../package/data/bit/bitE8-r865.json.gz | Bin 0 -> 33865 bytes .../package/data/gcert1-e8-r783-far.json.gz | Bin 0 -> 22008 bytes .../pr378-complex-screen/package/verify.sh | 67 + .../AMBIENT-GAUGE-INTEGRATION.txt | 55 + .../pr378-donor-screen/LOCAL-GAUGE-LIFT.txt | 70 + .../ambient-phase-audit.json | 11 + .../pr378-donor-screen/assemble_signed25.py | 21 + .../audit_complete_schedule.py | 113 + .../audit_signed25_gauge.py | 71 + .../audit_signed25_global.py | 19 + .../best-bank-geometry.json | 108 + .../best-bank-owners.json.gz | Bin 0 -> 31977 bytes .../pr378-donor-screen/best-candidate.json.gz | Bin 0 -> 22063 bytes .../pr378-donor-screen/best-local-audit.json | 162 + .../bound-schedule-audit.json | 35 + .../pr378-donor-screen/check_ambient_phase.py | 52 + .../check_signed25_composition.py | 50 + .../check_signed25_gauge_lift.py | 78 + .../pr378-donor-screen/emit_signed25_gauge.py | 107 + .../pr378-donor-screen/integrate_signed25.py | 46 + .../pr395-small/EXPECTED-COARSE.json | 16 + .../pr395-small/EXPECTED-DISCOVERY.json | 17 + .../pr395-small/EXPECTED-PROFILE.json | 14 + .../pr395-small/EXPECTED-WITNESS.json | 220 + .../pr395-small/MANIFEST.json | 12 + .../pr378-donor-screen/pr395-small/PROOF.md | 13 + .../pr378-donor-screen/pr395-small/README.md | 7 + .../pr395-small/SELECTION.json | 358 + .../pr395-small/SOURCE.json | 8 + .../pr395-small/construct.py | 79 + .../pr378-donor-screen/pr395-small/pins.json | 60 + .../pr378-donor-screen/pr395-small/verify.py | 56 + .../prefix-donor-candidate.json.gz | Bin 0 -> 22402 bytes .../prefix-gauge-bound-template.json.gz | Bin 0 -> 457716 bytes .../prefix-gauge-routes.json.gz | Bin 0 -> 108541 bytes .../pr378-donor-screen/refine_candidate.py | 39 + .../pr386-phase-screen/fresh/COMBINED.json | 115 + .../e8-signed-donor-gauge/requirements.txt | 1 + research/e8-signed-donor-gauge/verify.py | 24 + 189 files changed, 98755 insertions(+) create mode 100644 .github/workflows/e8-signed-donor-gauge.yml create mode 100644 research/e8-signed-donor-gauge/.gitattributes create mode 100644 research/e8-signed-donor-gauge/MANIFEST.json create mode 100644 research/e8-signed-donor-gauge/README.txt create mode 100644 research/e8-signed-donor-gauge/SOURCE.json create mode 100644 research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/base_two_moment.py create mode 100644 research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/moment.py create mode 100644 research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/outer.py create mode 100644 research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/prime_witnesses.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/candidate-pins.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/candidate-source-pins.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/bridged.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_basis.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_gx.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_labels.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_scalars.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_splice.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/p10pins.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/scatter.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/derived-pins.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/LICENSE create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/NOTICE create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/FINITE_BRIDGE.txt create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-layout.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-movement.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-assembly.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-lemma.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/endpoint-gauge-complex.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/general-clifford-frames.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/stopped-product-complex.tex create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/source-pins.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Cert.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Net.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Live.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Phases.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Fourier__Main.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Geom.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__InvThm.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetCert.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetDef.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetStage.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Phased.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__WinB.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__B2Gp193Main.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Glue.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__InstB2Gp193.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Cert.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Price.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193ScalOK.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__RateB2Gp193x.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Raw.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__SolutionB2Gp193x.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Adapt.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Letters.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Level.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__ORIGIN.md create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gx.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxbind.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxconv.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxcore.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/LICENSE create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/NOTICE create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8Main.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/ChallengeB2Ge8x.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Cert.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Price.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8ScalOK.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8/S0.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8End.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Hist.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Par.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Scal0.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg0.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg1.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8SegF.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab0.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab1.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab2.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab3.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8YChk.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/InstB2Ge8.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8x.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/SolutionB2Ge8x.lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/comparator/B2Ge8x.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/certificate/gcert1-e8-r783.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/e8/replay.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldgen.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldlib.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_rates.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_sharp.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/ChallengeB2L16x.lean.txt create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/SolutionB2L16x.lean.txt create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gsmirror.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxbind.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxcore.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxgen.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxpaths.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxrate.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxunit.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check_e8.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/new-derived-pins.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8-b3.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/portable_complex.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/CLIFFORD-RECIPES.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/CLIFFORD-REVIEW.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/DATA-PHASES.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/GLOBAL-REVIEW.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/GLOBAL-TEMPLATE.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/INDEPENDENT-TEMPLATE-AUDIT.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/OUTER-REPORTED-382-BIT.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/local-admission/INDEPENDENT-AUDIT.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/complex-nine-native/local-admission/UPSTREAM-GUARD.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/COMPLEX-NINE-CANDIDATE.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/RECIPE-9.json create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/audit_nine_template.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/clifford_exact.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/complex_candidate.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/data_phases.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/global_nine.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/outer_fixed.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/compressed/work/odd-stages/verify_clifford_frames.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/LICENSE create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/MANIFEST.sha256 create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/NOTICE.md create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/PROOF.md create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/README.md create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxcheck.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxfar.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxfinal.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxkernel.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxop.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxpiece.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxretime.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/cxsplit.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/e8core.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/engines/base_two_moment.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/engines/moment.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/engines/outer.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/kappa.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/code/layout_bk.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/complex/LICENSE-wht-power-saving-lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/complex/NOTICE-wht-power-saving-lean create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/complex/gcert1-e8-r783.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/complex/gx/gx.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/complex/gx/gxcore.py create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/data/bit/bitE8-r865.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/data/gcert1-e8-r783-far.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-complex-screen/package/verify.sh create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/AMBIENT-GAUGE-INTEGRATION.txt create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/LOCAL-GAUGE-LIFT.txt create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/ambient-phase-audit.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/assemble_signed25.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/audit_complete_schedule.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/audit_signed25_gauge.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/audit_signed25_global.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/best-bank-geometry.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/best-bank-owners.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/best-candidate.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/best-local-audit.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/bound-schedule-audit.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/check_ambient_phase.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/check_signed25_composition.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/check_signed25_gauge_lift.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/emit_signed25_gauge.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/integrate_signed25.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/EXPECTED-COARSE.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/EXPECTED-DISCOVERY.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/EXPECTED-PROFILE.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/EXPECTED-WITNESS.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/MANIFEST.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/PROOF.md create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/README.md create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/SELECTION.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/SOURCE.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/construct.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/pins.json create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/pr395-small/verify.py create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/prefix-donor-candidate.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/prefix-gauge-bound-template.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/prefix-gauge-routes.json.gz create mode 100644 research/e8-signed-donor-gauge/pr378-donor-screen/refine_candidate.py create mode 100644 research/e8-signed-donor-gauge/pr386-phase-screen/fresh/COMBINED.json create mode 100644 research/e8-signed-donor-gauge/requirements.txt create mode 100644 research/e8-signed-donor-gauge/verify.py diff --git a/.github/workflows/e8-signed-donor-gauge.yml b/.github/workflows/e8-signed-donor-gauge.yml new file mode 100644 index 0000000000..54b08a84bb --- /dev/null +++ b/.github/workflows/e8-signed-donor-gauge.yml @@ -0,0 +1,32 @@ +name: E8 signed donor gauge +on: + pull_request: + paths: + - 'research/e8-signed-donor-gauge/**' + - '.github/workflows/e8-signed-donor-gauge.yml' + workflow_dispatch: +permissions: + contents: read +jobs: + verify: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python: ['3.11', '3.14'] + steps: + - uses: actions/checkout@v4 + with: + lfs: false + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - run: python -m pip install -r research/e8-signed-donor-gauge/requirements.txt + - run: python -B research/e8-signed-donor-gauge/verify.py "$RUNNER_TEMP/e8-signed-donor-output" + env: + PYTHONDONTWRITEBYTECODE: '1' + - uses: actions/upload-artifact@v4 + if: always() + with: + name: e8-signed-donor-${{ matrix.python }} + path: ${{ runner.temp }}/e8-signed-donor-output/*.json diff --git a/research/e8-signed-donor-gauge/.gitattributes b/research/e8-signed-donor-gauge/.gitattributes new file mode 100644 index 0000000000..0c90828557 --- /dev/null +++ b/research/e8-signed-donor-gauge/.gitattributes @@ -0,0 +1 @@ +*.gz -filter -diff -merge diff --git a/research/e8-signed-donor-gauge/MANIFEST.json b/research/e8-signed-donor-gauge/MANIFEST.json new file mode 100644 index 0000000000..46a044713d --- /dev/null +++ b/research/e8-signed-donor-gauge/MANIFEST.json @@ -0,0 +1,189 @@ +{ + ".gitattributes": "56489ba7e3d3506e7db006b56de732f3e2169e2a18a9d8da1a164f53fde8b240", + "README.txt": "ce6b7f113c43368122917c8a17e3c868f5de5cef5031ee5ba126aa1ae1653d1b", + "requirements.txt": "25f9f1fb1988b230147a1d3092d34e09c069eb7a6c6d6df46b3973b9f2d36efc", + "SOURCE.json": "ae34a312d94132bc758c3e851119b7853d3c2acec80477316f23d9e40066de61", + "verify.py": "2a70a99f21e15a9475552a0e97cc45deecb3d95ff247ab07a3cc77870696169a", + "pr370-e8-screen/code/pricing/base_two_moment.py": "aee70c242a2f1d225528fabe2002e1564d1dc884797c07d28a831c7878ee9098", + "pr370-e8-screen/code/pricing/moment.py": "81cbc864e106418fc7854322746f72180cb8110ff39f74450a3b8d55a82c1482", + "pr370-e8-screen/code/pricing/outer.py": "c1ebb52163a7219504c728a5c2b098bf1e50bf20148a2879c5a74c3cadc7c03c", + "pr370-e8-screen/code/pricing/prime_witnesses.py": "98cd03bc9582e7bd0ab194c191ea8eea940539e510051443ab9fd3e572a364ab", + "pr378-complex-screen/candidate-guard/candidate-pins.json": "f8921199a1210802498117ed2ec4b7c9e8834436716e0dce8e388c8866cf4638", + "pr378-complex-screen/candidate-guard/candidate-source-pins.json": "a386359c046bf6c7ecfc8e372608efb23fc247d7f6ec8e9935d8fb6151ea8f67", + "pr378-complex-screen/candidate-guard/derived-pins.json": "42c46b8694f2f3682ddd5fffb5fb1c3cac08e919c33bafe8dda53b40c4d4fc2f", + "pr378-complex-screen/candidate-guard/new-derived-pins.json": "4a0d35f3cac4988ffae0346f530b2d02b1453f649769b5f7442cbc375de5a86c", + "pr378-complex-screen/candidate-guard/pins-e8-b3.json": "9e2d5b8e1f5f5d1c3113ed563ace88a3e5a605e1f053af350f1cec4d4791a4c4", + "pr378-complex-screen/candidate-guard/pins-e8.json": "bf66f785878f636616ceab193e5a222143945ea06fc2f13dfb99b204ebba82ff", + "pr378-complex-screen/candidate-guard/portable_complex.py": "a28cfd37ce5da0e97e03f225629f17f31e0278142b3757345ed47d7a66560cbf", + "pr378-complex-screen/candidate-guard/code/bridged.py": "5fe7174cd3a6580a74e4c1bf8fa7b426e8673f1c285603bf3076d4e758d70731", + "pr378-complex-screen/candidate-guard/code/complex_basis.py": "52d68781eaf6d9decf02446a532a7336fcf15924a9f6781ba0833d038decb9f8", + "pr378-complex-screen/candidate-guard/code/complex_gx.py": "ccc924537db0c0d55f0c1934e79b8cf4d85b4fb336473d7b42d69e12557aa9f2", + "pr378-complex-screen/candidate-guard/code/complex_labels.py": "e000ee131389fec427388b85f632879cbaaf10e5e5d979a47d6307d64ce58982", + "pr378-complex-screen/candidate-guard/code/complex_scalars.py": "c617b0fd2e18adcff15f6bf6cb3d54cc31f8432993be048b3442a5729eeff410", + "pr378-complex-screen/candidate-guard/code/complex_splice.py": "dfb4c9108bfea4a09f3e38f12b9dbe6164abab1a4fef8442ca593e2110d38ef4", + "pr378-complex-screen/candidate-guard/code/p10pins.py": "93b78a2e038b23264d04836928c78b6ebf33b87ff3dcc0e43ba0f1748fadd143", + "pr378-complex-screen/candidate-guard/code/scatter.py": "dfd1afbbb3ff86f54db6a0313916403ec8ee6f939caa62f3edcc9d7a151bff95", + "pr378-complex-screen/candidate-guard/inputs/complex/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", + "pr378-complex-screen/candidate-guard/inputs/complex/NOTICE": "9419dd03a2f52cf8bdfc4d18216ce29f263ab583b27f01ced8e420985bcb7c81", + "pr378-complex-screen/candidate-guard/inputs/complex/source-pins.json": "0d76527bf9c259b9532466a7b056ad6ff118867a96e044ff8e1a24aca12e1dbb", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-layout.tex": "2bc28e50f3eb092195294cafa81213e520f6d42e7935e9905ad8a6199e2a7c87", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-movement.tex": "b963c3d2f4e1b7059aa289bb4b4ac89b688920bcf42f5b20d7698cdef0132cc6", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-assembly.tex": "00117892971ae766188ace0af03030c44164fda105e42b70d84f52c3339a7dcb", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-lemma.tex": "d0ce6d3d504996aadb098227885224e48df46101daec8893523a0a8b7364d8fe", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/endpoint-gauge-complex.tex": "dfee33b0281e5551bb6927f757ff0240abade60ae1800f715afd88853ae0191e", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/FINITE_BRIDGE.txt": "66d8f4ea8752abd89952d6674a636575a0db16e18b1c16e293f48f64242f0c46", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/general-clifford-frames.tex": "c9bb9655b594583c6b4bab8cb485233f1d1e588f83858cf1e4c3530cee8fed54", + "pr378-complex-screen/candidate-guard/inputs/complex/retained/stopped-product-complex.tex": "4738089103a4b263b3b0ef458f5ef35519c696f1ea871ae79e508d3720f5870a", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gx.py": "6f3dc8bb639933227a8dae181ec4a542e85c7276be9c9e330f49518e7b630b95", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxbind.py": "9c9dcfac47f0535bf3aa8ebf7c662cdef0ebda50a9f0a9282b8f3cf34809f835", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxconv.py": "dab7fec9f44c2d368ed334055d7126e202017feb46e41a8d86e2d998720f67c2", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxcore.py": "eb972c06fe8c322db2d9a8d9a7d05596e8f40c4ca8e5f42eb6df3c7361b5d517", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__ORIGIN.md": "6ba897a9495ddadcf8558b93133fdfaf66fc35ce7fa2c53e2d5667335c315e0b", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Cert.lean": "5c24746a6330907b9b37d6064095035a58575d64ce793d6d7c9881121fdc3980", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Net.lean": "cf7d7d330b1bffe2e66712c873e647b13dc32db1ccfc0e0f4cd62ee6caf584f0", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Live.lean": "6d0649eb62589e66057f044e1e2103fc42f3f57a1498f82a26565bd8eb4026d0", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Phases.lean": "71dc3dda23dfe510d5d53cbada3a6c540cd1dc2825503fda618a5bd6cfc3e812", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Fourier__Main.lean": "2e8e88efd4dcbdf0b1a6e39ce7eea8c5fd5ffee2faf360a8c0c9cba84c0e4ef3", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Geom.lean": "c302f5834287421f11f3b0da7112fcde876cbc702896f2af4145b2d72ee393a2", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__InvThm.lean": "ade7e7873da75ca63a4b5ce2f562dde9c12bfbb69d87d7ae831039ff790e5adb", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetCert.lean": "22ae34809466b4ac2a2c5cdde526f51ff246f5189f7c142b38aa4c0dcffb04a4", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetDef.lean": "6e17a68b1e988969f6eb77000028f7ed877e687b8ad3976ec1707fcfe1d2f520", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetStage.lean": "c122bc01392a6fdcc0bee918fed81804d3c9b1d3e071016dab65a4ed804ef0b6", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Phased.lean": "0de429c80231334f1ce92575c1e8ac382ca2d5e7d956767b547639a8941d9a8c", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__WinB.lean": "c33ec3fce09c0971c32ddcbb86d9383ffbe4c6d05cf36f20460005e6547bb845", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__B2Gp193Main.lean": "cb61f304da51f1dd0a2ec25bca4b63eb095eeb2863289e1e2bdee7c82beff48b", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Glue.lean": "d5314f2b93a7f0e1c949fb502331825bfc6d9d8762d35f865443e7c95b6c7ef7", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__InstB2Gp193.lean": "9587ddb9961f44938032b609307ab91c0b0e757e3991f1ad95480dd50fd4f72b", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Cert.lean": "d92ee6889be4753fc99f467bd84039743325123a1165128378b9c906a04f2703", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Price.lean": "0299bcd0fe255960eec682eef0f045f7e5cb1e4711af2aab4393526eae2caea3", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193ScalOK.lean": "479434815822e98f015e335361089c3788d00dc3dd39c2944f75410aa0c158fe", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__RateB2Gp193x.lean": "6b40cac1481c931d47b1a092e382d04716ede0e785c492a2f2983e886a257c3f", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Raw.lean": "aba94a004c94dcae7cf3047c88a6da9561555f4ebe8ab92e299e6ce09ee7aa66", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__SolutionB2Gp193x.lean": "45c768c9d71a7cc18bd6db74cb036db880d89580ca60557bb4a492280296b169", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Adapt.lean": "feec0a3828867968a5c7c2c30b86ed70449abc3c660a60ada67203a75bae2ef7", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Letters.lean": "34906dbf5ae16b5174db00b4881a5cc1d2e583b8c8806db6523a5e2f86565f09", + "pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Level.lean": "80fb3daa9a45de0ed6da570eb4476b9104734be65d0116f58bcfcbcd67f771d0", + "pr378-complex-screen/candidate-guard/inputs/e8/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", + "pr378-complex-screen/candidate-guard/inputs/e8/NOTICE": "557c9ad4660eebd14a00583736c4d12d2c45f3fc9bc148845f9f3efec72c9434", + "pr378-complex-screen/candidate-guard/inputs/e8/comparator/B2Ge8x.json": "ddad06c37f9268986f3ec8ce43da5230ee2bd887da2480328413a0dc58f2a926", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/certificate/gcert1-e8-r783.json.gz": "f2664ee7bcdfb55893abe9f1be8ee6a394a602e8262e611de2a0328bbd508aa7", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/e8/replay.py": "be41ee310f28121c3e424cc8637d8fa02ef7c47fc8945e9bbd3856138fd800d6", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldgen.py": "a0f16e2c9e078ffbfb2174281ee93a48c18593aefb880318fc105ec85a205932", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldlib.py": "7a3c38a698c129e13a767da75926a1305eb0c031b908450afc6feb185505c59a", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_rates.py": "ef8c869e4cf8da33a4c10b96f7f6faafd46e15d66766238070a60315aa169994", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_sharp.py": "1b5eb3730cb16cf516e760879951fdfb9b065efc55f78c29a5c6404fcca57a78", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/ChallengeB2L16x.lean.txt": "0488b7a2442c795414f103df912d1e6cc66d37b5be270940ea9564b7f2b666be", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/SolutionB2L16x.lean.txt": "d414a890dfe126916374c1afc804b90e5081b7760f894b9ccdcf23d83a12f9ee", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gsmirror.py": "0e22bbe5924284e2fb916337ccefc8e41f6e54469749986ad15b3b81cfaec534", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxbind.py": "9c9dcfac47f0535bf3aa8ebf7c662cdef0ebda50a9f0a9282b8f3cf34809f835", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxcore.py": "eb972c06fe8c322db2d9a8d9a7d05596e8f40c4ca8e5f42eb6df3c7361b5d517", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxgen.py": "ce9151054370c2210ed08f54c249a19dcb6946d182cdf934dee1a3781b53040f", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxpaths.py": "f00802d48ef3fedb00278f0b1c7bde074cc49dd30f202d7f32a9d2aebb3be443", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxrate.py": "514a5719f970fe36b1273cf59df0396db0e042dd7864c2eea53ab2a2fd1e2ad6", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxunit.py": "3cc09a9c1a2db681c0f2016bc821af5b674d34834dbd6f195b9d482ce7c0ff58", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check.py": "b6172d58749c0b3b9138570c74827bcb23bf5db4ff9643740768cd7782ac4ca6", + "pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check_e8.py": "ad8fe9811c6ea0d89c795caef48686cfca600f5d540ebfd5d1251d6777cec7cf", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8.lean": "842b217147cf84e8042d6ef1c33104d5444b6587b594664bc9eb89b237ab4ad0", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8Main.lean": "987103107d5586c096016f0a702d0de35b74398dbb50ac66f5886a43a5ca0d05", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/ChallengeB2Ge8x.lean": "a59db9d54b83adc73391916f7c1ef5e381ff073027781c26cb350f43b79839e3", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Cert.lean": "13a243c7d7be31ae429d19b5ecd5d428d60c41b7cca8a330f0c4179b110ba7ea", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Price.lean": "cd250dd72406dde37765c501f666ceeedcc18f831070b26369bcb154c1f99a8e", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8ScalOK.lean": "6bd5e68effe8913a3f73e25ea59142cd9928ddf81e94250a6ea28aa7317388b3", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/InstB2Ge8.lean": "c1fee298187ea19b5d70fcfccef7d4fd4161be70c0adda19a89ca9933a759954", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8.lean": "7b6e59724c0f140e714afba237d5a1a91b22da70abc096ce274690140b39a3a6", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8x.lean": "7c56d865ed6bfcb6919dabc1a6e53f8744ff4824a2f78335787485f3090970d1", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/SolutionB2Ge8x.lean": "dd52f1fe0a372480edaf5e6c64903d6257c410e43d406f8acb6bf8f60a1ee28f", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8.lean": "5c7fb23df2c10b690f638a19bf066905b5b620b8a2ad0ffde76cc9348d8aa2b4", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8End.lean": "6ea83365afe01664b2132a630511b4de65f938dc328744ce7f77a01fad97f32d", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Hist.lean": "cce81699abe1f85a870dcf64edd395d2cf5a586da7700af565b557093095ab51", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Par.lean": "a343219b419f30f8ac4dd3a0a98bf53550c5fec6b2cbd245320a95977c319016", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Scal0.lean": "78036e5443775ade5bde46a77ba3e0433fe22160da11b5b6c96c7f1075ecfbbd", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg0.lean": "f6b248dc4c3b2c94db95989b6bd5ad3c3f0d7ece3a511e5b69069550b821b138", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg1.lean": "79d16ccceb61391446ea97f77fddadafa9150e9dea97919e775f6c78daa71839", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8SegF.lean": "924340aebc6f68b5a6526311ce33341af0a0a5a8375416762f08c1914ec08abe", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab0.lean": "650600b631a21221956f9abbab9abebcc9cca628512d3e9a017e2373e2649b17", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab1.lean": "60036fa4deeb19d39fc0dddf31359d2b6d2407ff66070f145b111bff16190eb0", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab2.lean": "c8a248da3eb770ba55ef267d118b29d49983311087ef789398d555e2c44b3a41", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab3.lean": "41975d430ec0095ad465a36d4903e90c01bc891d3abe5e2c372ef786c029a7ed", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8YChk.lean": "a290360c175544cb85edffe1b92fcf7d447cba09128e19de8dc87e0a1ff0c524", + "pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8/S0.lean": "36de82f6969c23082876a4d6848428623d1c65d2df3fc917f23ecba003189dd2", + "pr378-complex-screen/compressed/work/complex-nine-native/CLIFFORD-RECIPES.json": "1d09d59e7579912d07c8546f293d6ef1596a17b1c8d6e2ed061d279c0b366e1b", + "pr378-complex-screen/compressed/work/complex-nine-native/CLIFFORD-REVIEW.json": "3925b45b8473da5d011aaaa28f13495e318ff66174c833f65c17ccb4ebe1c442", + "pr378-complex-screen/compressed/work/complex-nine-native/DATA-PHASES.json": "f621f6d4296cb215f334830356c5f79fe10d6d04d15b3ccda76ba0885ab67d0a", + "pr378-complex-screen/compressed/work/complex-nine-native/GLOBAL-REVIEW.json": "51ec585f7bc5a4efb93c5aeb1fdf5b1020f60c871326514207efbfcfce0ca9bf", + "pr378-complex-screen/compressed/work/complex-nine-native/GLOBAL-TEMPLATE.json.gz": "452c2bd66c461d2f8851615d6c77802304d0421811b9d2af902166138d60a311", + "pr378-complex-screen/compressed/work/complex-nine-native/INDEPENDENT-TEMPLATE-AUDIT.json": "c57a0f0fa4f90fa8f42492da18f47e5adb3bfdb128271b7b35d9484df1207942", + "pr378-complex-screen/compressed/work/complex-nine-native/OUTER-REPORTED-382-BIT.json": "7396dbcfe6e42e892607d1e40a7e37c8792ea958bc32e2ecaba2cf8e6e3c3278", + "pr378-complex-screen/compressed/work/complex-nine-native/local-admission/INDEPENDENT-AUDIT.json": "1ae3c31ba3101f32114fbdaa9a471d7b4ea4280d7498b950e90619b6bfd86b9d", + "pr378-complex-screen/compressed/work/complex-nine-native/local-admission/UPSTREAM-GUARD.json": "9f8d33144c6cca6298a696ebea618d5a257f0ca0f1ca192e511b32fd32e29fb7", + "pr378-complex-screen/compressed/work/odd-stages/audit_nine_template.py": "c4fbdc8269808d6259dc36265df11595ab54fa35a2867cd862cf63d1665d7b16", + "pr378-complex-screen/compressed/work/odd-stages/clifford_exact.py": "2982ead07721e83358dc67c6f49c2b4c16a236a6bebdfd72f58221be1f5d0962", + "pr378-complex-screen/compressed/work/odd-stages/COMPLEX-NINE-CANDIDATE.json": "9faf137bdca651af0d54904ab9721574aa82f5d28b44c5725bf0cb8075f700b1", + "pr378-complex-screen/compressed/work/odd-stages/complex_candidate.py": "e4faf656403720f78223934bec90c667086453d449323c85fa839d19829b4517", + "pr378-complex-screen/compressed/work/odd-stages/data_phases.py": "671d6f8144c6d31e1766c6a0e144172da661a63f86b3d4d17fe2710f3ef752c4", + "pr378-complex-screen/compressed/work/odd-stages/global_nine.py": "65b29789956ec0ad4c1a3b371dd2a15a52ee95a7d31b3de6b2a87b3e45ade82f", + "pr378-complex-screen/compressed/work/odd-stages/outer_fixed.py": "0dc5b5a23bba5b4532cd11a290019d66d56ead611dddd3c40e2c9d0df64da198", + "pr378-complex-screen/compressed/work/odd-stages/RECIPE-9.json": "abda2e4c73ecb48d29c30c12bc9a5c2db71d11a35667b4298788ec9154eeec7b", + "pr378-complex-screen/compressed/work/odd-stages/verify_clifford_frames.py": "5d8cf110150c66f2e2df58ea4e24096f335740e2ae726a4778347d98053cfa76", + "pr378-complex-screen/package/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", + "pr378-complex-screen/package/MANIFEST.sha256": "f88d7300aeb8aa4bfef95c3571d0cc57d9726abfd75caee364e83ff211316a4a", + "pr378-complex-screen/package/NOTICE.md": "b4d2d9f6ed3419a56e76cc36bcab5059993c4853532401b56e4e77a8455d0f93", + "pr378-complex-screen/package/PROOF.md": "9d09e322645bdf4952758a76aa8a802ee1d58702bd66d4ad27285d5e5f6ed977", + "pr378-complex-screen/package/README.md": "fe46088149ee73dc8847004931c1e0175207d1ccfb6f7258961f09f5e6607e19", + "pr378-complex-screen/package/verify.sh": "779c48fc33d1dd967ed0b7125d86dfcac38f6e36dce82f6fbb2ac01742974530", + "pr378-complex-screen/package/code/cxcheck.py": "97b461509656798d30b2610b4755ce825b1f84ae8772b9b4efd5c84d7404385b", + "pr378-complex-screen/package/code/cxfar.py": "316cbf7d7c777e1fbe8a5d5fb249f0970b591330f4c2769c6827965a0e9c1adf", + "pr378-complex-screen/package/code/cxfinal.py": "7b2afb0be9591c72d31d7fbcce4e2d45bbe09daf7caa21123bca050b92cd2882", + "pr378-complex-screen/package/code/cxkernel.py": "8fc2a43e70fa8c1ce3f3025c9568b562accc5cf25b2ed53d7c0a1cbf954a0599", + "pr378-complex-screen/package/code/cxop.py": "2655e1e9ec94fb39512329ec86d261959ccd7c635c7535238f254a82861c2db1", + "pr378-complex-screen/package/code/cxpiece.py": "1c78b3025203c802c3aab9cc4113c48a7357d582f5bc75c47bde7953787f2e82", + "pr378-complex-screen/package/code/cxretime.py": "e7e06595c12fbafb707a6846719c54b85e0c2bb105927e7e7ee20f028a37438b", + "pr378-complex-screen/package/code/cxsplit.py": "9f6c0718f371120b015733983b3c91285a3825d306b557f0b9013059c6c88b0e", + "pr378-complex-screen/package/code/e8core.py": "1cb286196c1530d06f50f0997febc5993b388f33464e295611b920ba30a24eeb", + "pr378-complex-screen/package/code/kappa.py": "bd2c7d5bf546babf4700de802f9f49b45e8da0b3e75edcb4a5dfed914d186c6e", + "pr378-complex-screen/package/code/layout_bk.py": "e650d16538db8d80495fda5109cdfa0775e1d5f3b56b0aa39e5c1efc660877e7", + "pr378-complex-screen/package/code/engines/base_two_moment.py": "aee70c242a2f1d225528fabe2002e1564d1dc884797c07d28a831c7878ee9098", + "pr378-complex-screen/package/code/engines/moment.py": "81cbc864e106418fc7854322746f72180cb8110ff39f74450a3b8d55a82c1482", + "pr378-complex-screen/package/code/engines/outer.py": "c1ebb52163a7219504c728a5c2b098bf1e50bf20148a2879c5a74c3cadc7c03c", + "pr378-complex-screen/package/complex/gcert1-e8-r783.json.gz": "4b92f00fc7454b9b15e6d71a3b05062792eacca0a0ca4efee46f87827d57c8aa", + "pr378-complex-screen/package/complex/LICENSE-wht-power-saving-lean": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4", + "pr378-complex-screen/package/complex/NOTICE-wht-power-saving-lean": "557c9ad4660eebd14a00583736c4d12d2c45f3fc9bc148845f9f3efec72c9434", + "pr378-complex-screen/package/complex/gx/gx.py": "6f3dc8bb639933227a8dae181ec4a542e85c7276be9c9e330f49518e7b630b95", + "pr378-complex-screen/package/complex/gx/gxcore.py": "eb972c06fe8c322db2d9a8d9a7d05596e8f40c4ca8e5f42eb6df3c7361b5d517", + "pr378-complex-screen/package/data/gcert1-e8-r783-far.json.gz": "f2664ee7bcdfb55893abe9f1be8ee6a394a602e8262e611de2a0328bbd508aa7", + "pr378-complex-screen/package/data/bit/bitE8-r865.json.gz": "1fb726ea3818fe0837cceb0dd22a71a0814f064e5e781628104610d6468e0e55", + "pr378-donor-screen/AMBIENT-GAUGE-INTEGRATION.txt": "b05847fd8442d31bb994bf55e629359e427369b9b10828dfcdf31cdfb4094907", + "pr378-donor-screen/ambient-phase-audit.json": "8b025f01ef61d8de9c38a8be3290d7f196526affb91ebfb3b31249398e9a4797", + "pr378-donor-screen/assemble_signed25.py": "40bd945737ae69e7a9ed2a2f771d37f58b816ae42ca5f3b62b92c460459c0bac", + "pr378-donor-screen/audit_complete_schedule.py": "93a00897ba027691fbad1bcb1b11b3eca4e6ec964f019d3d4dc7ef3e0cad068e", + "pr378-donor-screen/audit_signed25_gauge.py": "0f9f2c691b2d6c9ecb18309877cd7d04b2dacf73c7416a97842b1aa41098252a", + "pr378-donor-screen/audit_signed25_global.py": "ab23a746ca2152136bf575c7580e09efb4f5eec864092d7739649f20011a7366", + "pr378-donor-screen/best-bank-geometry.json": "ddea7f168542f53e78c232e9c3aaff948cc9a5487fc9e39a429f460cff9f63af", + "pr378-donor-screen/best-bank-owners.json.gz": "a84087ce80057d8444e5df5b09ac5c956cbe7eb1af246bdd5bd7629599582868", + "pr378-donor-screen/best-candidate.json.gz": "f500b3cfef110da89d2c69c6402bd12580edad58d115fc154c628bb1e32f3f35", + "pr378-donor-screen/best-local-audit.json": "92367eda1d9375e32e47f9f238f6fa4fc7a0f2b04a59e4aaebf3e7c4ca89a7b5", + "pr378-donor-screen/bound-schedule-audit.json": "08048a3bbcfc1b15a729c5e2d824d6f44513b15e24e8e545be438c306a8c7ade", + "pr378-donor-screen/check_ambient_phase.py": "3de061ad6cf0720a49bb5cbf304477ca4f9356afaf3d5ef8161b616ea3fe90c8", + "pr378-donor-screen/check_signed25_composition.py": "ae1756fc65f3a1f5e5cc56111f991b95126b7456def829cb4ec7b23f7d1f13f1", + "pr378-donor-screen/check_signed25_gauge_lift.py": "5b66fc89126f77e33fb3049f02025ad491379b90cdf4ef2045c7ca0b0022c183", + "pr378-donor-screen/emit_signed25_gauge.py": "4e77cf87a3ff2b2ae7106e16d381d980905c43782e17e68361ffb4450f39eed3", + "pr378-donor-screen/integrate_signed25.py": "d50123cdac30d95fbb7ef9062ead952f22ac233c693f899efb942aa9b6dd96a6", + "pr378-donor-screen/LOCAL-GAUGE-LIFT.txt": "0c1a5c86c66d98f1c9e26d7397725485c7670bbe784a8fbae7d7d17aaf4e5eff", + "pr378-donor-screen/prefix-donor-candidate.json.gz": "8ed8a842bc529766a5a184f92551c1ab2f673590809a0a5cbe973248ef850146", + "pr378-donor-screen/prefix-gauge-bound-template.json.gz": "fdff8b210d8b0a79a82af1c4b40a381fbf135b8fc5702774908cd6526bd91334", + "pr378-donor-screen/prefix-gauge-routes.json.gz": "d01d19fdec03bec798b0c3846129257284a2b76be32c3cf3a15845113b03301c", + "pr378-donor-screen/refine_candidate.py": "85df5a85b5a1e94e67f0e59cc184e5dd91cb75ca3fad8132d2f23a9bf798361b", + "pr378-donor-screen/pr395-small/construct.py": "2b49d8b1f24f6e642d3cc81142a3ad8dfacead60280dc0df0a1326daa97acc0b", + "pr378-donor-screen/pr395-small/EXPECTED-COARSE.json": "cd8c5c5dc5b1755e75e92c5b139eb135d90c8d64f881244a8a60a9cf1e269bf0", + "pr378-donor-screen/pr395-small/EXPECTED-DISCOVERY.json": "ae4faa0723dbacb5d5775795f39b63c761ff9ddaf057a39edcc6861391c31703", + "pr378-donor-screen/pr395-small/EXPECTED-PROFILE.json": "fc5c4e5d816925f988dabb73ccaba390e358ce74c11d09385638ea364677ff16", + "pr378-donor-screen/pr395-small/EXPECTED-WITNESS.json": "3e0045b20080d2ef26ea6712894582f0001b3f34bf48ec9e9630cd47da3d9463", + "pr378-donor-screen/pr395-small/MANIFEST.json": "c7007c108391a740004d26fcb17087ad601626be6e1b053a96084c1d7d837f6d", + "pr378-donor-screen/pr395-small/pins.json": "63502072ab6b57220f524a7369f45b42afa520de8d07511cd8754f5cc783fcc1", + "pr378-donor-screen/pr395-small/PROOF.md": "6cf334083e56f539e691e5aaf917af01e207ccc0fbe5fc8c03031452fd8d0383", + "pr378-donor-screen/pr395-small/README.md": "35516c41118ed9c41cf167962bb56abc48b32e27fe1b8f01a1f9b90fe84bb32a", + "pr378-donor-screen/pr395-small/SELECTION.json": "fe2a1d44cb88f4b04c91a0d95959d2506937c1483e432a04e2c11f83b1b40b21", + "pr378-donor-screen/pr395-small/SOURCE.json": "8b95bd929bd9e679e5bcd337f4a6b2baee7b65319ae34f4914e83f91d17b51eb", + "pr378-donor-screen/pr395-small/verify.py": "2595011da4e55ccab4405205a55718fbfb9a2efecc1d0dafd1a762952e2d8e8a", + "pr386-phase-screen/fresh/COMBINED.json": "b0e6028d42037f106d81dc2c7ea9c826d5a959db429b799e4730b5f56bbb4bdf" +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/README.txt b/research/e8-signed-donor-gauge/README.txt new file mode 100644 index 0000000000..ec97c06596 --- /dev/null +++ b/research/e8-signed-donor-gauge/README.txt @@ -0,0 +1,4 @@ +Signed25 prefix plus nine exterior donor gauges: standalone changed-candidate replay. +Run Python3.11+ -B verify.py /fresh/SSD/output with existing SymPy available for inherited exact Clifford code. No installs are performed. Inputs are immutable; do not edit hardlinked files. +Credits: Jacob Sussman gx/E8, PR378 far retiming, Dugongue PR390 prefix construction, Rohan Arun PR395 signed extension, PR377 compressed cover, original PR370 and checked PR386 bit, PR315 rational engines. Original notices and licenses included in vendored package. New donor relations/normalization/banks and audits from this research task. All inherited conditional interfaces retained. +The verifier freshly executes changed complex reconstruction, scalar/gauge, emission, phases, finite binding, independent global schedule/ambient audit and exact assembly. It explicitly reuses baseline proofs/receipts and checked bit386 rather than falsely claiming a new full baseline run. diff --git a/research/e8-signed-donor-gauge/SOURCE.json b/research/e8-signed-donor-gauge/SOURCE.json new file mode 100644 index 0000000000..883cdf7e61 --- /dev/null +++ b/research/e8-signed-donor-gauge/SOURCE.json @@ -0,0 +1,6 @@ +{ + "pr395_head": "dcebad83e4d7e6a5643ba8edfb432b0ba0dd1826", + "pr390_head": "0e790f2dfb64e17bdee154aee151bb0c1dddb28e", + "pr386_head": "dd11cf8069554f0333afde398f12a56c3a7c29dd", + "scope": "Independent finite donor gauge and native compressed banking composition. Fresh changed-complex replay; original386 bit and unchanged source proofs retained, not freshly replayed here. No Lean/unconditional theorem or ready claim." +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/base_two_moment.py b/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/base_two_moment.py new file mode 100644 index 0000000000..14a90fa0e7 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/base_two_moment.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +"""Maintainer arithmetic cross-check of the pinned PR39 certificate. + +Uses no producer/checker imports. Counts are inputs, not proved by this script. +80-term rational logarithms and 12-term exponentials independently enclose +the two moments. The accompanying written review addresses their realization. +""" +import argparse +from fractions import Fraction as Q +from hashlib import sha256 +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +GRID = 10**30 + + +def require(condition, message): + if not condition: + raise ValueError(message) + + +def log_unit(x): + require(1 <= x <= 2, "logarithm range") + z = (x-1)/(x+1) + lo = 2*sum((z**(2*j+1)/(2*j+1) for j in range(80)), Q(0)) + return lo, lo+2*z**161/(161*(1-z*z)) + + +def log_bounds(x): + k = 0 + while x > 2: + x /= 2 + k += 1 + lo, hi = log_unit(x) + l2, u2 = log_unit(Q(2)) + lo, hi = lo+k*l2, hi+k*u2 + # Outward rational rounding keeps later certificates compact. + return Q((lo*GRID).__floor__(), GRID), Q((hi*GRID).__ceil__(), GRID) + + +def exp_bounds(x): + require(0 <= x < 1, "exponential range") + term = total = Q(1) + for j in range(1, 13): + term *= x/j + total += term + tail = term*x/13/(1-x/14) + return total, total+tail + + +def moment(m, W, entries, saving): + lo = hi = Q(0) + for t, count in entries: + t, count = int(t), int(count) + require(0 < t < m and count > 0, "improper child") + l, u = log_bounds(Q(m, t)) + lower = exp_bounds(saving*l)[0] + upper = exp_bounds(saving*u)[1] + lo += Q(t*count, m*W)*lower + hi += Q(t*count, m*W)*upper + return Q((lo*GRID).__floor__(), GRID), Q((hi*GRID).__ceil__(), GRID) + diff --git a/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/moment.py b/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/moment.py new file mode 100644 index 0000000000..7d697cb452 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/moment.py @@ -0,0 +1,113 @@ +"""Independent prospective ordinary five-stage cost, never supplier admission. + +Consumes a raw one-invocation ledger made from the actual source/internal/target +paths. No packed profile is used as an input. Missing physical/finite/compiler +obligations must remain explicit in the accompanying report. +""" +from collections import Counter +from decimal import Decimal, localcontext, ROUND_FLOOR +from fractions import Fraction as F +from functools import lru_cache +from math import factorial +import hashlib, json, sys +from pathlib import Path + +DYAD = 1 << 224 + +def floor(x): return F(x.numerator*DYAD//x.denominator, DYAD) +def ceil(x): return -floor(-x) + +@lru_cache(None) +def logarithm(x): + """Mercator bounds after binary reduction; ln(2) via two Mercator sums. + + For 1 <= y < 2, log(y) is an alternating series in z=y-1. + We instead reduce to 1 <= y < 3/2, and bound log(3/2) and + log(2) by the same alternating series at z=1/2 and z=1/3, + using log(2)=log(3/2)+log(4/3). All sums are exact rationals. + """ + assert x >= 1 + k = 0 + while x >= 2: x /= 2; k += 1 + j = int(x >= F(3, 2)) + if j: x /= F(3, 2) + def mercator(y): + z=y-1 + assert 0 <= z <= F(1,2) + # An even partial sum is below log; the next term bounds its tail. + t=z; s=F(0) + for n in range(1, 225): + s += (t if n & 1 else -t)/n + t *= z + return s, s+t/225 + a,b=mercator(x); c,d=mercator(F(3,2)); e,f=mercator(F(4,3)) + return floor(a+(k+j)*c+k*e), ceil(b+(k+j)*d+k*f) + +def exponential(l,u): + assert 0 <= l <= u < F(1,10) + def poly(x): + s=t=F(1) + for j in range(1,25): t=t*x/j; s+=t + return s,t + lo,_=poly(l);hi,last=poly(u) + return floor(lo),ceil(hi+last*u/25/(1-u/26)) + +def moment(H,m,W,a,bad=False): + lo=hi=F(0) + for r,n in H.items(): + assert 0 < r < m and n > 0 + l,u=logarithm(F(m,r)); e,f=exponential(a*l,a*u) + p=F(r*n,m*W);lo+=p*e;hi+=p*f + if bad: + # Existing envelope shape, only conditionally portable to the new cover. + l,u=logarithm(F(m));e,f=exponential(a*l,a*u) + p=F(32*m*sum(H.values()),10**16*W) + lo+=p*e;hi+=p*f + return floor(lo),ceil(hi) + +def decimal(x): + with localcontext() as c: + c.prec=70 + return str(Decimal(x.numerator)/Decimal(x.denominator)) + +def certify(H,m,W,bad=False): + with localcontext() as c: + c.prec=70 + terms=[(Decimal(r*n)/Decimal(m*W),(Decimal(m)/Decimal(r)).ln()) for r,n in H.items()] + fallback=Decimal(32*m*sum(H.values()))/Decimal(10**16*W) if bad else Decimal(0) + lm=Decimal(m).ln();lo=Decimal(0);hi=Decimal('.003') + for _ in range(210): + a=(lo+hi)/2 + if sum(p*(a*l).exp() for p,l in terms)+fallback*(a*lm).exp()<1:lo=a + else:hi=a + q=int(((lo+hi)/2*10**24).to_integral_value(rounding=ROUND_FLOOR)) + lo=F(q,10**24);hi=lo+F(1,10**24) + lv=moment(H,m,W,lo,bad);hv=moment(H,m,W,hi,bad) + assert lv[1]<10 for v in slacks.values()),{k:str(v) for k,v in slacks.items() if v<=0} + assert min(margins.values())==minimum + assert margins['balanced_prefix']-minimum==eta and 1-eps-r==eta/2 + assert 1-eps*(1+c)==eta-eps*eta/4 + return dict(parameters=dict(a_bit=a,a_complex=b,tau=tau,sigma=sigma, + eta=eta,beta=beta,q=q,c=c,epsilon=eps,lambda_=lam, + lambda_prime=lp,alpha_squared_power=r,delta=delta, + C0=bridge['semantic']['C0'],C1=1,kappa=kappa), + strict_constraints=slacks,margins=margins,minimum_margin=minimum, + absorption_gap=minimum-kappa, + recurrence=dict(internal=internal,leaf=leaf,reservations=1-c)) diff --git a/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/prime_witnesses.py b/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/prime_witnesses.py new file mode 100644 index 0000000000..7f16d93030 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr370-e8-screen/code/pricing/prime_witnesses.py @@ -0,0 +1,99 @@ +"""Exact finite prime exclusions for the selected new rational bit frames. + +For integer basis B and G=I-J/9, det(9 B G B^t) is a nonzero integer. +Excluding its prime divisors and 2,3,5 makes the reduced frame nondegenerate +over every odd local ring Z/q^w. Projector denominators divide this determinant +times fixed powers of 3. Retained frames retain their old exclusion witnesses. +The selected q is an arbitrarily large fixed prime chosen after this finite +set; this is not verification at a preselected numeric q. +""" +from pathlib import Path +import argparse,gzip,hashlib,json,sys + +HERE=Path(__file__).resolve().parent + +def det(A): + A=[list(r) for r in A];n=len(A) + if not n:return 1 + sign=1;previous=1 + for k in range(n-1): + pivot=next((i for i in range(k,n) if A[i][k]),None) + if pivot is None:return 0 + if pivot!=k:A[k],A[pivot]=A[pivot],A[k];sign=-sign + p=A[k][k] + for i in range(k+1,n): + for j in range(k+1,n): + v=A[i][j]*p-A[i][k]*A[k][j] + assert v%previous==0 + A[i][j]=v//previous + A[i][k]=0 + previous=p + return sign*A[-1][-1] + +PRIMES=(2,3,5,7,11,13,17,19,23,29,31) + +def factor_witness(determinant): + assert type(determinant) is int and determinant != 0 + residual=abs(determinant);powers={} + for prime in PRIMES: + power=0 + while residual%prime==0:residual//=prime;power+=1 + powers[str(prime)]=power + validate_factor(determinant,powers,residual) + return powers,residual + +def validate_factor(determinant,powers,residual): + assert type(determinant) is int and determinant != 0 + assert set(powers)==set(map(str,PRIMES)) + assert all(type(x) is int and x>=0 for x in powers.values()) + assert type(residual) is int and 0= 1 at block0 + qS(F0..F(t-2)), leaves at + qS(F(t-1)); stage 0: {l} -> block0 + Y enters stage t >= 1 at block0 - l + qS(F0..F(t-2)), leaves at + qS(F(t-1)); stage 0: {} -> block0 - l + X ends at every coordinate, Y at every coordinate but (block0, l). +check(k, h) verifies: every climb nested; every gate between roles at equal frames; every invocation entered at its +stage frame; final frames; each data role makes m - 1 moves; the exchange identity X_i = -y_i, Y_i = x_i (sympy). +It returns the idle climbs (moves of data roles outside invocations) per class, as blocks.""" +import itertools + +def qS(blocks, h, l=0): + return frozenset((c, j) for c in blocks for j in range(h) if j != l) + +def check(k, h, l=0, split=None): + s = 2 * k + 1; m = s * h + B0 = frozenset(('b0', j) for j in range(h)) + F = ['F%d' % i for i in range(s - 1)] + allc = B0 | frozenset((c, j) for c in F for j in range(h)) + assert len(allc) == m + def stage_in(t, role): + if t == 0: return frozenset([('b0', l)]) if role == 'X' else frozenset() + base = B0 if role == 'X' else B0 - {('b0', l)} + return base | qS(F[:t - 1], h, l) + def stage_out(t, role): + if t == 0: return B0 if role == 'X' else B0 - {('b0', l)} + return stage_in(t, role) | qS([F[t - 1]], h, l) + final = {'X': allc, 'Y': allc - {('b0', l)}} + stages = [(0, 'F', 1), (1, 'B', 1), (2, 'F', 1)] + [x for p in range(2, k + 1) for x in ((2 * p - 1, 'B', p), (2 * p, 'F', p))] + cur = {(r, p): stage_in(0, r) for p in range(1, k + 1) for r in 'XY'} + inv_moves = {key: 0 for key in cur}; idle = {key: [] for key in cur}; log = [] + def climb(key, new, idle_flag): + old = cur[key] + assert old <= new, ('not nested', key, len(old), len(new)) + if new != old: + if idle_flag: idle[key].append(len(new) - len(old)) + else: inv_moves[key] += len(new) - len(old) + cur[key] = new + def gate(dst, src, sign): + assert cur[dst] == cur[src], ('gate at unequal frames', dst, src) + log.append(('G', dst, src, sign)) + for t, kind, p in stages: + for r in 'XY': + climb((r, p), stage_in(t, r), True) # pair p reaches its stage frame (idle climb if needed) + climb((r, p), stage_out(t, r), False) # the invocation + log.append((kind, p)) + # twin gates of pairs (q-1, q) after stages 2q-3 and 2q-2 + for q in range(2, k + 1): + if t == 2 * q - 3: + for r in 'XY': climb((r, q), cur[(r, q - 1)], True) + gate(('X', q - 1), ('X', q), 1); gate(('Y', q), ('Y', q - 1), -1) + if t == 2 * q - 2: + for r in 'XY': climb((r, q), cur[(r, q - 1)], True) + gate(('Y', q), ('Y', q - 1), 1); gate(('X', q - 1), ('X', q), -1) + for key in cur: climb(key, final[key[0]], True) + for q in range(k, 1, -1): + gate(('Y', q - 1), ('Y', q), -1); gate(('X', q), ('X', q - 1), 1) + for key in cur: + assert inv_moves[key] + sum(idle[key]) == m - 1, (key, inv_moves[key], idle[key]) + # exchange identity (Sussman's abstraction: forward Y += X, backward X -= Y, gates are +-1 additions) + import sympy as sp + S = {} + for p in range(1, k + 1): + S[('X', p)] = sp.Symbol('x%d' % p); S[('Y', p)] = sp.Symbol('y%d' % p) + for op in log: + if op[0] == 'F': S[('Y', op[1])] = sp.expand(S[('Y', op[1])] + S[('X', op[1])]) + elif op[0] == 'B': S[('X', op[1])] = sp.expand(S[('X', op[1])] - S[('Y', op[1])]) + else: S[op[1]] = sp.expand(S[op[1]] + op[3] * S[op[2]]) + for p in range(1, k + 1): + assert S[('X', p)] == -sp.Symbol('y%d' % p) and S[('Y', p)] == sp.Symbol('x%d' % p), (p, S[('X', p)], S[('Y', p)]) + # idle blocks per class: X and Y of every pair have equal idle ranks + for p in range(1, k + 1): assert idle[('X', p)] == idle[('Y', p)], (p, idle[('X', p)], idle[('Y', p)]) + blocks = [r for p in range(1, k + 1) for r in idle[('X', p)]] + if split: + out = [] + for r in blocks: + while r > split: out.append(split); r -= split + if r: out.append(r) + blocks = out + return dict(stages=s, m=m, blocks_per_role_pair=blocks, gates=sum(1 for x in log if x[0] == 'G'), + invocations=sum(1 for x in log if x[0] in 'FB'), per_pair_idle={p: idle[('X', p)] for p in range(1, k + 1)}) + +if __name__ == '__main__': + import sys + h = int(sys.argv[1]) if len(sys.argv) > 1 else 9 + for k in (1, 2, 3, 4): + if k == 1: + continue + r = check(k, h) + print('k=%d stages=%d m=%d invocations=%d twin gates=%d idle per pair %s (sum %d per role pair)' % ( + k, r['stages'], r['m'], r['invocations'], r['gates'], r['per_pair_idle'], sum(r['blocks_per_role_pair']))) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_basis.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_basis.py new file mode 100644 index 0000000000..8c400798a5 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/code/complex_basis.py @@ -0,0 +1,35 @@ +"""Portable pure functions extracted from the reviewed complex checks; no historical receipt readers.""" +from collections import Counter +from copy import deepcopy +from fractions import Fraction +Q=Fraction +from hashlib import sha256 +from pathlib import Path +from math import prod +import gzip,json,sys + +def need(b, why): + if not b: raise ValueError(why) + +def gl_count_test(): + # Exhaustively test a literal binary Gaussian-elimination implementation + # through m=4. Row swaps cost three selected-bit additions. + out=[] + for m in range(1,5): + good=mx=0 + for word in range(1<<(m*m)): + rows=[(word>>(m*i))&((1<>k&1),None) + if p is None: break + if p!=k: rows[p],rows[k]=rows[k],rows[p];ops+=3 + for i in range(m): + if i!=k and rows[i]>>k&1: rows[i]^=rows[k];ops+=1 + else: + need(rows==[1<0, f"{where}: coefficient shape") + q=Fraction(a,b) + odd=q.denominator + while odd%2==0: + odd//=2 + need(odd in (1,3), f"{where}: literal coefficient outside dyadic/divisor-three grid") + return q + +def replay_label_counts(c): + """Full finite LABEL walk only. Never multiplies the 11,676-square scalar map.""" + need(c.get("format")=="gcert/1", "format") + need(all(c.get(k)==v for k,v in BASE.items()), "baseline parameter/count mismatch") + pin("cst",c.get("cst"),"baseline cst"); pin("N",c.get("N"),"baseline N") + h,v,R=c["h"],c["v"],c["R"]; n=2*v+R + need(c.get("ext")==[], "baseline has no exterior-gauged helper inputs") + frames=c["frames"]; dim=list(map(len,frames)) + pin("frames",len(frames),"baseline frame-table count") + need(frames[0]==[] and frames[1]==[1<piv[i+1] for i in range(len(piv)-1)), "frame pivot order") + need(all(not(b>>p&1) for i,b in enumerate(f) for j,p in enumerate(piv) if i!=j), + "frame is not reduced echelon") + ports=c["ports"] + need(len(ports)==v==len(set(ports)), "port count/uniqueness") + need(all(type(p) is int and 0=4 and g[0] in ("out","in"), where+": gate shape") + tag,f,pivot,terms=g[:4] + need(len(g)==(5 if tag=="out" else 4), where+": gate arity") + need(type(f) is int and 0<=f{tr}"]+=1 + totals[phase]["scalar_additions"]+=1 + if sr==tr=="y": + ybracket[(source,target)]+=q;ypiv.add(source);ytarget.add(target) + for r in regs: + climb(r,f,phase) + if phase=="A": + cut=cur.copy() + need(all(cur[v+t]==0 for t in range(v)), "scatter: Y role moved too early") + for k,r,f in c["ret"]: + need(type(r) is int and 2*v<=r0 else -1),clear(work)] + +def emit(c,ori): + """Construct the complete local parametric invocation, before cover routing. + One role stream is its full complete address rectangle. Frame labels denote + exact canonical representatives, never just rank or binary matrices. + """ + A=list(flat(c['A']));B=list(flat(c['B']));cur=c['start'].copy() + sc=scatter.table(c);rank=scatter.centre_ranks(c) + K=[] + for part in (A,None,B): + if part is None: + for t,p in enumerate(c['ports']): + for k,r,f in c['ret']: + if k in sc[t]:K.append(add(L(V+t),T(r),sc[t][k])) + else: + for t,s,q in part: + if role(s)=='X':continue + K.append(add(T(t) if role(t)=='S' else L(t),T(s),q)) + yield ('phase','old_response') + if ori=='forward': + for q in range(R):yield scal('old_response',copy(('T',q),L(2*V+q)),'old0') + for _,t,s,a,b in K:yield scal('old_response',add(t,s,Q(-a if t[0]=='L' else a,b)),'old0') + else: + for q in range(R):yield scal('old_response',clear(('T',q)),'old0') + for _,t,s,a,b in reversed(K):yield scal('old_response',add(s,t,Q(a,b)),'old0') + for q in range(R):yield scal('old_response',add(L(2*V+q),('T',q),Q(1)),'old0') + for q in range(R):yield scal('old_response',clear(('T',q)),'old0') + yield ('phase','ad0') + for r,f in enumerate(c['start']):yield ('adapter','old_to_new',r,f) + for part in ['A','centers','B','final']: + yield ('phase',part) + if part in ['A','B']: + for g in c[part]: + regs=[g[2]]+[x[0] for x in g[3]]+(g[4] if g[0]=='out' else []) + for r in regs: + if cur[r]!=g[1]: + old=cur[r];cur[r]=g[1] + yield ('climb',part,r,old,g[1],len(c['frames'][g[1]])-len(c['frames'][old])) + for t,s,q in flat([g]): + e=add(L(t),L(s),q) if ori=='forward' else add(L(s),L(t),-q) + yield scal('main',e,g[1]) + elif part=='centers': + for k,r,f in c['ret']: + yield scal('main',clear(C(k)),f if ori=='forward' else 0) + if ori=='forward':yield scal('main',add(C(k),L(r),Q(1)),f) + else: + for t,p in enumerate(c['ports']): + if k in sc[t]:yield scal('main',add(C(k),L(V+t),sc[t][k]),0) + yield ('center',k,f if ori=='forward' else 0,0 if ori=='forward' else f,rank[k]) + if ori=='forward': + for t,p in enumerate(c['ports']): + if k in sc[t]:yield scal('main',add(L(V+t),C(k),sc[t][k]),0) + else:yield scal('main',add(L(r),C(k),Q(-1)),f) + yield scal('main',clear(C(k)),0 if ori=='forward' else f) + else: + for r,f in enumerate(c['final']): + if cur[r]!=f: + old=cur[r];cur[r]=f + yield ('climb','final',r,old,f,len(c['frames'][f])-len(c['frames'][old])) + yield ('phase','adF') + for r,f in enumerate(c['final']):yield ('adapter','new_to_old',r,f) + yield ('phase','cleanup') + for t,s,q in reversed(A+B): + if role(t)=='Y':continue + e=add(L(t),L(s),-q) if ori=='forward' else add(L(s),L(t),q) + yield scal('cleanup',e,'old1') + yield ('phase','done') + +def contains(U,V): + for u in U: + for v in V: + if u>>(v.bit_length()-1)&1:u^=v + if u:return False + return True + +def validate(events,c,ori,manifest,bill): + rank=scatter.centre_ranks(c);nc=len(rank);need(nc<=H,'more retained totals than reserved centre slots') + phase=None;seen=[];cur=c['start'].copy();cent={};dirty=set();initialized=set() + climbed=Counter();hist=Counter();final_roles=Counter();afterB=None;projection=sha256();whole=sha256();counts=Counter();ad0=[];adF=[] + pairs=set();states={};all_frame_incidence=0;primitive=sha256();primitive_count=0 + for ev in events: + whole.update((json.dumps(ev,separators=(',',':'))+'\n').encode()) + tag=ev[0];counts[tag]+=1 + if tag=='phase': + if phase=='A':states['after_A']=digest(cur) + if phase=='B':states['after_B']=digest(cur);afterB=cur.copy() + if phase=='final':states['final']=digest(cur) + phase=ev[1];seen.append(phase) + need(seen==PHASES[:len(seen)],'strict old/A/copy/B/final/adapter/cleanup chronology') + if phase=='ad0':need(not dirty,'old-response tableau survived before label recursion') + if phase=='A':need(ad0==list(enumerate(c['start'])),'missing or reordered exact entry adapter') + if phase=='adF':need(cur==c['final'],'final climbs omitted before cleanup') + if phase=='cleanup':need(adF==list(enumerate(c['final'])),'missing or reordered exact final adapter') + continue + if tag=='adapter': + _,which,r,f=ev + if which=='old_to_new':need(phase=='ad0','entry adapter position');ad0.append((r,f)) + else:need(which=='new_to_old' and phase=='adF','final adapter position');adF.append((r,f)) + elif tag=='climb': + _,p,r,old,new,d=ev + need(phase==p and p in ['A','B','final'],'live child outside source label walk') + need(not dirty and not cent,'new work stock or center active during live child') + need(cur[r]==old and d==len(c['frames'][new])-len(c['frames'][old]) and d>0,'wrong exact child endpoints/rank') + pair=(old,new) + if pair not in pairs:need(contains(c['frames'][old],c['frames'][new]),'nonnested child');pairs.add(pair) + cur[r]=new;climbed[p]+=1;hist[d]+=1 + if p=='final':final_roles[role(r)]+=1 + elif tag=='center': + _,k,old,new,d=ev + need(phase=='centers' and not dirty and set(cent)=={k},'center child ownership') + need(cent[k]==old and (k,c['ret'][k][1],c['ret'][k][2])==tuple(c['ret'][k]),'center input frame') + f=c['ret'][k][2] + need((old,new,d)==((f,0,rank[k]) if ori=='forward' else (0,f,rank[k])),'center child direction/rank') + cent[k]=new;hist[d]+=1 + projection.update((json.dumps(('main',('recursive_center',k,d)),separators=(',',':'))+'\n').encode()) + elif tag=='scalar': + _,p,e,f=ev + need(p==('main' if phase in ['A','centers','B'] else phase),'scalar phase binding') + need(e[0] in ['add','copy','clear'],'unpaid scalar operation') + target=e[1];source=e[2] if e[0] in ['add','copy'] else None + for x in [target]+([source] if source else []): + bank,r=x + if bank=='T':need(phase=='old_response' and 0<=r> k & 1 else sout) for k in range(c["h"])] + + +def table(c): + """{t: {k: coefficient}} for every target; a total a target does not read is absent.""" + out = {} + for t in range(c["v"]): + r = row(c, t) + ks = [k for k, _ in r] + if len(set(ks)) != len(ks): + raise ValueError("scatter row %d names a total twice" % t) + out[t] = dict(r) + return out + + +def centre_ranks(c): + """the rank of each retained total's frame, in total order 0..len(ret)-1""" + dim = [len(f) for f in c["frames"]] + return [dim[f] for _, _, f in sorted(c["ret"])] diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/derived-pins.json b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/derived-pins.json new file mode 100644 index 0000000000..2e4949fb12 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/derived-pins.json @@ -0,0 +1,32 @@ +{ + "frames": 948, + "gates": [ + 775, + 1220 + ], + "label_histogram": { + "1": 2093, + "2": 598, + "3": 522, + "4": 141, + "5": 209, + "6": 335, + "7": 43, + "8": 24, + "9": 8 + }, + "ledger": [ + 29971, + 94473, + 216, + 31 + ], + "climbed": { + "A": 1237, + "B": 1953, + "final": 775 + }, + "climb_forward": 3965, + "climb_backward": 3965, + "local_bill": 2271769336984 +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/LICENSE b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/NOTICE b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/NOTICE new file mode 100644 index 0000000000..63aa295646 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/NOTICE @@ -0,0 +1,290 @@ +Walsh-Hadamard power saving (wht-power-saving-lean) +Copyright 2026 Jacob Sussman + +Repository: https://github.com/jacobalansussman/wht-power-saving-lean + +This repository is not a project of OpenAI. OpenAI did not write, review or +endorse it. The package name "OAI" and the namespace "OAI.PowerSaving" are +those of openai/math and are kept only because the new files extend that +development. + +This repository is not a project of CrocSwap/integer-mult-bounds either. Its +authors did not write, review or endorse it. Section 6 says what is taken +from their repository. + +This repository contains files from, and files derived from, the repository +"openai/math" (https://github.com/openai/math), family 130, "Exact Fourier +transforms below n log n", at commit fd4aeeb2ee4fc729c18d98444fed42fd0529eeeb. +That repository is published under the Apache License, Version 2.0. A copy of +the licence is in the file LICENSE. The upstream repository has no NOTICE file +and its licence text names no copyright holder; the files are attributed here +to the authors of openai/math (OpenAI). + +1. Unmodified upstream files. + The 89 files under OAI/Computability/ are byte-for-byte copies of the files + with the same paths under lean/ in openai/math at the commit above. They + have not been changed. Modified copies of some of them are under + Work/Fourier/ and are listed in section 7. + One more file of openai/math is here unchanged, outside the Lean build: + third-party/openai-math/lean/ComparatorChallenges/UniformFourier.lean is a + byte-for-byte copy of lean/ComparatorChallenges/UniformFourier.lean at the + commit above (the statement of OpenAI's Fourier challenge). It is included + so that the modified copy named in section 2 can be compared with it. + +2. Files that contain upstream text. + - Work/CarrierCheck/ChallengeB2Ke16x.lean, + Work/CarrierCheck/ChallengeB2Ke16xR.lean, + Work/GCert/Data/ChallengeB2Gp193x.lean and the text template + tools/gen/templates/ChallengeB2L16x.lean.txt each contain, as their + lines 22-270, lines 9-257 of + lean/ComparatorChallenges/UniformFourier.lean of openai/math (the RAM cost + model), unchanged. Everything else in these files was written for this + repository. + - Work/Fourier/UniformFourierChallenge.lean is a modified copy of + lean/ComparatorChallenges/UniformFourier.lean of openai/math (the + statement of OpenAI's Fourier challenge, 336 lines). Changes: a comment + was added at the top; the exponent 1 - 1/(10^(13:ℕ)) was replaced by + 1 - 7474546/(10^(10:ℕ)); seven names received the suffix "Z" + (decimalExponent, decimalTime, TimeBounds, DFTGoal, ConvGoal, + transform_main, convolution_main). Everything else in the file is the + upstream text, unchanged. See section 7. + - Work/Scratch/Engine.lean and Work/Block/Engine.lean contain copies of + proofs of openai/math, changed for this repository: sections 1, 2 and 5 + of Work/Scratch/Engine.lean are upstream proofs with the batch layout + renamed, and both files contain a copy of the private upstream theorem + "hills_project" (lean/OAI/Computability/FourierTransform/ + TensorProgram.lean) with its envelope generalised. The comments in the + two files mark these places. + - lakefile.lean is adapted from lean/lakefile.lean of openai/math: the same + package name, toolchain, package option and Mathlib pin; every other + dependency was removed and the libraries of this repository were added. + lean-toolchain is a byte-for-byte copy of lean/lean-toolchain. + lake-manifest.json lists Mathlib and its dependencies at the revisions of + lean/lake-manifest.json. + - RELATED-WORK.md reproduces the BibTeX entries of two manuscripts of + openai/math. + +3. New files that build on upstream proofs. + The other files under WHTCheck/ and Work/ were written for this + repository. They import the upstream files, and several of them generalise + or adapt proofs of upstream files (for example Work/Block/Recursion.lean, + which says so in its header). They are changes and additions made for this + repository and are not part of openai/math. + +4. How the new files were made. + Jacob Sussman made the new files on 2026-10-08 and 2026-10-09 by directing + a team of AI agents (Claude). The agents wrote the new Lean files, the + certificate data and the generator scripts. See README.md, section 4. + +5. Ideas taken from other public work. + The network of the first result uses ideas published by others, among them + the helper circuit "NStar3" (Swapnil-jain/integer-mult-kappa, which credits + CrocSwap pull request #36 and Paureel for parts of it), its transfer to + family 130 (shea256/fourier-transform-below-nlogn), and "carrier links" and + "whole-residual batching" (pull requests to CrocSwap/integer-mult-bounds). + No file of Swapnil-jain/integer-mult-kappa or of + shea256/fourier-transform-below-nlogn is included here. One comment in + Work/Scratch/Engine.lean quotes three counts reported in + Swapnil-jain/integer-mult-kappa and names that source. The general frame + lemma that Work/GFrame proves is stated in + notes/general-clifford-frames.tex of CrocSwap/integer-mult-bounds; its Lean + proof was written for this repository. The credits, with links, are in + RELATED-WORK.md. + +6. Data derived from CrocSwap/integer-mult-bounds (second result). + The helper circuit of the second result is the paired-cube circuit of the + repository "CrocSwap/integer-mult-bounds" + (https://github.com/CrocSwap/integer-mult-bounds), in the state of its pull + request #193. It is the design of that community: icekylinx (pull requests + #144 and #184), eumemic (#168, and #117 behind its modules), ikeboy / + Avi Eisenberg (#191 and #193), with an664 (#128) credited there for the + workspace-sharing principle. That repository is published under the Apache + License, Version 2.0 (the same licence text as the file LICENSE). Its + NOTICE file begins "A sharper exponent for integer multiplication / + Copyright 2026 Douglas Colkitt" and says that the community release "is + not solely Douglas Colkitt's work". A complete copy of that NOTICE file, as + it is at the head of pull request #193, is in + third-party/CrocSwap-integer-mult-bounds/NOTICE. + + The data were taken from these files of that repository. They were loaded + as data by programs written for this repository; no program of that + repository was run, and none is included here. + - at the head of pull request #168 (eumemic), + 4a3c769e5c5430e7114c4d3e099ff34664677f17: + references/paired-cube/sources/local_L1.json + references/paired-cube/sources/tmod_TE_TD_TB3_1_1_4_full_6.0617964e-4.json + references/paired-cube/sources/pmod_J0_full_6.0666810e-4.json + references/paired-cube/sources/qmod_climb3u_best.json + references/paired-cube/selected-module/matching-arcs.json + references/paired-cube/physical/frames.json + - at the head of pull request #193 (ikeboy), + 187e1010ac8b259af8e9b5166f68b64bc27b4b47: + research/source-assisted-v4/data/physical-pairs.json + + Files of this repository that contain data derived from them: + tools/certificate/gcert1-p11-pr193.json.gz and the Lean data modules + generated from it, Work/GCert/Data/Gen/P193*.lean and the files they import + from Work/GCert/Data/Gen/P193/; its block counts are also in the generated + modules Work/GCert/Data/P193Price.lean, RateB2Gp193.lean, RateB2Gp193x.lean + and InstB2Gp193.lean. + Changes made: the circuit was rebuilt from those data as one explicit, + renumbered list of additions with a table of frames, in the certificate + format "gcert/1" of this repository; its 1,980 in-place steps were written + as pairs of additions with rescaled coefficients; the Lean data modules + were generated from that list. No file of that repository is included + unchanged, except the copy of its NOTICE file named above. + + Notices of that NOTICE file that pertain to these data, quoted: + + Paired-cube and shared-core extension, 9 October 2026 + Copyright 2026 icekylinx + + Source-assisted common-frame extension (2026-10-09) + Copyright 2026 icekylinx. Apache-2.0. + Substantial dependency: eumemic PR168, + fd25adb7fbaa12ee761d02c733c54d1d2a7687ee + + The full text of both notices, and the notices of the work they build on, + are in the copy named above. The credits, with links and with the words of + pull request #193 about its own sources, are in README.md ("Whose circuit + this is") and in RELATED-WORK.md, section 1. + +7. Modified copies of upstream files (third result). + The files listed below are copies of files of openai/math at the commit + above, changed for this repository. Each begins with a comment that names + the upstream file it is derived from and states what was changed. The + upstream originals under lean/OAI/Computability/ are in this repository + as well, unchanged (section 1), and the copies import them. The upstream + challenge file lean/ComparatorChallenges/UniformFourier.lean is in this + repository in both forms: unchanged under third-party/openai-math/ + (section 1) and modified (section 2). + + - Work/Fourier/ArbitraryLength.lean: modified copy of + lean/OAI/Computability/FourierTransform/ArbitraryLength.lean (224 + lines; 159 of them unchanged in the copy). Changes: identifiers renamed + on 64 lines (18 names: 15 with the suffix Z, 3 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/Asymptotics.lean: modified copy of + lean/OAI/Computability/FourierTransform/Asymptotics.lean (187 lines; + 112 of them unchanged in the copy). Changes: identifiers renamed on 74 + lines (32 names: 26 with the suffix Z, 6 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + - Work/Fourier/Axioms.lean: written for this repository (not a copy of an + upstream file). + - Work/Fourier/ConvolutionProgram.lean: modified copy of + lean/OAI/Computability/FourierTransform/ConvolutionProgram.lean (100 + lines; 77 of them unchanged in the copy). Changes: identifiers renamed + on 22 lines (10 names: 9 with the suffix Z, 1 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/Goal.lean: written for this repository; contains lines of + upstream files: of its 7 code lines, 6 are lines of + lean/OAI/Computability/FourierTransform/Goal.lean (original lines 35, + 75-77, 79, 81): unchanged: its lines 25; with identifiers renamed: its + lines 21, 24, 26, 28, 30. + - Work/Fourier/Main.lean: modified copy of + lean/OAI/Computability/FourierTransform/Main.lean (151 lines; 90 of + them unchanged in the copy). Changes: identifiers renamed on 59 lines + (40 names: 35 with the suffix Z, 5 with Z inserted); 1 import line + replaced by 2; 24 comment lines added; other code lines changed: 1 of + the original, 1 of the copy (copy line 59). + - Work/Fourier/Seam.lean: written for this repository; contains lines of + upstream files: of its 122 code lines, 15 are lines of + lean/OAI/Computability/FourierTransform/TensorProgram.lean (original + lines 36-37, 95-96): unchanged: its lines 93-94, 113-114, 141-142, + 163-164, 185-187, 194-196; with identifiers renamed: its lines 184; 3 + are lines of lean/OAI/Computability/FourierTransform/TensorSaving.lean + (original lines 83-84, 114): with identifiers renamed: its lines 45-46, + 59; 1 is a line of lean/OAI/Computability/FourierTransform/Main.lean + (original line 60): with identifiers renamed: its lines 213. + - Work/Fourier/SectorAlgorithm.lean: modified copy of + lean/OAI/Computability/FourierTransform/SectorAlgorithm.lean (224 + lines; 162 of them unchanged in the copy). Changes: identifiers renamed + on 61 lines (17 names: 13 with the suffix Z, 4 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/SynchronizedAlgorithm.lean: modified copy of + lean/OAI/Computability/FourierTransform/SynchronizedAlgorithm.lean (126 + lines; 94 of them unchanged in the copy). Changes: identifiers renamed + on 31 lines (12 names: 10 with the suffix Z, 1 with Z inserted, 1 + other), the other being "canopy" to "Grove.canopy" (5 lines); 1 import + line replaced by 1; 16 comment lines added; no other change to the + code. + - Work/Fourier/TransformProgram.lean: modified copy of + lean/OAI/Computability/FourierTransform/TransformProgram.lean (146 + lines; 94 of them unchanged in the copy). Changes: identifiers renamed + on 51 lines (21 names: 19 with the suffix Z, 2 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/UniformBounds.lean: modified copy of + lean/OAI/Computability/FourierTransform/UniformBounds.lean (183 lines; + 115 of them unchanged in the copy). Changes: identifiers renamed on 67 + lines (29 names: 25 with the suffix Z, 4 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + - Work/Fourier/UniformFourierChallenge.lean: modified copy of + lean/ComparatorChallenges/UniformFourier.lean (336 lines; 328 of them + unchanged in the copy). Changes: identifiers renamed on 7 lines (7 + names: 7 with the suffix Z); 12 comment lines added; other code lines + changed: 1 of the original, 1 of the copy (copy line 281). + - Work/Fourier/WorkingCompiler.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingCompiler.lean (153 + lines; 104 of them unchanged in the copy). Changes: identifiers renamed + on 48 lines (14 names: 14 with the suffix Z); 1 import line replaced by + 1; 15 comment lines added; no other change to the code. + - Work/Fourier/WorkingPreparation.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingPreparation.lean (212 + lines; 156 of them unchanged in the copy). Changes: identifiers renamed + on 55 lines (30 names: 28 with the suffix Z, 2 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/WorkingTransform.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingTransform.lean (119 + lines; 91 of them unchanged in the copy). Changes: identifiers renamed + on 27 lines (9 names: 8 with the suffix Z, 1 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + + Changes made to the eleven copied proof files: every declaration received + the letter "Z" in its name (as a suffix of its own name, or of the name + of the declaration it belongs to), so that it does not collide with the + upstream declaration of the same name; the upstream exponent "alpha" + (1 - 2/10^11) and the bound "hills" defined from it were replaced by + "alphaZ" (1 - 7474547/10^10) and "hillsZ", which are defined in + Work/Fourier/Seam.lean, and the single use of the upstream theorem + "hills_program" by "hillsZ_program"; the five definitions of the upstream + statement that contain its exponent (decimalExponent, decimalTime, + TimeBounds, DFTGoal, ConvGoal) were replaced by the versions of + Work/Fourier/Goal.lean, whose exponent is 1 - 7474546/(10^(10:ℕ)); + the import lines point to the copies; a header comment was added. + Two further changes: in the copy of Main.lean the same constant stands + once as the literal 2/10^11 and was replaced there too, and the two + final theorems of that copy received a documentation comment; in the + copy of SynchronizedAlgorithm.lean the name "canopy" was written out as + "Grove.canopy" in 5 places, because the short name is shadowed in the + larger environment of the copy. The script also renamed three names + inside upstream comments; the comments are otherwise the upstream ones + and describe the upstream network. + The proofs are those of openai/math. The copies were made by the script + tools/fourier/mkchain.py of this repository. + + Work/Fourier/Goal.lean contains copies of those five definitions of + lean/OAI/Computability/FourierTransform/Goal.lean, with the exponent + replaced and the suffix "Z" on the five names. + + Work/Fourier/Seam.lean was written for this repository. It repeats the + statement of the upstream theorem "hills_program" (TensorProgram.lean) and + the definition of "hills" (TensorSaving.lean) with the two names replaced; + its header says so. + + The work of others that the third result follows (danadran01, shea256, + eumemic) is credited in README.md ("Whose reduction this is") and in + RELATED-WORK.md, section 1. No file of their repositories is included + here. + +Not included in this repository and fetched by the build: Mathlib +(https://github.com/leanprover-community/mathlib4, Apache License 2.0) and its +dependencies. The comparator (https://github.com/leanprover/comparator) is a +separate tool and is not included. diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/FINITE_BRIDGE.txt b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/FINITE_BRIDGE.txt new file mode 100644 index 0000000000..c1a8843611 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/FINITE_BRIDGE.txt @@ -0,0 +1,141 @@ +FINITE ROUTER, ROW-STOCK, AND SEMANTIC BRIDGE FOR ROUND 13 + +Prepared for icekylinx by GPT-6 Astra, 9 October 2026. Apache-2.0. + +This bridge applies to a completed, physically proved round-13 profile. +It cannot make a numerically attractive but unconstructed profile valid. +The local source/target flags, controlled injections, old-response +subtraction, inverse cleanup, and retained alias boundaries are separate +construction obligations. assemble_profiles.py records their role as +proof dependencies and independently checks the exact arithmetic. + +1. The inherited uniform interfaces + +Retain the three completed-core cover of PR144/PR168 and all of its +analytic and fixed-tape assumptions. The complex cover is O(m,2), m<=72, +with order V<2^(m*m)<=2^5184. No new independent cover coordinates are +introduced by common-frame scalar lifts or source-controlled local +rewrites. Every stage still uses one completed invocation at each vertex. + +For a supplied profile with W0<10^7 roles per cover vertex, the full +physical stock W=V W0 is less than2^5208. Its total rank s is less +than mW<2^5215. The profile's actual proper-child maximum is retained; +the selected complex maximum must be less than m/2. The script checks +these inequalities rather than assuming that fewer auxiliary rows imply +a better contraction or a shorter recursion. + +The bit word uses the same weighted q-adic frame interface and the same +internally borrowed selectors as its pinned parent. New source controls +must use existing nondegenerate source-meeting planes or separately +certified new frames. All zero-rank adapters remain charged scalar work. +The group-size factor is not omitted and is not inserted into an external +polynomial row reserve. The inherited ordinary leaf saving is exactly +384599/10^10. The bad-row allowance is1/10^16; the charged fallback per +edge is32m^2. Its inequality2m^3/2^80<1/10^16 is checked explicitly. + +2. A deliberately loose finite scalar bound + +The pinned words and round-13 modifications are finite straight-line +programs with fewer than2^40 stored nodes, roles, coefficients, and +boundary entries. Scalar sum/difference lifts use actual invertible +matrices and are executed pointwise at common frame representatives. +For the selected dyadic rewrite, new elementary coefficients are +dyadic; the inherited center scatters retain their fixed odd divisor3. +No unrecorded new odd denominator may be included under this bridge. + +Fixed integer multipliers can be expanded into scalar doublings and +additions; dyadic divisions can be expanded into halvings. The explicit +low words and full-frame inverses are much smaller than2^4096 primitive +scalar/movement groups per invocation. Even constructing their fixed +old-response matrices by exact elimination is dominated by this bound: +matrix order is below2^40, original finite-word coefficient bit lengths +are below2^80, and the elementary elimination and coefficient expansion +bounds are below2^1024. No input-size-dependent dense elimination is +being performed. These are constants of the chosen finite construction. + +Consequently all3V invocation words, endpoint adapters, and finite role +bookkeeping fit within K<2^9300 logical groups. The retained universal +router is overcharged by a full W-role permutation for every group: + + 64 (m+1)^3 (K+1) (W+1)^2 < 2^20000. + +Choose the exact dominating scalar/router budget G=2^30000. This also +dominates the primitive arithmetic required to realize the fixed scalar +coefficients and source-controlled inverse cleanup. The router still +uses a fixed number of tapes, with sequential reuse of row stock. + +3. Explicit semantic constants + +Choose the exact integer E=2^100000 and put B=s+E. Then + + 2 G W^2 + 8s + 4W + 4 + 32m < 2^40500 < E, + E <= B < 2^100001. + +For the actual maximum child r= s+E >= 1. + +Choose C0=2^210000 and C1=1. These dominate both the retained semantic +requirement32m B^2 and2B+18. The reported strict_literal_gap=1 and +induction_gap_lower=1 are proved lower bounds on the positive actual +integer gaps; they are not claims that those gaps equal one. + +Use the inherited common dyadic grid with fixed3^(-K') exposure and +retain its precision/rounding contract. No child receives an independent +rounding allowance and no source-controlled injection is treated as an +unpaid numerical operation. + +4. External rows and stopping + +The complex child maximum below m/2 gives halving degree1, while +log2 W<5208<10000. Keep the deliberately conservative inherited bit +coarse reserve9909 and ordinary-leaf reserve252. Thus the external +row coefficient is bounded by + + A=10000+9909+252=20161. + +Choose degree D=1000000 and suffix slope4D. The exact row gap is + + D - (51/25)A > 0. + +The q-adic selector fields and source-control labels remain internally +borrowed and restored. Increasing these finite overcharges changes +constants and the all-size bridge, not the selected exponent saving. + +5. Exact supplier moments and balanced assembly + +For each actual histogram, assemble_profiles.py proves + + sum_r n_r r exp(a log(m/r))/(mW0) + bad_allowance < 1 + +using rational upper bounds, with upward rounding on the2^120 grid. +The bit atom stop is the first10^(-12) grid point above +a/(1+a-old), which implies both required strict toll inequalities. +Its effective saving is(1-beta)a+beta*old. This stopping rule is the +already reviewed PR158 edge rule, not a new local-word contribution. + +The final assembly uses the substantial PR168 balanced-prefix adapter, +with eta=10^(-8) and phase stop10^(-9), retaining all47 strict +constraints and all7 margins. The selected final kappa is rounded +down on the10^(-10) grid below the minimum complete margin. The +script checks every constraint exactly and reports whether the fixed +target0.0009218338 is reached. + +This is a conditional bound of the retained theorem form + + T(n)=O(n (log n)^(1-kappa)). + +The improvement ratio refers to kappa, the logarithmic exponent saving. +It is not a measurement of practical multiplication throughput. + +Credits + +The base supplier, scalar/frame verification, and actual profiles are +pinned to PR168 fd25adb7fbaa12ee761d02c733c54d1d2a7687ee, eumemic +(Anthropic Claude assistance), building on icekylinx's PR144. The +balanced prefix is RaD/hipotures; the semantic constraints are retained +from the reviewed PR23 line; completed-core sharing is credited to +an664 PR128; the atom-edge stop is credited to geckods PR158. Existing +source notices retain their more detailed upstream attributions. +The new source-controlled boundary construction, this conservative +bridge, and its integration are GPT-6 Astra's round-13 work. diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-layout.tex b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-layout.tex new file mode 100644 index 0000000000..16f4d23347 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/compact-control-layout.tex @@ -0,0 +1,118 @@ +\paragraph{Rows and complete compact fields.} +Let $m,W,s$ denote the complex network constants and keep the layer's global +$p,d,K$ at every node. Put +\[ + G=4\lceil\log_2p\rceil+6,\quad H=dG,\quad + q_F=\left\lceil\frac{2H}{K}\right\rceil,\quad + q_B=\left\lceil\frac{H}{K}\right\rceil, +\] +\[ + q_0=\lceil\log_2W\rceil\lceil\log_m(2d)\rceil, + \quad k_0=\lceil\log_m d\rceil,\quad Q_0=q_0+q_F+q_B. +\] +If $D\le Q_0$, apply all $D$ selected kernels individually. Otherwise, +process individually the first $q_0+q_F$ and last $q_B$ selected axes. +This uses existing coordinates only. The remaining active axes are a +consecutive middle block of length $D-Q_0$. + +Regard the first $q_0$ chunks as the row index. Immediately after it, the +next $q_F$ chunks have at least $2H$ bits. Reinterpret these consecutive +bits as two $H$-bit front fields and a spectator remainder; a remainder +of length zero is omitted. The last $q_B$ chunks similarly supply one +$H$-bit back field and a spectator remainder. These reinterpretations move +no records and preserve the total address space. For a call with $f$ axes +per slot, carve $nG=(f-1)G\le H$ consecutive bits from each of these +fields; collapse their unused bits into spectators. The resulting field +list has a fixed number of entries. Both front fields precede all active +slots and the back field follows them, so the compact-control proposition +applies to every ordered pair of slots. For $f=1$ no compact fields are used. + +The original row range has length $R_{\rm row}=2^{q_0K}\ge W^{k_0}$. +For each original prefix, pad this row range to the next multiple of +$W^{k_0}$ by adding zero rows. A row includes the entire complete front +fields, active middle block, back field, all spectator coordinates and +polynomial record suffix. Padding adds whole such rows, so increases total +volume by at most two and does not change any within-row range. + +At a node write the row index as $u=Wg+w$, $0\le w2r_j^{t_j}$ for largest children $r_b=529,r_c=756$. +At width $e$ reserve the product +$Q=W_c^{D_c(e)}W_b^{D_b(e)}$, with +$D_j(e)=t_j\lceil\log_2e\rceil$. Its coefficient is +$9\cdot28+20\cdot30=852$, and +\[ + 2000>\frac{51}{25}\,852. +\] +The sufficient stock is therefore $p^{2000}$, supplied by the retained +physically preceding transformed prefix and a single complete-row +padding. Nested bit stock is restored before another complex child. +Sequential copies introduce no independent row field. The supplementary +suffix condition $b_{\rm in}^{1-\epsilon}>8000(\log_2b_{\rm in}+8)$ +is eventual for fixed $\epsilon<1$. + +\subsection{Exact conditional assembly} +Use the analytic proof map in +\path{notes/structured-bulk-assembly.tex}: arbitrary-source routing +with active masking and paid repair scans; one rounded phase-cell +matrix with preserved period cuts and downward-weight error bounds; +persistent target halos, sequential overlap tapes and factor pages; +Baker--Harman--Pintz prime packing; and the retained exact-recovery +interface. Their full costs are unchanged. In particular the bulk +bound retains the terms +\[ + O\!\left(Tp\left[p^\tau\operatorname{polylog}p+ + d\operatorname{polylog}p+dp^\delta+w^2p^\delta+ + dw^2p^\delta/L\right]\right)+n^{o(1)}, +\] +with $L=2^{\lceil8\log_2p\rceil}$, +$w^2=O(p^{1-r})$, and normalization exponent requiring +$\epsilon+r<1$. These arguments, not a change of arithmetic model, +justify the seven margins below. + +\begin{theorem}[Conditional fixed-tape multiplication bound] +Under the retained analytic and fixed-tape interfaces of PR23/PR29 +and the preceding proof map, the selected copied-center networks give +\[ + T(n)=O\!\left(n(\log n)^{1-\kappa}\right),\qquad + \boxed{\kappa=\frac{384569}{10000000000}=3.84569\times10^{-5}}. +\] +\end{theorem} +\begin{proof} +Take the strict finite savings $a=a_b=384599/10^{10}$ and +$b=a_c=717/10^7$, with $\tau=1-a$, $\sigma=1-b$, and put +\[ +\begin{gathered} + \eta=10^{-8},\quad\beta=\tfrac14,\quad q=a(1-2\eta),\quad + c=q(1+\eta),\quad\epsilon=\frac{1-\eta}{1+c+q},\\ + \lambda'=1-q,\quad\lambda=(\tau+\lambda')/2,\quad + g=\epsilon q,\quad r=(g+1-\epsilon)/2,\quad\delta=\eta/8. +\end{gathered} +\] +The stopped complex leaf saving $(1-\beta)b=53.775\times10^{-6}$ +is strictly above $a$, so paid internal adapters use exponent $\tau$ +and both layer exponents lie below $\lambda'$. The exact certificate +checks all 47 strict constraints of the retained semantic/bulk +composition, using the new literal scalar charge and product-row gap. +These include compact reservations, geometry, the linear guard, +$\epsilon+r<1$, phase-cell/band separation, prime packing, short-record +fallback and artificial-boundary allowances. + +The seven final savings are +\[ + 1-\epsilon(1+c),\quad a,\quad g,\quad a,\quad + \min(1-\epsilon-\delta,r-\delta),\quad + 1-\epsilon-\delta,\quad\epsilon. +\] +Their minimum is exactly $g$ and the prefix margin equals $g+\eta$. +Exact rational comparison gives +\[ + g-\frac{384569}{10^{10}}>4.0746056580\times10^{-11}>0. +\] +These positive gaps absorb fixed logarithms. The all-size conclusion +retains constructive finite setup, descriptor and catalogue domination, +prime existence and analytic recovery as eventual thresholds. The +strict bit and complex moments, copied-stream recurrence contracts and +these assembly inequalities prove the claimed conditional bound. +\end{proof} diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-lemma.tex b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-lemma.tex new file mode 100644 index 0000000000..8933aaf508 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/copied-centers-lemma.tex @@ -0,0 +1,103 @@ +\subsection{Scalar, frame and temporary-stream contracts} +The retained source-copy, reversible mixer and scatter maps satisfy +$JLV=I$. Over $\mathbb F_2$ the chronological word +\[ + L,\ J,\ L^{-1},\ V,\ L,\ J,\ L^{-1},\ V +\] +adds the input to the target and restores every arbitrary auxiliary. +Over Gaussian dyadics use its corresponding old-value subtraction and +new-value addition. A designated retained output has a distinct terminal +output-use carrier: a matching may feed that carrier, but cannot merge +two designated terminals or append a later middle-producer consumer. +Its remaining uses before cleanup are its scatter reads, all of which +leave its scalar value unchanged. + +Within one tensor invocation suppress the fixed future line and put +\[ + D_0=B\otimes F_h,\quad D_1=A\otimes F_h,\quad + A=B\mathbin{\perp}P,\quad D_U=D_0\mathbin{\perp}(P\otimes U), +\] +where $P$ and the suppressed future factor are one-dimensional and +$U$ is a nondegenerate retained-center space of dimension $r$. +Thus a local change of rank $d$ has ambient rank $d$. +Write $\mathcal F_Q$ for the address frame: it is the rational partial +swap $D_Q$ in the bit construction, and the binary phase $C_Q$ in the +complex construction. Changing a copy from frame $Q_1$ to $Q_2$ means +applying $\mathcal F_{Q_2}\mathcal F_{Q_1}^{-1}$ to its physical stream. +Orthogonal backgrounds cancel in this quotient. + +Copies use Paureel's retained copy/transform/read/discard interface +\cite{paureel,pr29}. A copy has precisely the original complete role +stream, including all control and spectator ranges, and volume $V/W$. +It is processed while inactive original streams are parked on the fixed +depth-first stack tapes. Copying, pointwise reads and erasure are linear +in that stream's volume. Sequential processing needs one additional +fixed work stream, not an independently varying row coordinate. + +\begin{lemma}[Copied retained-center schedule] +In either invocation orientation a designated retained center's +physical rank profile can be changed from $z^r+z^h$ to +$z^r+z^{h-r}$, with the same scalar action, original role endpoints, +and arbitrary-scratch restoration. The rank-$r$ transform on the copy +is included in the recursive call list. +\end{lemma} +\begin{proof} +In the forward orientation the original center has scalar value $w$ +at frame $D_U$ after the middle mixer. Its old sequence was +$D_U\to D_0\to D_1$: scatter at $D_0$, then cleanup at $D_1$, +with ranks $r,h$. +Keep the original at $D_U$, copy its physical stream, and transform +only the copy to $D_0$, paying rank $r$. Supply every scatter read +from that transformed copy while its data targets remain at their +unchanged common frame $D_0$, then erase the temporary. The reads +are exactly those of $w$ in the old schedule. Since they do not change +$w$, move the original directly from $D_U$ to $D_1$ before its first +cleanup incidence; this costs $h-r$. Every subsequent original gate +therefore receives the same scalar value at its required frame. + +In the reverse complementary orientation the old sequence was +$D_0\to D_1\to D_{U^\perp}$, with ranks $h,r$ and scatter at $D_1$. +After the preceding all-$D_0$ operations, advance the original directly +to $D_{U^\perp}=D_0\mathbin{\perp}(P\otimes U^\perp)$, paying +$h-r$. Copy it and transform the copy to $D_1$, paying $r$. +Use that copy for all early scatter reads, then erase it. The original +already has the exact frame and unchanged scalar value required by the +following inverse mixer. Terminal output-use separation ensures no +intervening producer consumer has been bypassed. + +For partial swaps either direction of the rank-$r$ change is the same +involution. For complex phases the forward copy uses $C_U^{-1}$, +the direct original growth uses $C_{U^\perp}$, and the reverse copy +uses $C_FC_{U^\perp}^{-1}=C_U$. These are the same charged ranks, +implemented by the retained forward/inverse residual interface. +All tensor backgrounds cancel as stated. Every original scalar +incidence, final source-copy cancellation and auxiliary source/sink +operator is unchanged. Thus the scalar identity and all endpoints +remain exact on arbitrary initial auxiliary values. +\end{proof} + +For the selected centers $r=h-1$, and there are $h$ distinct retained +output uses per invocation. Their old histogram has rank mass +$hR_h+2\ell_h$, where $\ell_h=h(h-1)$. The new histogram is exactly +\[ + H'_{h,1}=H_{h,1}+h,\qquad H'_{h,h}=H_{h,h}-h, + \qquad H'_{h,r}=H_{h,r}\quad(r\ne1,h), +\] +and hence $\sum_r rH'_{h,r}=hR_h+\ell_h$. +Every old rank-$(h-1)$ residual remains as a paid transform of a copy; +its projector and ordinary bit pivot profile are unchanged. Only the +full-rank original transition becomes the rank-one complement. +The physical role count $R_h$ is unchanged. + +For two factors, put $N=v_av_b$, $B_a=v_bR_a$, $B_b=v_aR_b$, +$W=2N+B_a+B_b$ and $L=v_b\ell_a+v_a\ell_b$. +All exterior, data-front and endpoint-correction calls remain in place. +The resulting complete rank mass is +\[ + s=Wm-N+L,\qquad Wm-s=N-L. +\] +This follows by subtracting exactly $L$ from the retained two-stage +physical mass $Wm-N+2L$. The $N$ rank-one endpoint-copy calls are +separate and remain fully charged. Because center copies retain the +same complete role-volume fraction $1/W$, the existing complete-row, +integer-width remainder and fixed-tape recurrence proofs apply. diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/endpoint-gauge-complex.tex b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/endpoint-gauge-complex.tex new file mode 100644 index 0000000000..907a0ceda8 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/retained/endpoint-gauge-complex.tex @@ -0,0 +1,225 @@ +\subsection{A normal form for every nondegenerate binary residual} +Let $E$ have binary basis matrix $V$ and nonsingular Gram matrix +$G=V^tV$. In dual Fourier coordinates put +$q(z)=\operatorname{wt}(VG^{-1}z)\pmod4$. +Its polarization is $2z^tG^{-1}w$. The same argument applies to mixed +signs on orthogonal summands, since reversing a sign preserves this +polarization. Write $S_q=\sum_z i^{q(z)}$. Completing the square gives +\[ +\begin{aligned} +K(x,y)&=2^{-r}\sum_z i^{q(z)}(-1)^{z^t(x+y)}\\ + &=2^{-r}S_q\,i^{-q(Gx)}(-1)^{x^tGy}i^{-q(Gy)}. +\end{aligned} +\] +The scaled Walsh kernel in the middle is a binary permutation of +$H_0^{\otimes r}$, where +\[ + H_0=\tfrac12\begin{pmatrix}1&1\\1&-1\end{pmatrix} + =bSCS,\qquad b=(1-i)/2,\quad S=\operatorname{diag}(1,i). +\] +The remaining scalar $S_qb^r$ is a fourth root of unity. To verify +this, decompose the nondegenerate quadratic module into odd +one-dimensional and alternating two-dimensional blocks. Their Gauss +sums are $1\pm i$ and $\pm2$, respectively; multiplying by $b$ and +$b^2$ gives a fourth root in each case. This is a proof device, not +an orthonormal-basis assumption on $E$. + +Consequently one rank-$r$ child suffices, with binary address changes, +diagonal fourth-root phases, and one scalar fourth-root phase. +On $f$ parallel columns it is one $C^{\otimes rf}$ child, the scalar +raised to power $f$, and columnwise quadratic phases modulo four. +The retained packed address operations evaluate these fixed formulas. +These wrappers have modulus one and introduce no denominator loss. + +\subsection{The selected Gaussian-dyadic producer} +Use paired triple exclusion with base threshold two, complete unsplit +disjoint and pair-star sums, and sharing by actual ordinary support. +For an ordinary support with at least two common points use the span +of its triple indicators; these form an orthonormal common-pair star. +Otherwise use the coordinate space of its union. Support inclusion +preserves these labels: losing the common pair enters a containing +coordinate space. Source lines use ordinary triple containment. + +Retain every full pair-star $P_{uv}=\sum_{w\ne u,v}X_{uvw}$ and form +$B_u=\sum_{v\ne u}P_{uv}=2\sum_{T\ni u}X_T$. +For even $h$ label these central additions by the nondegenerate +hyperplane $E_u=\{x:\sum_{j\ne u}x_j=0\}$; every contributing star +lies in it. Retain the global total $T$ with full-space label. +The central correction at target $S$ is +\[ + \frac14\sum_{u\in S}B_u-\frac12T + =\sum_U\frac{|S\cap U|-1}{2}X_U. +\] +Adding half the disjoint sum and subtracting half the intersection-two +sum gives exactly $X_S$. All coefficients are Gaussian dyadic. +The transparent retained-output wrapper and oriented carrier compiler +apply to these nested nondegenerate labels. The $h$ hyperplane centers +lose $h(h-1)$ and the global center loses $h$, so loss is $h^2$. +The selected counts, including all point centers, are +\[ +\begin{array}{c|rrrrrr} +h&v_h&c_h&q_h&|\mathcal M_h|&R_h&\text{loss}\\\hline +32&4960&122512&19873&19241&123144&1024\\ +30&4060&99153&16271&15873&99551&900\\ +40&9880&252023&39561&37642&253942&1600 +\end{array} +\] +Their internal histograms satisfy $\sum_r rH_{h,r}=hR_h+2h^2$. +They are distinct from the bit histograms. + +\subsection{Endpoint normalization and the complex characteristic} +For nondegenerate $U$, Fourier phases give +\[ + C_U^2=X_{P_U\mathbf1},\qquad + C_{U^\perp}C_U^{-1}=C_FX_{P_U\mathbf1}. +\] +Put $v=P_U\mathbf1$. On coordinates in $v$, this endpoint has +$C^{-1}$ instead of $C$. The identity $C^{-1}=-iZCZ$ shows that +conjugating by $Z_v$ and multiplying by $i^{\operatorname{wt}(v)}$ +normalizes it to $C_F$; for $f$ columns the exponent is +$f\operatorname{wt}(v)$. These are diagonal wrappers without a child. + +Choose stage-two source $C_{D_0}$ and sink $C_{D_0^\perp}$, where +$D_1=D_0\mathbin{\perp} A$ and $\dim A=b$. The same refined copy +schedule removes the entrance on every auxiliary role. With +$R=D_1^\perp$, the exit is $C_RC_{D_0}^{-1}$ on +$E=R\mathbin{\perp}D_0=A^\perp$. Its rank is $m-b$ and its +nondegenerate polar form is unchanged by the mixed signs. The normal +form above executes it as one child. Arbitrary auxiliary restoration +justifies the endpoint normalization on the entire $B_2$ bank. + +Use the complex counts to define $B_i=NR_{h_i}/v_{h_i}$, and now +\[ +\begin{aligned} +W&=2N+B_2+B_3=10390178240000,\\ +L&=\sum_i(N/v_{h_i})h_i^2=117399987200,\\ +s&=Wm-2N+2L=398982681296998400. +\end{aligned} +\] +The whole-residual macro list is +\[ +\begin{array}{c|rrrrr} +t&38328&38360&38370&37401&899\\\hline +n_t&B_1&B_3-B_1&B_2&2N&2N. +\end{array} +\] +Add $(N/v_h)H_{h,r}$ rank-$r$ children for each positive internal rank. +Leave the remaining physical-data rank, 39393978624000, as singleton +calls. The resulting list has weighted rank exactly $s$. +For $a_c=3/125000$ and $\sigma=1-a_c$, the rational logarithm bounds +above and $e^u\le(1-u)^{-1}$, $0\le u<1$, give +\[ + \Psi_c(\sigma)\le\sum_t\frac{n_tt}{Wm(1-a_c\ell_t)} + <1-\frac{792981575160764}{10^{23}}. +\] + +\subsection{The dependency-path guard} +Before gauging, nested producer labels telescope along every arithmetic +path, including wire switches at common-frame scalar gates. Retained +center drops occur on one return frontier per stage, crossed at most +once by a path, and each costs at most that axis dimension. Carrier +reuse adds only increasing continuations. This gives +$q_0=m+2(a+b+k)$. Gauging removes an early edge and adds $ab-b$ at +a late stage-two edge. A path meets at most one such edge, since it +terminates that stage-two role, which is not shared across stages. +Thus the conservative total rank budget is +\[ + q=m+2(a+b+k)+ab=39564. +\] +Every child except the four large macros is at most 899; two large +macros cannot fit within $q$. Set $\rho=19/10$, $\gamma=9997/10000$. +The integer comparisons $m^{19}>500000000^{10}$ and +$899^9<460^{10}$ give $m^\rho>500000000$ and +$899^{\rho-1}<460$. +If a path has one large child $t$, its moment is at most +\[ + (t/m)^\rho+(q-t)899^{\rho-1}/m^\rho. +\] +This expression increases over the large-child range, since its +numerator derivative is $\rho t^{\rho-1}-899^{\rho-1}>0$. +Use $t=m-b$ and the concavity bound +$(1-x)^{19/10}\le1-19x/10+9x^2/10$ to obtain +\[ + \sum_{\rm path}(r/m)^\rho + <1-\frac{19}{12800}+\frac9{10\cdot1280^2} + +\frac{1194\cdot460}{500000000} + =\frac{51180270301}{51200000000}<\gamma. +\] +Without a large macro the bound is $227493/6250000<\gamma$. + +For coefficient-depth accounting take $E_0=128(W+m+1)^3$. +There are at most $s$ positive-rank residual calls and $W$ endpoint +normalizations. Combining the quadratic phases with the $S$ factors, +each uses at most two diagonal phase passes and one scalar phase. +The inherited gate and remainder count is therefore bounded conservatively by +\[ + 36W^3+16s+16W+8m+4 card Γ * N.unit φ) + +Scalar chain of one class (`x1 y1 x2 y2` on `X1 Y1 X2 Y2`), as in `bridged-word.md`: + + stage 0 F on pair 1 Y1 = y1 + x1 + stage 1 B on pair 1 X1 = -y1 + gates A X1 += X2, Y2 -= Y1 + stage 2 F on pair 1 Y1 = x1 + x2 + gates B Y2 += Y1, X1 -= X2 (X1 = -y1, Y2 = y2 - y1 + x2) + stage 3 B on pair 2 X2 = y1 - y2 + stage 4 F on pair 2 Y2 = x2 + gates C Y1 -= Y2, X2 += X1 (X1 = -y1, X2 = -y2, Y1 = x1, Y2 = x2) + exchange X_i := Y_i, Y_i := -X_i +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace BR +open Binary Matrix Finset RAM SS CB RF +noncomputable section + +section Gates +variable {Γ T Sl C : Type} + +/-- source of the gates of the layers A and B: `X1 ← X2`, `Y2 ← Y1`. -/ +def pAB : BRole Γ T Sl C → BRole Γ T Sl C := + mkB (fun g t => kX2 (g,t)) (fun g t => kY1 (g,t)) (fun g t => kX2 (g,t)) + (fun g t => kY1 (g,t)) (fun g q => kS (g,q)) (fun g c => kC (g,c)) + +/-- layer A: `X1 += X2`, `Y2 -= Y1`. -/ +def kA : BRole Γ T Sl C → ℚ := + mkB (fun _ _ => 1) (fun _ _ => 0) (fun _ _ => 0) (fun _ _ => -1) (fun _ _ => 0) (fun _ _ => 0) + +/-- layer B: `X1 -= X2`, `Y2 += Y1`. -/ +def kB : BRole Γ T Sl C → ℚ := + mkB (fun _ _ => -1) (fun _ _ => 0) (fun _ _ => 0) (fun _ _ => 1) (fun _ _ => 0) (fun _ _ => 0) + +/-- source of the gates of the layer C: `Y1 ← Y2`, `X2 ← X1`. -/ +def pC : BRole Γ T Sl C → BRole Γ T Sl C := + mkB (fun g t => kX1 (g,t)) (fun g t => kY2 (g,t)) (fun g t => kX1 (g,t)) + (fun g t => kY2 (g,t)) (fun g q => kS (g,q)) (fun g c => kC (g,c)) + +/-- layer C: `Y1 -= Y2`, `X2 += X1`. -/ +def kCc : BRole Γ T Sl C → ℚ := + mkB (fun _ _ => 0) (fun _ _ => -1) (fun _ _ => 1) (fun _ _ => 0) (fun _ _ => 0) (fun _ _ => 0) + +/-- scalar map of a gate layer. -/ +def gsc (p : BRole Γ T Sl C → BRole Γ T Sl C) (k : BRole Γ T Sl C → ℚ) + (x : BRole Γ T Sl C → ℂ) : BRole Γ T Sl C → ℂ := fun i => x i + (k i : ℂ) * x (p i) + +/-- the signed exchange `X_i := Y_i`, `Y_i := -X_i` on both pairs. -/ +def bpull : BRole Γ T Sl C → BRole Γ T Sl C := + mkB (fun g t => kY1 (g,t)) (fun g t => kX1 (g,t)) (fun g t => kY2 (g,t)) + (fun g t => kX2 (g,t)) (fun g q => kS (g,q)) (fun g c => kC (g,c)) + +def bsgn : BRole Γ T Sl C → ℚ := + mkB (fun _ _ => 1) (fun _ _ => -1) (fun _ _ => 1) (fun _ _ => -1) (fun _ _ => 1) (fun _ _ => 1) + +variable [Fintype Γ] [DecidableEq Γ] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] + +def brecM : Matrix (BRole Γ T Sl C) (BRole Γ T Sl C) ℚ := + fun i j => if j = bpull i then bsgn i else 0 + +lemma actPoint_brecM (x : BRole Γ T Sl C → ℂ) (i : BRole Γ T Sl C) : + actPoint brecM x i = (bsgn i : ℂ) * x (bpull i) := by + unfold actPoint + rw [sum_eq_single (bpull i)] + · simp [brecM] + · intro j _ hj; simp [brecM, hj] + · simp + +/-- the scalar map of the whole network before the exchange, on one class. -/ +def chain (x : BRole Γ T Sl C → ℂ) : BRole Γ T Sl C → ℂ := + gsc pC kCc (lift2 GF (lift2 GB (gsc pAB kB (lift1 GF (gsc pAB kA (lift1 GB (lift1 GF x))))))) + +/-- **The scalar identity of the bridged chain**: `X_i = -y_i`, `Y_i = x_i` on both pairs, +helper slots unchanged. -/ +lemma chain_eq (x : BRole Γ T Sl C → ℂ) (l : BLive Γ T Sl) : + chain x (Sum.inl l) = mkB (fun g t => -x (kY1 (g,t))) (fun g t => x (kX1 (g,t))) + (fun g t => -x (kY2 (g,t))) (fun g t => x (kX2 (g,t))) + (fun g q => x (kS (g,q))) (fun g c => x (kC (g,c))) (Sum.inl l) := by + rcases l with (((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩) + all_goals + simp only [chain, gsc, lift1, lift2, GF, GB, mkB, mkS, pAB, pC, kA, kB, kCc, pos1, pos2, + kX1, kY1, kX2, kY2, kS, kC, jX, jY, jS, jC, Function.comp_apply] + first + | (push_cast; ring) + | (push_cast; done) + | ring + +end Gates + +section Net +variable {H T Sl C α Γ : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] + [Fintype Γ] [DecidableEq Γ] +variable (N : Bridge2 H T Sl C α Γ) + +/-- gate layer A, after stage 1 and the first idle climb of pair 2: twins have equal frames. -/ +lemma Bridge2.gateA : XRoute N.S3 N.S3 (gsc pAB kA) (fun _ => 0) := by + refine gateP pAB kA N.S3 ?_ + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) hk + · rfl + · exact (hk rfl).elim + · exact (hk rfl).elim + · rfl + · exact (hk rfl).elim + · exact (hk rfl).elim + +/-- gate layer B, after stage 2 and the second idle climb of pair 2. -/ +lemma Bridge2.gateB : XRoute N.S5 N.S5 (gsc pAB kB) (fun _ => 0) := by + refine gateP pAB kB N.S5 ?_ + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) hk + · exact N.x23 g t + · exact (hk rfl).elim + · exact (hk rfl).elim + · exact (N.y23 g t).symm + · exact (hk rfl).elim + · exact (hk rfl).elim + +/-- gate layer C, after the final climbs. -/ +lemma Bridge2.gateC : XRoute N.S8 N.S8 (gsc pC kCc) (fun _ => 0) := by + refine gateP pC kCc N.S8 ?_ + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) hk + · exact (hk rfl).elim + · rfl + · rfl + · exact (hk rfl).elim + · exact (hk rfl).elim + · exact (hk rfl).elim + +/-- the free shifts at the end. -/ +def Bridge2.corr : BRole Γ T Sl C → Space α := + mkB (fun _ _ => 0) (fun g t => N.u g t) (fun _ _ => 0) (fun g t => N.u g t) + (fun _ _ => 0) (fun _ _ => 0) + +def Bridge2.S9 : BRole Γ T Sl C → CMat α := fun r => shift (N.corr r) * N.S8 r + +/-- the whole word before the exchange: five stages, three idle-climb layers, three gate +layers. -/ +lemma Bridge2.route : + XRoute N.S0 N.S8 chain (fun φ => (Fintype.card Γ : ℝ) * N.unit φ) := by + have R := ((((((((((N.stage0.trans N.stage1).trans N.climbA).trans N.gateA).trans + N.stage2).trans N.climbB).trans N.gateB).trans N.stage3).trans N.stage4).trans + N.fin).trans N.gateC) + refine (R.castg ?_).cast (fun φ => ?_) + · rfl + · simp only [Bridge2.unit] + ring + +/-- **The scratch certificate of the bridged five-stage network with shared helper sets**, +in whole blocks, with its exact price for every price list. -/ +theorem bridge2_certificate : + BCert α (Sum.inl : BLive Γ T Sl → BRole Γ T Sl C) + (fun φ => (Fintype.card Γ : ℝ) * N.unit φ) := by + have R2 : XRoute N.S8 N.S9 id (fun _ => 0) := XRoute.shifts N.hm N.S8 N.corr + have R3 : XRoute N.S9 (fun r => N.S9 (bpull r)) (actPoint brecM) (fun _ => 0) := + XRoute.gate brecM N.S9 _ (fun i j h => by + have hj : j = bpull i := by + by_contra hne + exact h (by simp [brecM, hne]) + rw [hj]) + have Rt := ((N.route.trans R2).trans R3).cast (c' := fun φ => (Fintype.card Γ : ℝ) * N.unit φ) + (fun φ => by first | ring | simp) + have hSinv : ∀ r, ∃ M, N.S0 r * M = 1 := by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact N.inv0 g t + · refine ⟨1, ?_⟩ + show (N.M0 g).Φ 0 * 1 = 1 + rw [N.z0, Matrix.mul_one] + · exact N.inv0 g t + · refine ⟨1, ?_⟩ + show (N.M0 g).Φ 0 * 1 = 1 + rw [N.z0, Matrix.mul_one] + · exact ⟨1, Matrix.mul_one _⟩ + · exact ⟨1, Matrix.mul_one _⟩ + choose S' hS' using hSinv + have hT : ∀ l : BLive Γ T Sl, N.S9 (bpull (Sum.inl l)) = kernel α * N.S0 (Sum.inl l) := by + rintro (((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩) + · show shift (N.u g t) * N.YF g t = kernel α * (N.M0 g).Φ (tt (N.I.tv t)) + exact (N.term g t).symm + · show shift (0 : Space α) * kernel α = kernel α * (N.M0 g).Φ 0 + rw [shift_zero, Matrix.one_mul, N.z0, Matrix.mul_one] + · show shift (N.u g t) * N.YF g t = kernel α * (N.M0 g).Φ (tt (N.I.tv t)) + exact (N.term g t).symm + · show shift (0 : Space α) * kernel α = kernel α * (N.M0 g).Φ 0 + rw [shift_zero, Matrix.one_mul, N.z0, Matrix.mul_one] + · show shift (0 : Space α) * kernel α = kernel α * 1 + rw [shift_zero, Matrix.one_mul, Matrix.mul_one] + have hg : ∀ x : BRole Γ T Sl C → ℂ, + (∀ s, (∀ l : BLive Γ T Sl, (Sum.inl l : BRole Γ T Sl C) ≠ s) → x s = 0) → + ∀ l : BLive Γ T Sl, + (actPoint brecM ∘ (id ∘ chain)) x (Sum.inl l) = x (Sum.inl l) := by + intro x _ l + change actPoint brecM (chain x) (Sum.inl l) = _ + rw [actPoint_brecM] + rcases l with (((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩) + · show ((1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inl (Sum.inr (g,t))))) = _ + rw [chain_eq] + show ((1:ℚ):ℂ) * x (kX1 (g,t)) = x (kX1 (g,t)) + first | (push_cast; ring) | simp + · show ((-1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inl (Sum.inl (g,t))))) = _ + rw [chain_eq] + show ((-1:ℚ):ℂ) * (-x (kY1 (g,t))) = x (kY1 (g,t)) + first | (push_cast; ring) | simp + · show ((1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inr (Sum.inr (g,t))))) = _ + rw [chain_eq] + show ((1:ℚ):ℂ) * x (kX2 (g,t)) = x (kX2 (g,t)) + first | (push_cast; ring) | simp + · show ((-1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inr (Sum.inl (g,t))))) = _ + rw [chain_eq] + show ((-1:ℚ):ℂ) * (-x (kY2 (g,t))) = x (kY2 (g,t)) + first | (push_cast; ring) | simp + · show ((1:ℚ):ℂ) * chain x (Sum.inl (Sum.inr (g,q))) = _ + rw [chain_eq] + show ((1:ℚ):ℂ) * x (kS (g,q)) = x (kS (g,q)) + first | (push_cast; ring) | simp + exact XRoute.liveKernel (Sum.inl : BLive Γ T Sl → BRole Γ T Sl C) N.S0 S' + (fun r => N.S9 (bpull r)) hS' _ _ Rt hg hT + +end Net +end +end BR +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.BR.chain_eq +#print axioms OAI.PowerSaving.BR.Bridge2.route +#print axioms OAI.PowerSaving.BR.bridge2_certificate diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Net.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Net.lean new file mode 100644 index 0000000000..204f6d9cf9 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Bridge__Net.lean @@ -0,0 +1,345 @@ +import Work.Bridge.Inv + +/-! +# (key: bridge-net) The BRIDGED five-stage network B_2 with shared helper sets, abstract form + +Generalises `RF.Fold3S` / `RF.fold3s_certificate` (`Work.Reframe.SCert`) to the bridged word +of PLAN2.md B1: every class `(g,t)` has TWO bank pairs `(X1,Y1)`, `(X2,Y2)` with the same +line; five stages of invocations + + stage 0 forward on pair 1 invocation of the class (g,t): g + stage 1 backward on pair 1 r1 t g + stage 2 forward on pair 1 r2 t g + stage 3 backward on pair 2 r3 t g + stage 4 forward on pair 2 r4 t g + +and three layers of FREE gates between twins at equal frames: + + after stage 1 (pair 2 has climbed to the frames of pair 1): X1 += X2, Y2 -= Y1 + after stage 2 (pair 2 has climbed one more window): Y2 += Y1, X1 -= X2 + after the final climbs (all four roles at their end frames): Y1 -= Y2, X2 += X1 + +Result on both pairs: `X_i = -y_i`, `Y_i = x_i`; then the usual signed exchange. + +The idle pair does not move during a stage. Its climbs are ONE block per role: +`aX2`, `aY2` (pair 2 before the first gate layer, prices `caX`, `caY`; in B_2 ONE block of +rank `2h-2` each), +the window of stage 2 (pair 2 before the second gate layer, rank `card H - 1`, from the +package: `Inv.climbX`, `Inv.climbY`), `fX1`, `fY1` (pair 1 at the end, prices `cX1`, `cY1`; +in B_2 ONE block of rank `2h+2` each), `fX2`, `fY2` (pair 2 at the end, prices `cX2`, `cY2`; +in B_2 one block of rank `4` each). The prices are arbitrary functions of the price list, so +a geometry that makes an idle climb in several blocks can be plugged in as well. + +`Bridge2 H T Sl C α Γ` is everything the wiring needs to know about the geometry; +`bridge2_certificate`: a `BCert` on the live roles `BLive Γ T Sl` +(`card Γ * (4 card T + card Sl)` of them, `BR.card_BLive`) whose price, for EVERY price +list, is `card Γ * N.unit φ`, + + N.unit φ = 5 * N.I.cost φ + card T * ((caX φ + caY φ) + 2 * bcost φ (card H - 1) + + (cX1 φ + cY1 φ) + (cX2 φ + cY2 φ)). +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace BR +open Binary Matrix Finset RAM SS CB RF +noncomputable section + +/-- See the file header. Fields in the style of `RF.Fold3S`; stages are numbered 0 to 4. -/ +structure Bridge2 (H T Sl C α Γ : Type) [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] where + /-- the invocation (for a block circuit `X`: `X.inv`). -/ + I : Inv H T Sl C + /-- frame maps of the invocations of the five stages. -/ + M0 : Γ → XMap H α + M1 : Γ → XMap H α + M2 : Γ → XMap H α + M3 : Γ → XMap H α + M4 : Γ → XMap H α + /-- the class `(g,t)` is served by the invocation `g` in stage 0 and `r_l t g` in stage `l`. -/ + r1 : T → Γ ≃ Γ + r2 : T → Γ ≃ Γ + r3 : T → Γ ≃ Γ + r4 : T → Γ ≃ Γ + /-- the invocation `d` of stage `l` uses the helper set (and the copies) `s_l d`. -/ + s1 : Γ ≃ Γ + s2 : Γ ≃ Γ + s3 : Γ ≃ Γ + s4 : Γ ≃ Γ + /-- inverse of the frame of the base, and frame of the window, of every invocation. -/ + N1 : Γ → CMat α + W1 : Γ → CMat α + N2 : Γ → CMat α + W2 : Γ → CMat α + N3 : Γ → CMat α + W3 : Γ → CMat α + N4 : Γ → CMat α + W4 : Γ → CMat α + u : Γ → T → Space α + YF : Γ → T → CMat α + hm : 2 ≤ Fintype.card α + /-- prices of the idle climbs, for every price list. B_2 with merged climbs: + `caX = caY = fun φ => bcost φ (2h-2)`, `cX1 = cY1 = fun φ => bcost φ (2h+2)`, + `cX2 = cY2 = fun φ => bcost φ 4`. -/ + caX : (ℕ → ℝ) → ℝ + caY : (ℕ → ℝ) → ℝ + cX1 : (ℕ → ℝ) → ℝ + cY1 : (ℕ → ℝ) → ℝ + cX2 : (ℕ → ℝ) → ℝ + cY2 : (ℕ → ℝ) → ℝ + inv0 : ∀ g t, ∃ N : CMat α, (M0 g).Φ (tt (I.tv t)) * N = 1 + z0 : ∀ g, (M0 g).Φ 0 = 1 + hN1 : ∀ d, (M1 d).Φ 0 * N1 d = 1 + hW1 : ∀ d, (M1 d).Φ 1 = W1 d * (M1 d).Φ 0 + hN2 : ∀ d, (M2 d).Φ 0 * N2 d = 1 + hW2 : ∀ d, (M2 d).Φ 1 = W2 d * (M2 d).Φ 0 + hN3 : ∀ d, (M3 d).Φ 0 * N3 d = 1 + hW3 : ∀ d, (M3 d).Φ 1 = W3 d * (M3 d).Φ 0 + hN4 : ∀ d, (M4 d).Φ 0 * N4 d = 1 + hW4 : ∀ d, (M4 d).Φ 1 = W4 d * (M4 d).Φ 0 + /-- the bank frames a stage leaves are the bank frames the next stage starts from. -/ + x01 : ∀ g t, (M0 g).Φ 1 = (M1 (r1 t g)).Φ (tt (I.tv t)) + y01 : ∀ g t, (M0 g).Φ (1 + tt (I.tv t)) = (M1 (r1 t g)).Φ 0 + x12 : ∀ g t, (M1 (r1 t g)).Φ 1 = (M2 (r2 t g)).Φ (tt (I.tv t)) + y12 : ∀ g t, (M1 (r1 t g)).Φ (1 + tt (I.tv t)) = (M2 (r2 t g)).Φ 0 + x23 : ∀ g t, (M2 (r2 t g)).Φ 1 = (M3 (r3 t g)).Φ (tt (I.tv t)) + y23 : ∀ g t, (M2 (r2 t g)).Φ (1 + tt (I.tv t)) = (M3 (r3 t g)).Φ 0 + x34 : ∀ g t, (M3 (r3 t g)).Φ 1 = (M4 (r4 t g)).Φ (tt (I.tv t)) + y34 : ∀ g t, (M3 (r3 t g)).Φ (1 + tt (I.tv t)) = (M4 (r4 t g)).Φ 0 + /-- the five windows of a helper set make up the kernel. -/ + sfin : ∀ g, W4 (s4.symm g) * (W3 (s3.symm g) * (W2 (s2.symm g) * + (W1 (s1.symm g) * (M0 g).Φ 1))) = kernel α + /-- pair 2, idle in stages 0 and 1: ONE block from its start frame to the frame of its + twin after stage 1. -/ + aX2 : ∀ g t, XReach ((M0 g).Φ (tt (I.tv t))) ((M1 (r1 t g)).Φ 1) caX + aY2 : ∀ g t, XReach ((M0 g).Φ 0) ((M1 (r1 t g)).Φ (1 + tt (I.tv t))) caY + /-- pair 1, idle in stages 3 and 4: ONE block from its frame after stage 2 to the end. -/ + fX1 : ∀ g t, XReach ((M2 (r2 t g)).Φ 1) (kernel α) cX1 + fY1 : ∀ g t, XReach ((M2 (r2 t g)).Φ (1 + tt (I.tv t))) (YF g t) cY1 + /-- pair 2 after stage 4: ONE final block. -/ + fX2 : ∀ g t, XReach ((M4 (r4 t g)).Φ 1) (kernel α) cX2 + fY2 : ∀ g t, XReach ((M4 (r4 t g)).Φ (1 + tt (I.tv t))) (YF g t) cY2 + term : ∀ g t, kernel α * (M0 g).Φ (tt (I.tv t)) = shift (u g t) * YF g t + +section Net +variable {H T Sl C α Γ : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] + [Fintype Γ] [DecidableEq Γ] +variable (N : Bridge2 H T Sl C α Γ) + +/-- price of the blocks of one unit (one element of `Γ`): five invocations and the idle +climbs of the four bank roles of every class. -/ +def Bridge2.unit (φ : ℕ → ℝ) : ℝ := + 5 * N.I.cost φ + (Fintype.card T : ℝ) * ((N.caX φ + N.caY φ) + + 2 * bcost φ (Fintype.card H - 1) + + (N.cX1 φ + N.cY1 φ) + (N.cX2 φ + N.cY2 φ)) + +/-- scratch copies always enter and leave with the matrix `1` (also: the helper slots at the +start, with `C := Sl`). -/ +def cOne (Γ C α : Type) [Fintype α] [DecidableEq α] : Γ → C → CMat α := fun _ _ => 1 + +/-- the bank index of stage 0: the class `(g,t)` belongs to the invocation `g`. -/ +abbrev bid (Γ T : Type) : T → Γ ≃ Γ := fun _ => Equiv.refl Γ + +/-! bank frames of the class `(g,t)`: `xi l`, `yi l` at the START of stage `l`; `xo l`, +`yo l` at the END of stage `l` (only where no next stage follows on that pair). -/ +def Bridge2.xi0 (g : Γ) (t : T) : CMat α := (N.M0 g).Φ (tt (N.I.tv t)) +def Bridge2.yi0 (g : Γ) (t : T) : CMat α := (N.M0 g).Φ 0 +def Bridge2.xi1 (g : Γ) (t : T) : CMat α := (N.M1 (N.r1 t g)).Φ (tt (N.I.tv t)) +def Bridge2.yi1 (g : Γ) (t : T) : CMat α := (N.M1 (N.r1 t g)).Φ 0 +def Bridge2.xi2 (g : Γ) (t : T) : CMat α := (N.M2 (N.r2 t g)).Φ (tt (N.I.tv t)) +def Bridge2.yi2 (g : Γ) (t : T) : CMat α := (N.M2 (N.r2 t g)).Φ 0 +def Bridge2.xo2 (g : Γ) (t : T) : CMat α := (N.M2 (N.r2 t g)).Φ 1 +def Bridge2.yo2 (g : Γ) (t : T) : CMat α := (N.M2 (N.r2 t g)).Φ (1 + tt (N.I.tv t)) +def Bridge2.xi3 (g : Γ) (t : T) : CMat α := (N.M3 (N.r3 t g)).Φ (tt (N.I.tv t)) +def Bridge2.yi3 (g : Γ) (t : T) : CMat α := (N.M3 (N.r3 t g)).Φ 0 +def Bridge2.xi4 (g : Γ) (t : T) : CMat α := (N.M4 (N.r4 t g)).Φ (tt (N.I.tv t)) +def Bridge2.yi4 (g : Γ) (t : T) : CMat α := (N.M4 (N.r4 t g)).Φ 0 +def Bridge2.xo4 (g : Γ) (t : T) : CMat α := (N.M4 (N.r4 t g)).Φ 1 +def Bridge2.yo4 (g : Γ) (t : T) : CMat α := (N.M4 (N.r4 t g)).Φ (1 + tt (N.I.tv t)) + +/-- helper slots after the stages 0, 1, 2, 3, 4 (at the start: `cOne Γ Sl α`). -/ +def Bridge2.Z1 : Γ → Sl → CMat α := fun g _ => (N.M0 g).Φ 1 +def Bridge2.Z2 : Γ → Sl → CMat α := fun g q => N.W1 (N.s1.symm g) * N.Z1 g q +def Bridge2.Z3 : Γ → Sl → CMat α := fun g q => N.W2 (N.s2.symm g) * N.Z2 g q +def Bridge2.Z4 : Γ → Sl → CMat α := fun g q => N.W3 (N.s3.symm g) * N.Z3 g q +def Bridge2.Z5 : Γ → Sl → CMat α := fun g q => N.W4 (N.s4.symm g) * N.Z4 g q + +/-- frames: at the start; after stage 0; after stage 1; after the first idle climb of pair 2 +(first gate layer here); after stage 2; after the second idle climb of pair 2 (second gate +layer here); after stage 3; after stage 4; after the final climbs (third gate layer here). -/ +def Bridge2.S0 : BRole Γ T Sl C → CMat α := mkB N.xi0 N.yi0 N.xi0 N.yi0 (cOne Γ Sl α) (cOne Γ C α) +def Bridge2.S1 : BRole Γ T Sl C → CMat α := mkB N.xi1 N.yi1 N.xi0 N.yi0 N.Z1 (cOne Γ C α) +def Bridge2.S2 : BRole Γ T Sl C → CMat α := mkB N.xi2 N.yi2 N.xi0 N.yi0 N.Z2 (cOne Γ C α) +def Bridge2.S3 : BRole Γ T Sl C → CMat α := mkB N.xi2 N.yi2 N.xi2 N.yi2 N.Z2 (cOne Γ C α) +def Bridge2.S4 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xi2 N.yi2 N.Z3 (cOne Γ C α) +def Bridge2.S5 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xi3 N.yi3 N.Z3 (cOne Γ C α) +def Bridge2.S6 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xi4 N.yi4 N.Z4 (cOne Γ C α) +def Bridge2.S7 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xo4 N.yo4 N.Z5 (cOne Γ C α) +def Bridge2.S8 : BRole Γ T Sl C → CMat α := + mkB (fun _ _ => kernel α) N.YF (fun _ _ => kernel α) N.YF (fun _ _ => kernel α) (cOne Γ C α) + +/-- stage 0: forward on pair 1, every helper set starts at the matrix `1`. -/ +lemma Bridge2.stage0 : + XRoute N.S0 N.S1 (lift1 GF) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + have h := istage_fwd N.I (bid Γ T) (Equiv.refl Γ) N.M0 (fun _ => 1) (fun g => (N.M0 g).Φ 1) + (fun d => by rw [N.z0, Matrix.mul_one]) (fun d => by rw [N.z0, Matrix.mul_one]) + (cOne Γ Sl α) (cOne Γ C α) (cOne Γ C α) + have e : bOut N.I.tv (bid Γ T) N.M0 + (fun g (q : Sl) => (N.M0 ((Equiv.refl Γ).symm g)).Φ 1 * cOne Γ Sl α g q) (cOne Γ C α) + = mkS N.xi1 N.yi1 N.Z1 (cOne Γ C α) := by + funext r + rcases r with (((⟨g,t⟩|⟨g,t⟩)|⟨g,q⟩)|⟨g,c⟩) + · exact N.x01 g t + · exact N.y01 g t + · show (N.M0 g).Φ 1 * 1 = (N.M0 g).Φ 1 + rw [Matrix.mul_one] + · rfl + have h' : XRoute (bIn N.I.tv (bid Γ T) N.M0 (cOne Γ Sl α) (cOne Γ C α)) + (mkS N.xi1 N.yi1 N.Z1 (cOne Γ C α)) GF (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + rw [← e] + exact h + exact blift1 N.xi0 N.yi0 h' + +/-- stage 1: backward on pair 1; the helper set `g` serves the invocation `s1⁻¹ g`. -/ +lemma Bridge2.stage1 : + XRoute N.S1 N.S2 (lift1 GB) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + have h := istage_bwd N.I N.r1 N.s1 N.M1 N.N1 N.W1 N.hN1 N.hW1 N.Z1 (cOne Γ C α) (cOne Γ C α) + have e : bOut N.I.tv N.r1 N.M1 (fun g q => N.W1 (N.s1.symm g) * N.Z1 g q) (cOne Γ C α) + = mkS N.xi2 N.yi2 N.Z2 (cOne Γ C α) := by + funext r + rcases r with (((⟨g,t⟩|⟨g,t⟩)|⟨g,q⟩)|⟨g,c⟩) + · exact N.x12 g t + · exact N.y12 g t + · rfl + · rfl + have h' : XRoute (bIn N.I.tv N.r1 N.M1 N.Z1 (cOne Γ C α)) + (mkS N.xi2 N.yi2 N.Z2 (cOne Γ C α)) GB (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + rw [← e] + exact h + exact blift1 N.xi0 N.yi0 h' + +/-- stage 2: forward on pair 1. -/ +lemma Bridge2.stage2 : + XRoute N.S3 N.S4 (lift1 GF) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := + blift1 N.xi2 N.yi2 + (istage_fwd N.I N.r2 N.s2 N.M2 N.N2 N.W2 N.hN2 N.hW2 N.Z2 (cOne Γ C α) (cOne Γ C α)) + +/-- stage 3: backward on pair 2. -/ +lemma Bridge2.stage3 : + XRoute N.S5 N.S6 (lift2 GB) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + have h := istage_bwd N.I N.r3 N.s3 N.M3 N.N3 N.W3 N.hN3 N.hW3 N.Z3 (cOne Γ C α) (cOne Γ C α) + have e : bOut N.I.tv N.r3 N.M3 (fun g q => N.W3 (N.s3.symm g) * N.Z3 g q) (cOne Γ C α) + = mkS N.xi4 N.yi4 N.Z4 (cOne Γ C α) := by + funext r + rcases r with (((⟨g,t⟩|⟨g,t⟩)|⟨g,q⟩)|⟨g,c⟩) + · exact N.x34 g t + · exact N.y34 g t + · rfl + · rfl + have h' : XRoute (bIn N.I.tv N.r3 N.M3 N.Z3 (cOne Γ C α)) + (mkS N.xi4 N.yi4 N.Z4 (cOne Γ C α)) GB (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + rw [← e] + exact h + exact blift2 N.xo2 N.yo2 h' + +/-- stage 4: forward on pair 2. -/ +lemma Bridge2.stage4 : + XRoute N.S6 N.S7 (lift2 GF) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := + blift2 N.xo2 N.yo2 + (istage_fwd N.I N.r4 N.s4 N.M4 N.N4 N.W4 N.hN4 N.hW4 N.Z4 (cOne Γ C α) (cOne Γ C α)) + +/-- first idle climb of pair 2 (stages 0 and 1 in ONE block per role), to the frames of +pair 1 after stage 1. -/ +lemma Bridge2.climbA : + XRoute N.S2 N.S3 id (fun φ => (Fintype.card Γ : ℝ) * + ((Fintype.card T : ℝ) * (N.caX φ + N.caY φ))) := by + have H1 := XRoute.reach_all N.S2 N.S3 + (mkB (fun _ _ _ => 0) (fun _ _ _ => 0) (fun _ _ => N.caX) + (fun _ _ => N.caY) (fun _ _ _ => 0) (fun _ _ _ => 0)) (by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact XReach.refl _ + · exact XReach.refl _ + · show XReach ((N.M0 g).Φ (tt (N.I.tv t))) ((N.M2 (N.r2 t g)).Φ (tt (N.I.tv t))) N.caX + rw [← N.x12 g t] + exact N.aX2 g t + · show XReach ((N.M0 g).Φ 0) ((N.M2 (N.r2 t g)).Φ 0) N.caY + rw [← N.y12 g t] + exact N.aY2 g t + · exact XReach.refl _ + · exact XReach.refl _) + refine H1.cast (fun φ => ?_) + simp_rw [mkB_map (fun c : (ℕ → ℝ) → ℝ => c φ)] + rw [sum_mkB] + simp only [sum_const, card_univ, nsmul_eq_mul, mul_zero, add_zero, zero_add] + ring + +/-- second idle climb of pair 2: the window of stage 2, ONE block of rank `card H - 1` per +role, to the frames of pair 1 after stage 2. -/ +lemma Bridge2.climbB : + XRoute N.S4 N.S5 id (fun φ => (Fintype.card Γ : ℝ) * + ((Fintype.card T : ℝ) * (2 * bcost φ (Fintype.card H - 1)))) := by + have H1 := XRoute.reach_all N.S4 N.S5 + (mkB (fun _ _ _ => 0) (fun _ _ _ => 0) (fun _ _ φ => bcost φ (Fintype.card H - 1)) + (fun _ _ φ => bcost φ (Fintype.card H - 1)) (fun _ _ _ => 0) (fun _ _ _ => 0)) (by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact XReach.refl _ + · exact XReach.refl _ + · show XReach ((N.M2 (N.r2 t g)).Φ (tt (N.I.tv t))) ((N.M3 (N.r3 t g)).Φ (tt (N.I.tv t))) + (fun φ => bcost φ (Fintype.card H - 1)) + rw [← N.x23 g t] + exact N.I.climbX (N.M2 (N.r2 t g)) t + · show XReach ((N.M2 (N.r2 t g)).Φ 0) ((N.M3 (N.r3 t g)).Φ 0) + (fun φ => bcost φ (Fintype.card H - 1)) + rw [← N.y23 g t] + exact N.I.climbY (N.M2 (N.r2 t g)) t + · exact XReach.refl _ + · exact XReach.refl _) + refine H1.cast (fun φ => ?_) + simp_rw [mkB_map (fun c : (ℕ → ℝ) → ℝ => c φ)] + rw [sum_mkB] + simp only [sum_const, card_univ, nsmul_eq_mul, mul_zero, add_zero, zero_add] + ring + +/-- the final climbs: pair 1 from its frames after stage 2 (ONE block per role for the +stages 3, 4 and the rest), pair 2 from its frames after stage 4; the helper slots are +already at the kernel. -/ +lemma Bridge2.fin : + XRoute N.S7 N.S8 id (fun φ => (Fintype.card Γ : ℝ) * + ((Fintype.card T : ℝ) * ((N.cX1 φ + N.cY1 φ) + (N.cX2 φ + N.cY2 φ)))) := by + have H1 := XRoute.reach_all N.S7 N.S8 + (mkB (fun _ _ => N.cX1) (fun _ _ => N.cY1) (fun _ _ => N.cX2) (fun _ _ => N.cY2) + (fun _ _ _ => 0) (fun _ _ _ => 0)) (by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact N.fX1 g t + · exact N.fY1 g t + · exact N.fX2 g t + · exact N.fY2 g t + · show XReach (N.W4 (N.s4.symm g) * (N.W3 (N.s3.symm g) * (N.W2 (N.s2.symm g) * + (N.W1 (N.s1.symm g) * (N.M0 g).Φ 1)))) (kernel α) (fun _ => 0) + rw [N.sfin g] + exact XReach.refl _ + · exact XReach.refl _) + refine H1.cast (fun φ => ?_) + simp_rw [mkB_map (fun c : (ℕ → ℝ) → ℝ => c φ)] + rw [sum_mkB] + simp only [sum_const, card_univ, nsmul_eq_mul, mul_zero, add_zero, zero_add] + ring + +end Net +end +end BR +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.BR.Bridge2.stage0 +#print axioms OAI.PowerSaving.BR.Bridge2.stage1 +#print axioms OAI.PowerSaving.BR.Bridge2.stage2 +#print axioms OAI.PowerSaving.BR.Bridge2.stage3 +#print axioms OAI.PowerSaving.BR.Bridge2.stage4 +#print axioms OAI.PowerSaving.BR.Bridge2.climbA +#print axioms OAI.PowerSaving.BR.Bridge2.climbB +#print axioms OAI.PowerSaving.BR.Bridge2.fin diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Live.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Live.lean new file mode 100644 index 0000000000..b8306527d6 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Live.lean @@ -0,0 +1,232 @@ +import Work.Carrier.Pack +import Work.Carrier.Ring + +/-! +# (key: carrier-thm) The live roles of an invocation, and the four dirt gates as matrices + +`L3 T Sl = (T ⊕ T) ⊕ Sl`: the bank roles `x` (`lX`), `y` (`lY`) and the helper slots (`lS`), all +on the same footing (no scratch copies). `PX`, `PY`: the coordinate projectors. + +For the matrix `M` of all gates of the main phase and its inverse `Mi`: + + g1 M = 1 - PY * M * PS `y -= K s` g1i M = 1 + PY * M * PS (its inverse) + g8 Mi = PX + PY + PS * Mi slot rows of `M⁻¹` h8 M = PX + PY + PS * M (its inverse) + +(`PS = 1 - PX - PY`). This file: unit rows / columns of these gates (hence between which roles +their entries can be nonzero), the scatter with the copies eliminated (`scatM`), and the scalar +maps of `1 + PY * M * PX` and of the transpose of `1 - PY * M * PX`. + +No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace CR +open Binary Matrix Finset RAM SS CB BR +noncomputable section + +section Diag +variable {ρ : Type*} [Fintype ρ] [DecidableEq ρ] + +lemma col_zero_of {d : ρ → ℚ} {G : Matrix ρ ρ ℚ} + (h : G * Matrix.diagonal d = Matrix.diagonal d) {i j : ρ} (hj : d j = 1) (hij : i ≠ j) : + G i j = 0 := by + have e := congrFun (congrFun h i) j + rw [Matrix.mul_diagonal, Matrix.diagonal_apply_ne _ hij, hj, mul_one] at e + exact e + +lemma row_zero_of {d : ρ → ℚ} {G : Matrix ρ ρ ℚ} + (h : Matrix.diagonal d * G = Matrix.diagonal d) {i j : ρ} (hi : d i = 1) (hij : i ≠ j) : + G i j = 0 := by + have e := congrFun (congrFun h i) j + rw [Matrix.diagonal_mul, Matrix.diagonal_apply_ne _ hij, hi, one_mul] at e + exact e + +lemma diag_mul_of_rows {d : ρ → ℚ} {G : Matrix ρ ρ ℚ} + (h : ∀ i j, d i ≠ 0 → G i j = if i = j then 1 else 0) : + Matrix.diagonal d * G = Matrix.diagonal d := by + ext i j + rw [Matrix.diagonal_mul] + by_cases hd : d i = 0 + · rw [hd, zero_mul] + by_cases hij : i = j + · subst hij; rw [Matrix.diagonal_apply_eq, hd] + · rw [Matrix.diagonal_apply_ne _ hij] + · rw [h i j hd] + by_cases hij : i = j + · subst hij; rw [if_pos rfl, mul_one, Matrix.diagonal_apply_eq] + · rw [if_neg hij, mul_zero, Matrix.diagonal_apply_ne _ hij] + +lemma mul_diag_of_cols {d : ρ → ℚ} {G : Matrix ρ ρ ℚ} + (h : ∀ i j, d j ≠ 0 → G i j = if i = j then 1 else 0) : + G * Matrix.diagonal d = Matrix.diagonal d := by + ext i j + rw [Matrix.mul_diagonal] + by_cases hd : d j = 0 + · rw [hd, mul_zero] + by_cases hij : i = j + · subst hij; rw [Matrix.diagonal_apply_eq, hd] + · rw [Matrix.diagonal_apply_ne _ hij] + · rw [h i j hd] + by_cases hij : i = j + · subst hij; rw [if_pos rfl, one_mul, Matrix.diagonal_apply_eq] + · rw [if_neg hij, zero_mul, Matrix.diagonal_apply_ne _ hij] + +/-- scalar map of a diagonal gate matrix. -/ +lemma act_diag (d : ρ → ℚ) (u : ρ → ℂ) : + actPoint (Matrix.diagonal d) u = fun i => ((d i : ℚ) : ℂ) * u i := by + funext i + show ∑ j, ((Matrix.diagonal d i j : ℚ) : ℂ) * u j = ((d i : ℚ) : ℂ) * u i + rw [Finset.sum_eq_single i] + · rw [Matrix.diagonal_apply_eq] + · intro j _ hj + rw [Matrix.diagonal_apply_ne _ (Ne.symm hj), Rat.cast_zero, zero_mul] + · intro h + exact absurd (Finset.mem_univ i) h + +lemma actPoint_mul (A B : Matrix ρ ρ ℚ) (u : ρ → ℂ) : + actPoint (A * B) u = actPoint A (actPoint B u) := + ap_mul A B u + +end Diag + +section Live +variable {T Sl : Type} [Fintype T] [DecidableEq T] [Fintype Sl] [DecidableEq Sl] + +/-- live roles of one invocation: `x`, `y`, helper slots. -/ +abbrev L3 (T Sl : Type) := (T ⊕ T) ⊕ Sl +abbrev lX (t : T) : L3 T Sl := Sum.inl (Sum.inl t) +abbrev lY (t : T) : L3 T Sl := Sum.inl (Sum.inr t) +abbrev lS (q : Sl) : L3 T Sl := Sum.inr q + +/-- indicator of the x roles. -/ +def iX : L3 T Sl → ℚ := Sum.elim (Sum.elim (fun _ => 1) (fun _ => 0)) (fun _ => 0) +/-- indicator of the y roles. -/ +def iY : L3 T Sl → ℚ := Sum.elim (Sum.elim (fun _ => 0) (fun _ => 1)) (fun _ => 0) + +def PX : Matrix (L3 T Sl) (L3 T Sl) ℚ := Matrix.diagonal iX +def PY : Matrix (L3 T Sl) (L3 T Sl) ℚ := Matrix.diagonal iY + +lemma iX_cases (i : L3 T Sl) : iX i = 0 ∨ iX i = 1 := by + rcases i with ((t|t)|q) + · exact Or.inr rfl + · exact Or.inl rfl + · exact Or.inl rfl + +lemma iY_cases (i : L3 T Sl) : iY i = 0 ∨ iY i = 1 := by + rcases i with ((t|t)|q) + · exact Or.inl rfl + · exact Or.inr rfl + · exact Or.inl rfl + +lemma PX_sq : (PX : Matrix (L3 T Sl) (L3 T Sl) ℚ) * PX = PX := by + unfold PX + have e : (fun i : L3 T Sl => iX i * iX i) = iX := by + funext i + rcases i with ((t|t)|q) <;> simp [iX] + rw [Matrix.diagonal_mul_diagonal, e] + +lemma PY_sq : (PY : Matrix (L3 T Sl) (L3 T Sl) ℚ) * PY = PY := by + unfold PY + have e : (fun i : L3 T Sl => iY i * iY i) = iY := by + funext i + rcases i with ((t|t)|q) <;> simp [iY] + rw [Matrix.diagonal_mul_diagonal, e] + +lemma PX_PY : (PX : Matrix (L3 T Sl) (L3 T Sl) ℚ) * PY = 0 := by + unfold PX PY + rw [Matrix.diagonal_mul_diagonal] + have e : (fun i : L3 T Sl => iX i * iY i) = fun _ => 0 := by + funext i + rcases i with ((t|t)|q) <;> simp [iX, iY] + rw [e] + exact Matrix.diagonal_zero + +lemma PY_PX : (PY : Matrix (L3 T Sl) (L3 T Sl) ℚ) * PX = 0 := by + unfold PX PY + rw [Matrix.diagonal_mul_diagonal] + have e : (fun i : L3 T Sl => iY i * iX i) = fun _ => 0 := by + funext i + rcases i with ((t|t)|q) <;> simp [iX, iY] + rw [e] + exact Matrix.diagonal_zero + +lemma PX_T : (PX : Matrix (L3 T Sl) (L3 T Sl) ℚ)ᵀ = PX := Matrix.diagonal_transpose _ +lemma PY_T : (PY : Matrix (L3 T Sl) (L3 T Sl) ℚ)ᵀ = PY := Matrix.diagonal_transpose _ + +/-- "no gate into an x role": the x rows are unit rows. -/ +lemma PX_mul_of {M : Matrix (L3 T Sl) (L3 T Sl) ℚ} + (hx : ∀ t j, M (lX t) j = if lX t = j then 1 else 0) : PX * M = PX := by + unfold PX + apply diag_mul_of_rows + intro i j hi + rcases i with ((t|t)|q) + · exact hx t j + · exact absurd rfl hi + · exact absurd rfl hi + +/-- "no gate reads a y role": the y columns are unit columns. -/ +lemma mul_PY_of {M : Matrix (L3 T Sl) (L3 T Sl) ℚ} + (hy : ∀ i t, M i (lY t) = if i = lY t then 1 else 0) : M * PY = PY := by + unfold PY + apply mul_diag_of_cols + intro i j hj + rcases j with ((t|t)|q) + · exact absurd rfl hj + · exact hy i t + · exact absurd rfl hj + +/-! ### the four dirt gates -/ + +def g1 (M : Matrix (L3 T Sl) (L3 T Sl) ℚ) : Matrix (L3 T Sl) (L3 T Sl) ℚ := + 1 - PY * M * (1 - PX - PY) +def g1i (M : Matrix (L3 T Sl) (L3 T Sl) ℚ) : Matrix (L3 T Sl) (L3 T Sl) ℚ := + 1 + PY * M * (1 - PX - PY) +def g8 (Mi : Matrix (L3 T Sl) (L3 T Sl) ℚ) : Matrix (L3 T Sl) (L3 T Sl) ℚ := + PX + PY + (1 - PX - PY) * Mi +def h8 (M : Matrix (L3 T Sl) (L3 T Sl) ℚ) : Matrix (L3 T Sl) (L3 T Sl) ℚ := + PX + PY + (1 - PX - PY) * M + +/-- a gate with unit x rows and unit x columns joins two different roles only if neither is an +x role. -/ +lemma offdiag_x {G : Matrix (L3 T Sl) (L3 T Sl) ℚ} (h1 : G * PX = PX) (h2 : PX * G = PX) + {i j : L3 T Sl} (hij : G i j ≠ 0) (e : i ≠ j) : iX i = 0 ∧ iX j = 0 := by + constructor + · by_contra h + exact hij (row_zero_of h2 ((iX_cases i).resolve_left h) e) + · by_contra h + exact hij (col_zero_of h1 ((iX_cases j).resolve_left h) e) + +/-- a gate with unit x rows, unit y rows and unit y columns: a nonzero entry off the diagonal +is in a slot row and not in a y column. -/ +lemma offdiag_s {G : Matrix (L3 T Sl) (L3 T Sl) ℚ} (hx : PX * G = PX) (hy : PY * G = PY) + (hyc : G * PY = PY) {i j : L3 T Sl} (hij : G i j ≠ 0) (e : i ≠ j) : + iX i = 0 ∧ iY i = 0 ∧ iY j = 0 := by + refine ⟨?_, ?_, ?_⟩ + · by_contra h + exact hij (row_zero_of hx ((iX_cases i).resolve_left h) e) + · by_contra h + exact hij (row_zero_of hy ((iY_cases i).resolve_left h) e) + · by_contra h + exact hij (col_zero_of hyc ((iY_cases j).resolve_left h) e) + +lemma g1_x (M : Matrix (L3 T Sl) (L3 T Sl) ℚ) : g1 M * PX = PX ∧ PX * g1 M = PX := by + unfold g1 + constructor + · rw [sub_mul, one_mul, side_n_right (PX_sq (T := T) (Sl := Sl)) PY_PX, sub_zero] + · rw [mul_sub, mul_one, side_n_left (PX_PY (T := T) (Sl := Sl)), sub_zero] + +lemma g1i_x (M : Matrix (L3 T Sl) (L3 T Sl) ℚ) : g1i M * PX = PX ∧ PX * g1i M = PX := by + unfold g1i + constructor + · rw [add_mul, one_mul, side_n_right (PX_sq (T := T) (Sl := Sl)) PY_PX, add_zero] + · rw [mul_add, mul_one, side_n_left (PX_PY (T := T) (Sl := Sl)), add_zero] + +end Live +end +end CR +end PowerSaving +end OAI diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Phases.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Phases.lean new file mode 100644 index 0000000000..305da15b5d --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Carrier__Phases.lean @@ -0,0 +1,192 @@ +import Work.Carrier.Glue + +/-! +# (key: carrier-thm) A carrier circuit given by its phases: hypotheses and scalar identities + +`Phased H T Sl C` is the hypothesis structure of the carrier invocation theorem in the general +scope (any ordered mix of gates `(x, slot)`, `(slot, slot)`, `(x, y)`, `(slot, y)`): + +* phase A (before the scatter), phase B (after it) and the final climbs F are exact block routes + on the LIVE roles `L3 T Sl` (`x`, `y`, slots: all on the same footing), for every block frame + map, with the gate products `MA`, `MB` (and the transposed inverses for the backward word); +* the scatter goes through the scratch copies: `c += Cc s` at the labels `cen`, the copies come + down, `y += Jr c` at 0; +* `hx`: no gate INTO an x role, `hy`: no gate READS a y role, `hid`: the y roles receive exactly + the x roles — three facts about the ONE matrix `Mt = MB * scatM (Jr * Cc) * MA`. + +This file: `Mt`, its inverse `Mti`, and the scalar identities of the forward and of the backward +word (`fwd_scalar`, `bwd_scalar`): with the two dirt gates `g1`, `g8` (resp. the transposes of +`g1i`, `h8`) the word does `y += x` (resp. `x -= y`) for ARBITRARY slot contents. + +No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace CR +open Binary Matrix Finset RAM SS CB BR +noncomputable section + +/-- labels of the live roles at the START of an invocation. -/ +def lab3 {H T Sl : Type} (tv : T → Space H) : L3 T Sl → Lbl H := + Sum.elim (Sum.elim (fun t => lineL (tv t)) (fun _ => zeroL)) (fun _ => zeroL) + +/-- **The hypotheses of the carrier invocation theorem, by phases.** See the file header. -/ +structure Phased (H T Sl C : Type) [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] where + tv : T → Space H + kx : ∀ t, Climb (lineL (tv t)) fullL + ky : ∀ t, Climb zeroL (perpL (tv t)) + cen : C → Lbl H + kc : ∀ k, Climb zeroL (cen k) + Cc : Matrix C Sl ℚ + Jr : Matrix T C ℚ + labA : L3 T Sl → Lbl H + labB : L3 T Sl → Lbl H + labF : L3 T Sl → Lbl H + hAy : ∀ t, (labA (lY t)).P = 0 + hAc : ∀ k q, Cc k q ≠ 0 → (cen k).P = (labA (lS q)).P + hFx : ∀ t, (labF (lX t)).P = 1 + hFy : ∀ t, (labF (lY t)).P = 1 + tt (tv t) + hFs : ∀ q, (labF (lS q)).P = 1 + MA : Matrix (L3 T Sl) (L3 T Sl) ℚ + MAi : Matrix (L3 T Sl) (L3 T Sl) ℚ + MB : Matrix (L3 T Sl) (L3 T Sl) ℚ + MBi : Matrix (L3 T Sl) (L3 T Sl) ℚ + hAi : MAi * MA = 1 + hBi : MBi * MB = 1 + hx : ∀ t j, (MB * scatM (Jr * Cc) * MA) (lX t) j = if lX t = j then 1 else 0 + hy : ∀ i t, (MB * scatM (Jr * Cc) * MA) i (lY t) = if i = lY t then 1 else 0 + hid : ∀ S t, (MB * scatM (Jr * Cc) * MA) (lY S) (lX t) = if S = t then 1 else 0 + rA : List ℕ + rB : List ℕ + rF : List ℕ + pA : ∀ {α : Type} [Fintype α] [DecidableEq α] (Xm : XMap H α), + XRoute (fun r => Xm.Φ (lab3 tv r).P) (fun r => Xm.Φ (labA r).P) (actPoint MA) + (fun φ => rcost φ rA) ∧ + XRoute (fun r => Xm.Φ (lab3 tv r).P) (fun r => Xm.Φ (labA r).P) (actPoint MAiᵀ) + (fun φ => rcost φ rA) + pB : ∀ {α : Type} [Fintype α] [DecidableEq α] (Xm : XMap H α), + XRoute (fun r => Xm.Φ (labA r).P) (fun r => Xm.Φ (labB r).P) (actPoint MB) + (fun φ => rcost φ rB) ∧ + XRoute (fun r => Xm.Φ (labA r).P) (fun r => Xm.Φ (labB r).P) (actPoint MBiᵀ) + (fun φ => rcost φ rB) + pF : ∀ {α : Type} [Fintype α] [DecidableEq α] (Xm : XMap H α), + XRoute (fun r => Xm.Φ (labB r).P) (fun r => Xm.Φ (labF r).P) id (fun φ => rcost φ rF) + +section Alg +variable {H T Sl C : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] + +namespace Phased +variable (K : Phased H T Sl C) + +/-- the product of ALL gates of the main phase (scatter with the copies eliminated). -/ +def Mt : Matrix (L3 T Sl) (L3 T Sl) ℚ := K.MB * scatM (K.Jr * K.Cc) * K.MA +/-- its inverse. -/ +def Mti : Matrix (L3 T Sl) (L3 T Sl) ℚ := K.MAi * scatMi (K.Jr * K.Cc) * K.MBi + +/-- price of one invocation: the blocks of the three phases and one block per copy. -/ +def cost (φ : ℕ → ℝ) : ℝ := + rcost φ K.rA + (∑ k, bcost φ (K.cen k).d) + rcost φ K.rB + rcost φ K.rF + +lemma im : K.Mti * K.Mt = 1 := by + unfold Mti Mt + have hB : ∀ X : Matrix (L3 T Sl) (L3 T Sl) ℚ, K.MBi * (K.MB * X) = X := fun X => by + rw [← Matrix.mul_assoc, K.hBi, Matrix.one_mul] + have hS : ∀ X : Matrix (L3 T Sl) (L3 T Sl) ℚ, + scatMi (K.Jr * K.Cc) * (scatM (K.Jr * K.Cc) * X) = X := fun X => by + rw [← Matrix.mul_assoc, scat_inv, Matrix.one_mul] + rw [Matrix.mul_assoc, Matrix.mul_assoc, Matrix.mul_assoc, hB, hS, K.hAi] + +lemma mi : K.Mt * K.Mti = 1 := mul_eq_one_comm.mp K.im + +lemma hxm : PX * K.Mt = PX := PX_mul_of (M := K.Mt) K.hx +lemma hmy : K.Mt * PY = PY := mul_PY_of (M := K.Mt) K.hy +lemma hiy : K.Mti * PY = PY := dirt_iy K.hmy K.im + +/-- **the dirt rule, forward**, for the matrices of the circuit. -/ +lemma hF : g8 K.Mti * K.Mt * g1 K.Mt = 1 + PY * K.Mt * PX := by + unfold g8 g1 + exact dirt_fwd PX_sq PY_sq PX_PY PY_PX K.hxm K.hmy K.im K.mi + +/-- **the dirt rule, backward.** -/ +lemma hB : g1i K.Mt * K.Mti * h8 K.Mt = 1 - PY * K.Mt * PX := by + unfold g1i h8 + exact dirt_bwd PX_sq PY_sq PX_PY PY_PX K.hxm K.hmy K.im K.mi + +/-- live part of the forward word before the scatter: `y -= K s`, then phase A. -/ +def f1 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint K.MA (actPoint (g1 K.Mt) u) +/-- after the scatter: phase B, then the slot rows of the inverse. -/ +def f2 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint (g8 K.Mti) (actPoint K.MB u) +/-- the same for the backward word (transposed inverses). -/ +def b1 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint K.MAiᵀ (actPoint (g1i K.Mt)ᵀ u) +def b2 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint (h8 K.Mt)ᵀ (actPoint K.MBiᵀ u) + +lemma fwd_live (u : L3 T Sl → ℂ) : + K.f2 (actPoint (scatM (K.Jr * K.Cc)) (K.f1 u)) = actPoint (1 + PY * K.Mt * PX) u := by + rw [← K.hF] + show actPoint (g8 K.Mti) (actPoint K.MB (actPoint (scatM (K.Jr * K.Cc)) + (actPoint K.MA (actPoint (g1 K.Mt) u)))) + = actPoint (g8 K.Mti * (K.MB * scatM (K.Jr * K.Cc) * K.MA) * g1 K.Mt) u + rw [actPoint_mul, actPoint_mul, actPoint_mul, actPoint_mul] + +lemma bwd_live (u : L3 T Sl → ℂ) : + K.b2 (actPoint ((scatMi (K.Jr * K.Cc))ᵀ) (K.b1 u)) + = actPoint ((1 - PY * K.Mt * PX)ᵀ) u := by + rw [← K.hB] + show actPoint (h8 K.Mt)ᵀ (actPoint K.MBiᵀ (actPoint (scatMi (K.Jr * K.Cc))ᵀ + (actPoint K.MAiᵀ (actPoint (g1i K.Mt)ᵀ u)))) + = actPoint ((g1i K.Mt * (K.MAi * scatMi (K.Jr * K.Cc) * K.MBi) * h8 K.Mt)ᵀ) u + rw [Matrix.transpose_mul, Matrix.transpose_mul, Matrix.transpose_mul, Matrix.transpose_mul, + actPoint_mul, actPoint_mul, actPoint_mul, actPoint_mul] + +lemma liveAct_glue (φ : (L3 T Sl → ℂ) → (L3 T Sl → ℂ)) (u : L3 T Sl → ℂ) (c : C → ℂ) : + liveAct φ (glue u c) = glue (φ u) c := + congrArg (fun v => glue (φ v) c) (glue_up u c) + +/-- **Scalar identity of the forward word**: `y += x`, slots restored, for ARBITRARY slot +contents (the copies are erased before and after). -/ +theorem fwd_scalar (z : Box T Sl C → ℂ) : + eraseC (liveAct K.f2 (gateS bY bC K.Jr (gateS bC bS K.Cc (liveAct K.f1 (eraseC z))))) + = shearF z := by + have h1 : liveAct K.f1 (eraseC z) = glue (K.f1 (z ∘ upE)) (fun _ => 0) := by + rw [erase_glue z, liveAct_glue] + have hs : gateS bY bC K.Jr (gateS bC bS K.Cc (glue (K.f1 (z ∘ upE)) (fun _ => 0))) ∘ upE + = actPoint (scatM (K.Jr * K.Cc)) (K.f1 (z ∘ upE)) := by + have h := scat_glue K.Jr K.Cc (glue (K.f1 (z ∘ upE)) (fun _ => 0)) rfl + rw [glue_up] at h + exact h + rw [h1] + unfold liveAct + rw [erase_of_glue, hs, K.fwd_live, act_shear K.Mt K.hid] + exact glue_shearF z + +/-- **Scalar identity of the backward word**: `x -= y`, slots restored. -/ +theorem bwd_scalar (z : Box T Sl C → ℂ) : + eraseC (liveAct K.b2 (gateS bS bC (-K.Ccᵀ) (gateS bC bY K.Jrᵀ (liveAct K.b1 (eraseC z))))) + = shearB z := by + have h1 : liveAct K.b1 (eraseC z) = glue (K.b1 (z ∘ upE)) (fun _ => 0) := by + rw [erase_glue z, liveAct_glue] + have hs : gateS bS bC (-K.Ccᵀ) (gateS bC bY K.Jrᵀ (glue (K.b1 (z ∘ upE)) (fun _ => 0))) ∘ upE + = actPoint ((scatMi (K.Jr * K.Cc))ᵀ) (K.b1 (z ∘ upE)) := by + have h := scat_glueT K.Jr K.Cc (glue (K.b1 (z ∘ upE)) (fun _ => 0)) rfl + rw [glue_up] at h + exact h + rw [h1] + unfold liveAct + rw [erase_of_glue, hs, K.bwd_live, act_shearT K.Mt K.hid] + exact glue_shearB z + +end Phased +end Alg +end +end CR +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.CR.Phased.fwd_scalar +#print axioms OAI.PowerSaving.CR.Phased.bwd_scalar diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Fourier__Main.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Fourier__Main.lean new file mode 100644 index 0000000000..9aa06b5bf2 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__Fourier__Main.lean @@ -0,0 +1,176 @@ +import Work.Fourier.Asymptotics +import OAI.Computability.FourierTransform.RegisterBounds +import Work.Fourier.Goal + +/- +Modified copy of lean/OAI/Computability/FourierTransform/Main.lean of github.com/openai/math +(commit fd4aeeb, Apache-2.0), generated by `tools/fourier/mkchain.py`. OpenAI's file itself is +unmodified in this repository and still imported. Changed for this repository, all mechanically: + * every declaration of this file (and of the other 10 copied files) has the suffix `Z` + on its name, so that it does not collide with OpenAI's original; + * OpenAI's exponent `alpha = 1 - 2/10^11` and envelope `hills` are replaced by + `alphaZ = 1 - 7474547/10^10` and `hillsZ` (Work/Fourier/Seam.lean), and the single use of + OpenAI's `hills_program` by `hillsZ_program`; + * `decimalExponent`, `decimalTime`, `TimeBounds`, `DFTGoal`, `ConvGoal` are replaced by their + `Z` versions from Work/Fourier/Goal.lean (exponent `1 - 7474546/10^10`); + * imports point to the copies. + * literal `let d : ℝ := 2/(10:ℝ)^11` -> `let d : ℝ := 7474547/(10:ℝ)^10` (alpha_thetaZ: the local constant d must equal 1 - alphaZ) + * `theorem transform_mainZ : DFTGoalZ :=`: docstring added + * `theorem convolution_mainZ : ConvGoalZ :=`: docstring added +Comments and docstrings below are OpenAI's and describe OpenAI's network, not ours. +-/ + +namespace OAI + +/-! +Exact uniform Fourier transforms and convolution. + +The construction formalizes the exact arithmetic algorithms of +*An explicit power saving for the exact discrete Fourier transform* (OpenAI). +The finite phase network originates in the complex construction of +*Integer multiplication below n log n*. + +`transform_mainZ` and `convolution_mainZ` give fixed finite RAM programs, including +preparation and index work, polynomial storage bounds, and a canonical root whose +order is computed from the input length. Each includes the paper exponent, decimal +power saving, and little-o bound. The `_order` variants also specify the root order. + +The implementation uses a smaller concrete tensor network (32 binary coordinates +per factor, 4060 triples, and a `2^50` role envelope) with a stronger saving that +implies the stated paper constants. The general rational-algebra extraction, +symbolic certificate search, circuit printer, and bounded-printer uniformization +from the synthesis appendix are outside this formalization. +-/ +namespace PowerSaving +open RAM Bench Selection Filter Asymptotics Real +noncomputable section +namespace Skies + +lemma multiplier_rangeZ : 1 < paperMultiplier ∧ paperMultiplier < paperM := by + norm_num [paperMultiplier,paperM,paperDelta,paperW] + +lemma theta_ltZ : theta < 1 := by + have h := multiplier_rangeZ + have hg : 0 by rw [speedZ,Real.rpow_one]; rfl + rw [h] at H; exact H + +lemma speed_paperZ : speedZ theta =O[atTop] paperTime := by + rw [isBigO_iff] + refine ⟨1,?_⟩ + filter_upwards [TtopZ.eventually_ge_atTop 1,QtopZ.eventually_ge_atTop 1] with n hn hh + have he : 0 (lunchZ a b N n:ℝ)) =O[atTop] decimalTimeZ := hd.isBigO + exact ⟨hp.isBigO.trans speed_paperZ,ht,ht.trans_isLittleO decimal_littleZ⟩ + +end Skies + +/-! Main results. Provide formula for the order besides the existential specification. -/ +theorem transform_main_orderZ : ∃ order solve W, + DFTProgram order solve W ∧ TimeBoundsZ W ∧ + ∀ n, 0 ⟨le_rfl,by dsimp; omega⟩) + a b,fun n hn => ⟨ho n hn,(ho n hn).symm ▸ (receipt_bound n hn).2⟩⟩ + +theorem convolution_main_orderZ : ∃ order solve W, + ConvProgram order solve W ∧ TimeBoundsZ W ∧ + ∀ n, 0 + ⟨ho n hn,(ho n hn).symm ▸ (receipt_bound _ (stretch_posZ hn)).2⟩⟩ + +/-- **The discrete Fourier transform of every length in `O(n (log n)^(1 - 7474546/10^10))`.** +OpenAI's `transform_main` (one fixed program, OpenAI's own `DFTProgram`, `paperTime` and `nlogn`) +with the decimal exponent `1 - 1/10^13` replaced by `decimalExponentZ = 1 - 7474546/10^10` +(Work/Fourier/Goal.lean). Sibling of the Walsh-Hadamard theorem `wht_main_block_B2Gp193x`: both +follow from one kernel program, `RAM.hillsZ_program` (Work/Fourier/Seam.lean). -/ +theorem transform_mainZ : DFTGoalZ := + let ⟨o,s,W,h,g,_⟩ := transform_main_orderZ + ⟨o,s,W,h,g⟩ + +/-- **Convolution of every length with the same bounds** (OpenAI's `convolution_main`, same change). -/ +theorem convolution_mainZ : ConvGoalZ := + let ⟨o,s,W,h,g,_⟩ := convolution_main_orderZ + ⟨o,s,W,h,g⟩ + +lemma matrix_definitionZ (n : ℕ) (x : Vec n) : dft n x = Matrix.mulVec (dftMatrix n) x := + rfl + +end +end PowerSaving + +end OAI diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Geom.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Geom.lean new file mode 100644 index 0000000000..eb4490af8b --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Geom.lean @@ -0,0 +1,210 @@ +import Work.GCert.Chain.NetCert +import Work.GCert.Chain.WinB +import Work.BridgeGeom.B2 + +/-! +# (key: gx-chain) THE NETWORK LEMMA (spec statement 6): the bridged word B_2 delivers a `GCert` + +GENERATED by checks/wht26/gx-chain/py/netgen.py from Work/BridgeGeom/Net.lean (section Net): +the geometry of `BG.geomBridge2`, word for word, with the windows `gwinB` (`.Xm = BG.fmapB`). + +`bridge2_gcert I hH`: for every generalised invocation package, a `GCert` on +`card Γ * (4 card T + card Sl)` live roles, label dimension `5h`, unit price +`5 * I.cost φ + card T * BG.bankPrice h φ` (unchanged). No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB RF BR GF BG +noncomputable section + +section Net +variable {H T Sl C : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] +variable (I : GInv H T Sl C) (base : T → OBase H) (l : H) + (hbase : ∀ t, I.tv t = (base t).v l) (hH : 1 ≤ Fintype.card H) +include hbase + +lemma ggeom_x01 (g : Orth (L5 H)) (t : T) : + PhiB g ∅ 1 = PhiB (RrB (base t) l (0 : Fin 4) g) (qS bs1 l) (tt (I.tv t)) := by + rw [hbase t] + exact bankT_x0 (base t) l (0 : Fin 4) g + +lemma ggeom_y01 (g : Orth (L5 H)) (t : T) : + PhiB g ∅ (1 + tt (I.tv t)) = PhiB (RrB (base t) l (0 : Fin 4) g) (qS bs1 l) 0 := by + rw [hbase t] + exact bankT_y0 (base t) l (0 : Fin 4) g + +/-- consecutive stages `c ∈ bs`, `c' ∉ bs`: `X` leaves where it enters. -/ +lemma ggeom_xx (bs : Finset (Fin 4)) (c c' : Fin 4) (hc : c ∈ bs) (hc' : c' ∉ bs) + (g : Orth (L5 H)) (t : T) : + PhiB (RrB (base t) l c g) (qS bs l) 1 + = PhiB (RrB (base t) l c' g) (qS (insert c' bs) l) (tt (I.tv t)) := by + rw [hbase t] + exact bankT_xx (base t) l bs c c' hc hc' g + +/-- consecutive stages: `Y` leaves where it enters. -/ +lemma ggeom_yy (bs : Finset (Fin 4)) (c c' : Fin 4) (hc : c ∈ bs) (hc' : c' ∉ bs) + (g : Orth (L5 H)) (t : T) : + PhiB (RrB (base t) l c g) (qS bs l) (1 + tt (I.tv t)) + = PhiB (RrB (base t) l c' g) (qS (insert c' bs) l) 0 := by + rw [hbase t] + exact bankT_yy (base t) l bs c c' hc hc' g + +/-- terminal identity of the bank pairs of the class `(g,t)`. -/ +lemma ggeom_term5 (g : Orth (L5 H)) (t : T) : + kernel (L5 H) * PhiB g ∅ (tt (I.tv t)) + = shift ((BBB (base t) g).v (Sum.inl l)) + * frame (BBB (base t) g) (univ \ {Sum.inl l}) := by + rw [hbase t] + exact class_term (base t) l g + +include hH + +/-- pair 2 before the first gate layer, `X`: ONE block of rank `2h-2`. -/ +lemma ggeom_aX2 (g : Orth (L5 H)) (t : T) : + XReach (PhiB g ∅ (tt (I.tv t))) (PhiB (RrB (base t) l (0 : Fin 4) g) (qS bs1 l) 1) + (fun φ => bcost φ (2 * Fintype.card H - 2)) := by + rw [hbase t] + exact idle_X0 (base t) l hB4 hH (0 : Fin 4) g _ (by omega) + +/-- pair 2 before the first gate layer, `Y`: ONE block of rank `2h-2`. -/ +lemma ggeom_aY2 (g : Orth (L5 H)) (t : T) : + XReach (PhiB g ∅ 0) (PhiB (RrB (base t) l (0 : Fin 4) g) (qS bs1 l) (1 + tt (I.tv t))) + (fun φ => bcost φ (2 * Fintype.card H - 2)) := by + rw [hbase t] + exact idle_Y0 (base t) l hB4 hH (0 : Fin 4) g _ (by omega) + +/-- pair 1 at the end (idle in stages 3, 4, then the last four moves), `X`: ONE block `2h+2`. -/ +lemma ggeom_fX1 (g : Orth (L5 H)) (t : T) : + XReach (PhiB (RrB (base t) l (1 : Fin 4) g) (qS bs2 l) 1) (kernel (L5 H)) + (fun φ => bcost φ (2 * Fintype.card H + 2)) := + idle_Xend (base t) l hB4 hH bs2 (1 : Fin 4) (Finset.mem_insert_self _ _) g _ + (by rw [card_bs2, Fintype.card_fin]; omega) + +/-- pair 1 at the end, `Y`: ONE block of rank `2h+2`. -/ +lemma ggeom_fY1 (g : Orth (L5 H)) (t : T) : + XReach (PhiB (RrB (base t) l (1 : Fin 4) g) (qS bs2 l) (1 + tt (I.tv t))) + (frame (BBB (base t) g) (univ \ {Sum.inl l})) + (fun φ => bcost φ (2 * Fintype.card H + 2)) := by + rw [hbase t] + exact idle_Yend (base t) l hB4 hH bs2 (1 : Fin 4) (Finset.mem_insert_self _ _) g _ + (by rw [card_bs2, Fintype.card_fin]; omega) + +/-- pair 2 after stage 4, `X`: ONE block of rank `4`. -/ +lemma ggeom_fX2 (g : Orth (L5 H)) (t : T) : + XReach (PhiB (RrB (base t) l (3 : Fin 4) g) (qS bs4 l) 1) (kernel (L5 H)) + (fun φ => bcost φ 4) := + idle_Xend (base t) l hB4 hH bs4 (3 : Fin 4) (Finset.mem_insert_self _ _) g _ + (by rw [card_bs4, Fintype.card_fin]; omega) + +/-- pair 2 after stage 4, `Y`: ONE block of rank `4`. -/ +lemma ggeom_fY2 (g : Orth (L5 H)) (t : T) : + XReach (PhiB (RrB (base t) l (3 : Fin 4) g) (qS bs4 l) (1 + tt (I.tv t))) + (frame (BBB (base t) g) (univ \ {Sum.inl l})) (fun φ => bcost φ 4) := by + rw [hbase t] + exact idle_Yend (base t) l hB4 hH bs4 (3 : Fin 4) (Finset.mem_insert_self _ _) g _ + (by rw [card_bs4, Fintype.card_fin]; omega) + +/-- **The bridged word B_2 as a term of `BR.Bridge2`**: five stages on the label space +`H ⊕ (Fin 4 × H)`, for any invocation package whose lines are the vectors of index `l` of +orthonormal bases. -/ +def ggeomBridge2 : GBridge2 H T Sl C (L5 H) (Orth (L5 H)) where + I := I + G0 := fun g => gwinB hB4 hH g ∅ + G1 := fun d => gwinB hB4 hH d (qS bs1 l) + G2 := fun d => gwinB hB4 hH d (qS bs2 l) + G3 := fun d => gwinB hB4 hH d (qS bs3 l) + G4 := fun d => gwinB hB4 hH d (qS bs4 l) + r1 := fun t => RrB (base t) l (0 : Fin 4) + r2 := fun t => RrB (base t) l (1 : Fin 4) + r3 := fun t => RrB (base t) l (2 : Fin 4) + r4 := fun t => RrB (base t) l (3 : Fin 4) + s1 := (Orth.colPerm (tauB (0 : Fin 4))).symm + s2 := (Orth.colPerm (tauB (1 : Fin 4))).symm + s3 := (Orth.colPerm (tauB (2 : Fin 4))).symm + s4 := (Orth.colPerm (tauB (3 : Fin 4))).symm + N1 := fun d => unframeM (d.1 * Matrix.fromBlocks 0 0 0 (diagI (qS bs1 l)) * d.1ᵀ) + W1 := fun d => frameM (d.1 * diagI (JB univ ∅) * d.1ᵀ) + N2 := fun d => unframeM (d.1 * Matrix.fromBlocks 0 0 0 (diagI (qS bs2 l)) * d.1ᵀ) + W2 := fun d => frameM (d.1 * diagI (JB univ ∅) * d.1ᵀ) + N3 := fun d => unframeM (d.1 * Matrix.fromBlocks 0 0 0 (diagI (qS bs3 l)) * d.1ᵀ) + W3 := fun d => frameM (d.1 * diagI (JB univ ∅) * d.1ᵀ) + N4 := fun d => unframeM (d.1 * Matrix.fromBlocks 0 0 0 (diagI (qS bs4 l)) * d.1ᵀ) + W4 := fun d => frameM (d.1 * diagI (JB univ ∅) * d.1ᵀ) + u := fun g t => (BBB (base t) g).v (Sum.inl l) + YF := fun g t => frame (BBB (base t) g) (univ \ {Sum.inl l}) + hm := two_le_card_LB hB4 hH + caX := fun φ => bcost φ (2 * Fintype.card H - 2) + caY := fun φ => bcost φ (2 * Fintype.card H - 2) + cX1 := fun φ => bcost φ (2 * Fintype.card H + 2) + cY1 := fun φ => bcost φ (2 * Fintype.card H + 2) + cX2 := fun φ => bcost φ 4 + cY2 := fun φ => bcost φ 4 + inv0 := fun g t => ⟨unframeM (g.1 * Matrix.fromBlocks (tt (I.tv t)) 0 0 (diagI ∅) * g.1ᵀ), + frameM_unframeM _⟩ + z0 := fun g => PhiB_zero_empty g + hN1 := fun d => frameM_unframeM _ + hW1 := fun d => PhiB_one d (qS bs1 l) + hN2 := fun d => frameM_unframeM _ + hW2 := fun d => PhiB_one d (qS bs2 l) + hN3 := fun d => frameM_unframeM _ + hW3 := fun d => PhiB_one d (qS bs3 l) + hN4 := fun d => frameM_unframeM _ + hW4 := fun d => PhiB_one d (qS bs4 l) + x01 := fun g t => ggeom_x01 I base l hbase g t + y01 := fun g t => ggeom_y01 I base l hbase g t + x12 := fun g t => ggeom_xx I base l hbase bs1 0 1 (Finset.mem_singleton_self _) mem1 g t + y12 := fun g t => ggeom_yy I base l hbase bs1 0 1 (Finset.mem_singleton_self _) mem1 g t + x23 := fun g t => ggeom_xx I base l hbase bs2 1 2 (Finset.mem_insert_self _ _) mem2 g t + y23 := fun g t => ggeom_yy I base l hbase bs2 1 2 (Finset.mem_insert_self _ _) mem2 g t + x34 := fun g t => ggeom_xx I base l hbase bs3 2 3 (Finset.mem_insert_self _ _) mem3 g t + y34 := fun g t => ggeom_yy I base l hbase bs3 2 3 (Finset.mem_insert_self _ _) mem3 g t + sfin := fun g => helper_fin5 g + aX2 := fun g t => ggeom_aX2 I base l hbase hH g t + aY2 := fun g t => ggeom_aY2 I base l hbase hH g t + fX1 := fun g t => ggeom_fX1 I base l hbase hH g t + fY1 := fun g t => ggeom_fY1 I base l hbase hH g t + fX2 := fun g t => ggeom_fX2 I base l hbase hH g t + fY2 := fun g t => ggeom_fY2 I base l hbase hH g t + term := fun g t => ggeom_term5 I base l hbase g t + +end Net + +section End +variable {H T Sl C : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] + +/-- an orthonormal basis through a unit vector with a zero coordinate, at any index. -/ +theorem base_ex (z : Space H) (hz : dot z z = 1) (hg : ∃ p, z p = 0) (l : H) : + ∃ A : OBase H, z = A.v l := by + obtain ⟨p, hp⟩ := hg + obtain ⟨A, k, hA⟩ := exists_base_one z hz p hp + refine ⟨reindex A (Equiv.swap k l), ?_⟩ + rw [← hA] + show A.v k = A.v (Equiv.swap k l l) + rw [Equiv.swap_apply_right] + +/-- **Generalised certificate of the bridged word B_2** for a generalised invocation package. -/ +theorem bridge2_gcert (I : GInv H T Sl C) (hH : 1 ≤ Fintype.card H) : + GCert (L5 H) (Sum.inl : BLive (Orth (L5 H)) T Sl → BRole (Orth (L5 H)) T Sl C) + (fun φ => (Fintype.card (Orth (L5 H)) : ℝ) + * (5 * I.cost φ + (Fintype.card T : ℝ) * bankPrice (Fintype.card H) φ)) := by + obtain ⟨l⟩ : Nonempty H := Fintype.card_pos_iff.mp (by omega) + have hb : ∀ t, ∃ A : OBase H, I.tv t = A.v l := + fun t => base_ex (I.tv t) (I.hunit t) (I.hgap t) l + choose base hbase using hb + exact gbridge2_certificate (ggeomBridge2 I base l hbase hH) + +end End +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.ggeomBridge2 +#print axioms OAI.PowerSaving.GX.bridge2_gcert diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__InvThm.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__InvThm.lean new file mode 100644 index 0000000000..d69fcb4992 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__InvThm.lean @@ -0,0 +1,164 @@ +import Work.GCert.Chain.Inv + +/-! +# (key: gx-chain) THE CARRIER INVOCATION THEOREM on the generalised engine: `Lab.inv` + +`CR.Phased.inv` (`Work/Carrier/PhasedInv.lean`) with subspace labels and `GRoute`. Forward word: + + erase | y -= K s (old frame 0) | free adapters to the labels of the certificate | phase A | + c += Cc s | copies down | y += Jr c | phase B | final climbs | free adapters to the old + frames | slots := slot rows of the inverse (old frame 1) | erase + +The backward word is the transposed inverse, gate by gate, on the same labels. The scalar +identities are `Scal.fwd_scalar` / `Scal.bwd_scalar` (those of `CR.Phased`). + +No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB BR CR GF RF +noncomputable section + +section Thm +variable {H T Sl C : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] +variable {α : Type} [Fintype α] [DecidableEq α] +variable {S : Scal T Sl C} (L : Lab H S) (W : GWin H α) + +/-- **Forward word on clean frames.** -/ +theorem Lab.fwd_erased (c0 c1 : C → CMat α) : + GRoute (iin W.Xm L.tv (fun _ : Sl => W.Xm.Φ 0) c0) + (iout W.Xm L.tv (fun _ : Sl => W.Xm.Φ 1) c1) shearF L.cost := by + have a1 : GRoute (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) + (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) + (actPoint (g1 S.Mt)) (fun _ => 0) := + GRoute.gate (g1 S.Mt) _ _ (fun i j hij => by + by_cases e : i = j + · subst e; rfl + · obtain ⟨h1, h2⟩ := offdiag_x (g1_x S.Mt).1 (g1_x S.Mt).2 hij e + exact start_frames W.Xm L.tv i j h1 h2) + have b3 : GRoute (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) + (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) + (actPoint (g8 S.Mti)) (fun _ => 0) := + GRoute.gate (g8 S.Mti) _ _ (fun i j hij => by + by_cases e : i = j + · subst e; rfl + · have f := g8_facts S.hiy + obtain ⟨h1, h2, h3⟩ := offdiag_s f.1 f.2.1 f.2.2 hij e + exact end_old W.Xm L.tv i j h1 h2 h3) + have seg1 : GRoute (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) (fun r => W.X.Φ (L.labA r)) + S.f1 (fun φ => rcost φ L.rA) := + ((a1.trans (L.ad0 W)).trans (L.pA W.X W.big).1).cast (fun φ => by simp) + have seg2 : GRoute (fun r => W.X.Φ (L.labA r)) (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) + S.f2 (fun φ => rcost φ L.rB + rcost φ L.rF) := + ((((L.pB W.X W.big).1.trans (L.pF W.X W.big)).trans (L.adF W)).trans b3).cast + (fun φ => by simp) + have e0 : GRoute (iin W.Xm L.tv (fun _ : Sl => W.Xm.Φ 0) c0) + (glue (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) (fun k => W.X.Φ (L.cen k))) + eraseC (fun _ => 0) := + GRoute.ofX (xerase (fun t => rfl) (fun t => rfl) (fun q => rfl)) + have L1 := glift_live (fun k => W.X.Φ (L.cen k)) seg1 + have m1 : GRoute (glue (fun r => W.X.Φ (L.labA r)) (fun k => W.X.Φ (L.cen k))) + (glue (fun r => W.X.Φ (L.labA r)) (fun k => W.X.Φ (L.cen k))) + (fun z => addBlk bC (ap S.Cc (z ∘ bS)) z) (fun _ => 0) := + GRoute.ofX (xgate_shear bC bS bS_inj S.Cc (fun k q h => congrArg W.X.Φ (L.hAc k q h))) + have m2 := L.cdown W (fun r => W.X.Φ (L.labA r)) + have m3 : GRoute (glue (fun r => W.X.Φ (L.labA r)) (fun _ : C => W.X.Φ L.z0)) + (glue (fun r => W.X.Φ (L.labA r)) (fun _ : C => W.X.Φ L.z0)) + (fun z => addBlk bY (ap S.Jr (z ∘ bC)) z) (fun _ => 0) := + GRoute.ofX (xgate_shear bY bC bC_inj S.Jr (fun t k _ => congrArg W.X.Φ (L.hAy t))) + have L2 := glift_live (fun _ : C => W.X.Φ L.z0) seg2 + have e1 : GRoute (glue (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) (fun _ : C => W.X.Φ L.z0)) + (iout W.Xm L.tv (fun _ : Sl => W.Xm.Φ 1) c1) eraseC (fun _ => 0) := + GRoute.ofX (xerase (fun t => rfl) (fun t => rfl) (fun q => rfl)) + have tot := (((((e0.trans L1).trans m1).trans m2).trans m3).trans L2).trans e1 + refine (tot.castg (g' := shearF) (funext fun z => S.fwd_scalar z)).cast (fun φ => ?_) + simp only [Lab.cost, zero_add, add_zero] + ring + +/-- **Backward word on clean frames**: the transposed inverse gates, same labels; the copies +start at the zero frame and climb. -/ +theorem Lab.bwd_erased (c0 c1 : C → CMat α) : + GRoute (iin W.Xm L.tv (fun _ : Sl => W.Xm.Φ 0) c0) + (iout W.Xm L.tv (fun _ : Sl => W.Xm.Φ 1) c1) shearB L.cost := by + have a1 : GRoute (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) + (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) + (actPoint (g1i S.Mt)ᵀ) (fun _ => 0) := + GRoute.gate (g1i S.Mt)ᵀ _ _ (fun i j hij => by + by_cases e : i = j + · subst e; rfl + · have hij' : g1i S.Mt j i ≠ 0 := hij + obtain ⟨h1, h2⟩ := offdiag_x (g1i_x S.Mt).1 (g1i_x S.Mt).2 hij' (Ne.symm e) + exact start_frames W.Xm L.tv i j h2 h1) + have b3 : GRoute (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) + (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) + (actPoint (h8 S.Mt)ᵀ) (fun _ => 0) := + GRoute.gate (h8 S.Mt)ᵀ _ _ (fun i j hij => by + by_cases e : i = j + · subst e; rfl + · have hij' : h8 S.Mt j i ≠ 0 := hij + have f := h8_facts S.hmy + obtain ⟨h1, h2, h3⟩ := offdiag_s f.1 f.2.1 f.2.2 hij' (Ne.symm e) + exact (end_old W.Xm L.tv j i h1 h2 h3).symm) + have seg1 : GRoute (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) (fun r => W.X.Φ (L.labA r)) + S.b1 (fun φ => rcost φ L.rA) := + ((a1.trans (L.ad0 W)).trans (L.pA W.X W.big).2).cast (fun φ => by simp) + have seg2 : GRoute (fun r => W.X.Φ (L.labA r)) (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) + S.b2 (fun φ => rcost φ L.rB + rcost φ L.rF) := + ((((L.pB W.X W.big).2.trans (L.pF W.X W.big)).trans (L.adF W)).trans b3).cast + (fun φ => by simp) + have e0 : GRoute (iin W.Xm L.tv (fun _ : Sl => W.Xm.Φ 0) c0) + (glue (fun r : L3 T Sl => W.Xm.Φ (lab3 L.tv r).P) (fun _ : C => W.X.Φ L.z0)) + eraseC (fun _ => 0) := + GRoute.ofX (xerase (fun t => rfl) (fun t => rfl) (fun q => rfl)) + have L1 := glift_live (fun _ : C => W.X.Φ L.z0) seg1 + have m1 : GRoute (glue (fun r => W.X.Φ (L.labA r)) (fun _ : C => W.X.Φ L.z0)) + (glue (fun r => W.X.Φ (L.labA r)) (fun _ : C => W.X.Φ L.z0)) + (fun z => addBlk bC (ap S.Jrᵀ (z ∘ bY)) z) (fun _ => 0) := + GRoute.ofX (xgate_shear bC bY bY_inj S.Jrᵀ (fun k t _ => (congrArg W.X.Φ (L.hAy t)).symm)) + have m2 := L.cup W (fun r => W.X.Φ (L.labA r)) + have m3 : GRoute (glue (fun r => W.X.Φ (L.labA r)) (fun k => W.X.Φ (L.cen k))) + (glue (fun r => W.X.Φ (L.labA r)) (fun k => W.X.Φ (L.cen k))) + (fun z => addBlk bS (ap (-S.Ccᵀ) (z ∘ bC)) z) (fun _ => 0) := + GRoute.ofX (xgate_shear bS bC bC_inj (-S.Ccᵀ) + (fun q k h => (congrArg W.X.Φ (L.hAc k q (ne_of_negT S.Cc h))).symm)) + have L2 := glift_live (fun k => W.X.Φ (L.cen k)) seg2 + have e1 : GRoute (glue (fun r : L3 T Sl => W.Xm.Φ (labE L.tv r)) (fun k => W.X.Φ (L.cen k))) + (iout W.Xm L.tv (fun _ : Sl => W.Xm.Φ 1) c1) eraseC (fun _ => 0) := + GRoute.ofX (xerase (fun t => rfl) (fun t => rfl) (fun q => rfl)) + have tot := (((((e0.trans L1).trans m1).trans m2).trans m3).trans L2).trans e1 + refine (tot.castg (g' := shearB) (funext fun z => S.bwd_scalar z)).cast (fun φ => ?_) + simp only [Lab.cost, zero_add, add_zero] + ring + +/-- **THE CARRIER INVOCATION THEOREM on the generalised engine.** The two halves of a +certificate are an invocation package for the bridged network, with the price `L.cost`. -/ +def Lab.inv : GInv H T Sl C where + tv := L.tv + hunit := L.hunit + hgap := L.hgap + cost := L.cost + fwd := fun W N0 Wn hN hW Z c0 c1 => + gdirty_of_erased W.Xm L.tv N0 Wn hN hW Z c0 c1 (L.fwd_erased W c0 c1) + (shearF_comm (fun _ => 1) (fun q => N0 * Z q) (fun _ => 1)) + bwd := fun W N0 Wn hN hW Z c0 c1 => + gdirty_of_erased W.Xm L.tv N0 Wn hN hW Z c0 c1 (L.bwd_erased W c0 c1) + (shearB_comm (fun _ => 1) (fun q => N0 * Z q) (fun _ => 1)) + +@[simp] lemma Lab.inv_cost (φ : ℕ → ℝ) : L.inv.cost φ = L.cost φ := rfl +@[simp] lemma Lab.inv_tv : L.inv.tv = L.tv := rfl + +end Thm +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.Lab.fwd_erased +#print axioms OAI.PowerSaving.GX.Lab.bwd_erased +#print axioms OAI.PowerSaving.GX.Lab.inv diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetCert.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetCert.lean new file mode 100644 index 0000000000..6336ba0766 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetCert.lean @@ -0,0 +1,157 @@ +import Work.GCert.Chain.NetStage +import Work.GFrame.Top.Assemble + +/-! +# (key: gx-chain) The bridged word B_2 on the generalised engine: the certificate `GCert` + +GENERATED by checks/wht26/gx-chain/py/netgen.py from Work/Bridge/Cert.lean (section Net). +`gbridge2_certificate`: a `GCert` on the live roles `BLive Γ T Sl` with price `card Γ * N.unit φ`. +The gate layers, the idle climbs and the exchange are the old routes (`GRoute.ofX`). No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB RF BR GF +noncomputable section + +section Net +variable {H T Sl C α Γ : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] + [Fintype Γ] [DecidableEq Γ] +variable (N : GBridge2 H T Sl C α Γ) + +/-- gate layer A, after stage 1 and the first idle climb of pair 2: twins have equal frames. -/ +lemma GBridge2.gateA : XRoute N.S3 N.S3 (gsc pAB kA) (fun _ => 0) := by + refine gateP pAB kA N.S3 ?_ + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) hk + · rfl + · exact (hk rfl).elim + · exact (hk rfl).elim + · rfl + · exact (hk rfl).elim + · exact (hk rfl).elim + +/-- gate layer B, after stage 2 and the second idle climb of pair 2. -/ +lemma GBridge2.gateB : XRoute N.S5 N.S5 (gsc pAB kB) (fun _ => 0) := by + refine gateP pAB kB N.S5 ?_ + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) hk + · exact N.x23 g t + · exact (hk rfl).elim + · exact (hk rfl).elim + · exact (N.y23 g t).symm + · exact (hk rfl).elim + · exact (hk rfl).elim + +/-- gate layer C, after the final climbs. -/ +lemma GBridge2.gateC : XRoute N.S8 N.S8 (gsc pC kCc) (fun _ => 0) := by + refine gateP pC kCc N.S8 ?_ + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) hk + · exact (hk rfl).elim + · rfl + · rfl + · exact (hk rfl).elim + · exact (hk rfl).elim + · exact (hk rfl).elim + +/-- the free shifts at the end. -/ +def GBridge2.corr : BRole Γ T Sl C → Space α := + mkB (fun _ _ => 0) (fun g t => N.u g t) (fun _ _ => 0) (fun g t => N.u g t) + (fun _ _ => 0) (fun _ _ => 0) + +def GBridge2.S9 : BRole Γ T Sl C → CMat α := fun r => shift (N.corr r) * N.S8 r + +/-- the whole word before the exchange: five stages, three idle-climb layers, three gate +layers. -/ +lemma GBridge2.route : + GRoute N.S0 N.S8 chain (fun φ => (Fintype.card Γ : ℝ) * N.unit φ) := by + have R := ((((((((((N.stage0.trans N.stage1).trans (GRoute.ofX N.climbA)).trans + (GRoute.ofX N.gateA)).trans N.stage2).trans (GRoute.ofX N.climbB)).trans + (GRoute.ofX N.gateB)).trans N.stage3).trans N.stage4).trans + (GRoute.ofX N.fin)).trans (GRoute.ofX N.gateC)) + refine (R.castg ?_).cast (fun φ => ?_) + · rfl + · simp only [GBridge2.unit] + ring + +/-- **The scratch certificate of the bridged five-stage network with shared helper sets**, +in whole blocks, with its exact price for every price list. -/ +theorem gbridge2_certificate : + GCert α (Sum.inl : BLive Γ T Sl → BRole Γ T Sl C) + (fun φ => (Fintype.card Γ : ℝ) * N.unit φ) := by + have R2 : GRoute N.S8 N.S9 id (fun _ => 0) := GRoute.shifts N.hm N.S8 N.corr + have R3 : GRoute N.S9 (fun r => N.S9 (bpull r)) (actPoint brecM) (fun _ => 0) := + GRoute.gate brecM N.S9 _ (fun i j h => by + have hj : j = bpull i := by + by_contra hne + exact h (by simp [brecM, hne]) + rw [hj]) + have Rt := ((N.route.trans R2).trans R3).cast (c' := fun φ => (Fintype.card Γ : ℝ) * N.unit φ) + (fun φ => by first | ring | simp) + have hSinv : ∀ r, ∃ M, N.S0 r * M = 1 := by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact N.inv0 g t + · refine ⟨1, ?_⟩ + show (N.G0 g).Xm.Φ 0 * 1 = 1 + rw [N.z0, Matrix.mul_one] + · exact N.inv0 g t + · refine ⟨1, ?_⟩ + show (N.G0 g).Xm.Φ 0 * 1 = 1 + rw [N.z0, Matrix.mul_one] + · exact ⟨1, Matrix.mul_one _⟩ + · exact ⟨1, Matrix.mul_one _⟩ + have hT : ∀ l : BLive Γ T Sl, N.S9 (bpull (Sum.inl l)) = kernel α * N.S0 (Sum.inl l) := by + rintro (((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩) + · show shift (N.u g t) * N.YF g t = kernel α * (N.G0 g).Xm.Φ (tt (N.I.tv t)) + exact (N.term g t).symm + · show shift (0 : Space α) * kernel α = kernel α * (N.G0 g).Xm.Φ 0 + rw [shift_zero, Matrix.one_mul, N.z0, Matrix.mul_one] + · show shift (N.u g t) * N.YF g t = kernel α * (N.G0 g).Xm.Φ (tt (N.I.tv t)) + exact (N.term g t).symm + · show shift (0 : Space α) * kernel α = kernel α * (N.G0 g).Xm.Φ 0 + rw [shift_zero, Matrix.one_mul, N.z0, Matrix.mul_one] + · show shift (0 : Space α) * kernel α = kernel α * 1 + rw [shift_zero, Matrix.one_mul, Matrix.mul_one] + have hg : ∀ x : BRole Γ T Sl C → ℂ, + (∀ s, (∀ l : BLive Γ T Sl, (Sum.inl l : BRole Γ T Sl C) ≠ s) → x s = 0) → + ∀ l : BLive Γ T Sl, + (actPoint brecM ∘ (id ∘ chain)) x (Sum.inl l) = x (Sum.inl l) := by + intro x _ l + change actPoint brecM (chain x) (Sum.inl l) = _ + rw [actPoint_brecM] + rcases l with (((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩) + · show ((1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inl (Sum.inr (g,t))))) = _ + rw [chain_eq] + show ((1:ℚ):ℂ) * x (kX1 (g,t)) = x (kX1 (g,t)) + first | (push_cast; ring) | simp + · show ((-1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inl (Sum.inl (g,t))))) = _ + rw [chain_eq] + show ((-1:ℚ):ℂ) * (-x (kY1 (g,t))) = x (kY1 (g,t)) + first | (push_cast; ring) | simp + · show ((1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inr (Sum.inr (g,t))))) = _ + rw [chain_eq] + show ((1:ℚ):ℂ) * x (kX2 (g,t)) = x (kX2 (g,t)) + first | (push_cast; ring) | simp + · show ((-1:ℚ):ℂ) * chain x (Sum.inl (Sum.inl (Sum.inr (Sum.inl (g,t))))) = _ + rw [chain_eq] + show ((-1:ℚ):ℂ) * (-x (kY2 (g,t))) = x (kY2 (g,t)) + first | (push_cast; ring) | simp + · show ((1:ℚ):ℂ) * chain x (Sum.inl (Sum.inr (g,q))) = _ + rw [chain_eq] + show ((1:ℚ):ℂ) * x (kS (g,q)) = x (kS (g,q)) + first | (push_cast; ring) | simp + exact gcert_of_groute (Sum.inl : BLive Γ T Sl → BRole Γ T Sl C) N.S0 + (fun r => N.S9 (bpull r)) _ _ Rt hSinv hg hT + +end Net + +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.GBridge2.route +#print axioms OAI.PowerSaving.GX.gbridge2_certificate diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetDef.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetDef.lean new file mode 100644 index 0000000000..c13042eb43 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetDef.lean @@ -0,0 +1,157 @@ +import Work.GCert.Chain.Stage + +/-! +# (key: gx-chain) The bridged five-stage word B_2 on the generalised engine: data and frames + +GENERATED by checks/wht26/gx-chain/py/netgen.py from Work/Bridge/Net.lean (`BR.Bridge2`): the +invocation is a `GInv`, the frame maps of the stages are windows `GWin` (`G0 .. G4`; the old +frame map of a window is `.Xm`). Everything else word for word. No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB RF BR GF +noncomputable section + +/-- See the file header. Fields in the style of `RF.Fold3S`; stages are numbered 0 to 4. -/ +structure GBridge2 (H T Sl C α Γ : Type) [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] where + /-- the invocation (for a block circuit `X`: `X.inv`). -/ + I : GInv H T Sl C + /-- frame maps of the invocations of the five stages. -/ + G0 : Γ → GWin H α + G1 : Γ → GWin H α + G2 : Γ → GWin H α + G3 : Γ → GWin H α + G4 : Γ → GWin H α + /-- the class `(g,t)` is served by the invocation `g` in stage 0 and `r_l t g` in stage `l`. -/ + r1 : T → Γ ≃ Γ + r2 : T → Γ ≃ Γ + r3 : T → Γ ≃ Γ + r4 : T → Γ ≃ Γ + /-- the invocation `d` of stage `l` uses the helper set (and the copies) `s_l d`. -/ + s1 : Γ ≃ Γ + s2 : Γ ≃ Γ + s3 : Γ ≃ Γ + s4 : Γ ≃ Γ + /-- inverse of the frame of the base, and frame of the window, of every invocation. -/ + N1 : Γ → CMat α + W1 : Γ → CMat α + N2 : Γ → CMat α + W2 : Γ → CMat α + N3 : Γ → CMat α + W3 : Γ → CMat α + N4 : Γ → CMat α + W4 : Γ → CMat α + u : Γ → T → Space α + YF : Γ → T → CMat α + hm : 2 ≤ Fintype.card α + /-- prices of the idle climbs, for every price list. B_2 with merged climbs: + `caX = caY = fun φ => bcost φ (2h-2)`, `cX1 = cY1 = fun φ => bcost φ (2h+2)`, + `cX2 = cY2 = fun φ => bcost φ 4`. -/ + caX : (ℕ → ℝ) → ℝ + caY : (ℕ → ℝ) → ℝ + cX1 : (ℕ → ℝ) → ℝ + cY1 : (ℕ → ℝ) → ℝ + cX2 : (ℕ → ℝ) → ℝ + cY2 : (ℕ → ℝ) → ℝ + inv0 : ∀ g t, ∃ N : CMat α, (G0 g).Xm.Φ (tt (I.tv t)) * N = 1 + z0 : ∀ g, (G0 g).Xm.Φ 0 = 1 + hN1 : ∀ d, (G1 d).Xm.Φ 0 * N1 d = 1 + hW1 : ∀ d, (G1 d).Xm.Φ 1 = W1 d * (G1 d).Xm.Φ 0 + hN2 : ∀ d, (G2 d).Xm.Φ 0 * N2 d = 1 + hW2 : ∀ d, (G2 d).Xm.Φ 1 = W2 d * (G2 d).Xm.Φ 0 + hN3 : ∀ d, (G3 d).Xm.Φ 0 * N3 d = 1 + hW3 : ∀ d, (G3 d).Xm.Φ 1 = W3 d * (G3 d).Xm.Φ 0 + hN4 : ∀ d, (G4 d).Xm.Φ 0 * N4 d = 1 + hW4 : ∀ d, (G4 d).Xm.Φ 1 = W4 d * (G4 d).Xm.Φ 0 + /-- the bank frames a stage leaves are the bank frames the next stage starts from. -/ + x01 : ∀ g t, (G0 g).Xm.Φ 1 = (G1 (r1 t g)).Xm.Φ (tt (I.tv t)) + y01 : ∀ g t, (G0 g).Xm.Φ (1 + tt (I.tv t)) = (G1 (r1 t g)).Xm.Φ 0 + x12 : ∀ g t, (G1 (r1 t g)).Xm.Φ 1 = (G2 (r2 t g)).Xm.Φ (tt (I.tv t)) + y12 : ∀ g t, (G1 (r1 t g)).Xm.Φ (1 + tt (I.tv t)) = (G2 (r2 t g)).Xm.Φ 0 + x23 : ∀ g t, (G2 (r2 t g)).Xm.Φ 1 = (G3 (r3 t g)).Xm.Φ (tt (I.tv t)) + y23 : ∀ g t, (G2 (r2 t g)).Xm.Φ (1 + tt (I.tv t)) = (G3 (r3 t g)).Xm.Φ 0 + x34 : ∀ g t, (G3 (r3 t g)).Xm.Φ 1 = (G4 (r4 t g)).Xm.Φ (tt (I.tv t)) + y34 : ∀ g t, (G3 (r3 t g)).Xm.Φ (1 + tt (I.tv t)) = (G4 (r4 t g)).Xm.Φ 0 + /-- the five windows of a helper set make up the kernel. -/ + sfin : ∀ g, W4 (s4.symm g) * (W3 (s3.symm g) * (W2 (s2.symm g) * + (W1 (s1.symm g) * (G0 g).Xm.Φ 1))) = kernel α + /-- pair 2, idle in stages 0 and 1: ONE block from its start frame to the frame of its + twin after stage 1. -/ + aX2 : ∀ g t, XReach ((G0 g).Xm.Φ (tt (I.tv t))) ((G1 (r1 t g)).Xm.Φ 1) caX + aY2 : ∀ g t, XReach ((G0 g).Xm.Φ 0) ((G1 (r1 t g)).Xm.Φ (1 + tt (I.tv t))) caY + /-- pair 1, idle in stages 3 and 4: ONE block from its frame after stage 2 to the end. -/ + fX1 : ∀ g t, XReach ((G2 (r2 t g)).Xm.Φ 1) (kernel α) cX1 + fY1 : ∀ g t, XReach ((G2 (r2 t g)).Xm.Φ (1 + tt (I.tv t))) (YF g t) cY1 + /-- pair 2 after stage 4: ONE final block. -/ + fX2 : ∀ g t, XReach ((G4 (r4 t g)).Xm.Φ 1) (kernel α) cX2 + fY2 : ∀ g t, XReach ((G4 (r4 t g)).Xm.Φ (1 + tt (I.tv t))) (YF g t) cY2 + term : ∀ g t, kernel α * (G0 g).Xm.Φ (tt (I.tv t)) = shift (u g t) * YF g t + +section Net +variable {H T Sl C α Γ : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] + [Fintype Γ] [DecidableEq Γ] +variable (N : GBridge2 H T Sl C α Γ) + +/-- price of the blocks of one unit (one element of `Γ`): five invocations and the idle +climbs of the four bank roles of every class. -/ +def GBridge2.unit (φ : ℕ → ℝ) : ℝ := + 5 * N.I.cost φ + (Fintype.card T : ℝ) * ((N.caX φ + N.caY φ) + + 2 * bcost φ (Fintype.card H - 1) + + (N.cX1 φ + N.cY1 φ) + (N.cX2 φ + N.cY2 φ)) + +/-- the bank index of stage 0: the class `(g,t)` belongs to the invocation `g`. -/ +abbrev bid (Γ T : Type) : T → Γ ≃ Γ := fun _ => Equiv.refl Γ + +/-! bank frames of the class `(g,t)`: `xi l`, `yi l` at the START of stage `l`; `xo l`, +`yo l` at the END of stage `l` (only where no next stage follows on that pair). -/ +def GBridge2.xi0 (g : Γ) (t : T) : CMat α := (N.G0 g).Xm.Φ (tt (N.I.tv t)) +def GBridge2.yi0 (g : Γ) (t : T) : CMat α := (N.G0 g).Xm.Φ 0 +def GBridge2.xi1 (g : Γ) (t : T) : CMat α := (N.G1 (N.r1 t g)).Xm.Φ (tt (N.I.tv t)) +def GBridge2.yi1 (g : Γ) (t : T) : CMat α := (N.G1 (N.r1 t g)).Xm.Φ 0 +def GBridge2.xi2 (g : Γ) (t : T) : CMat α := (N.G2 (N.r2 t g)).Xm.Φ (tt (N.I.tv t)) +def GBridge2.yi2 (g : Γ) (t : T) : CMat α := (N.G2 (N.r2 t g)).Xm.Φ 0 +def GBridge2.xo2 (g : Γ) (t : T) : CMat α := (N.G2 (N.r2 t g)).Xm.Φ 1 +def GBridge2.yo2 (g : Γ) (t : T) : CMat α := (N.G2 (N.r2 t g)).Xm.Φ (1 + tt (N.I.tv t)) +def GBridge2.xi3 (g : Γ) (t : T) : CMat α := (N.G3 (N.r3 t g)).Xm.Φ (tt (N.I.tv t)) +def GBridge2.yi3 (g : Γ) (t : T) : CMat α := (N.G3 (N.r3 t g)).Xm.Φ 0 +def GBridge2.xi4 (g : Γ) (t : T) : CMat α := (N.G4 (N.r4 t g)).Xm.Φ (tt (N.I.tv t)) +def GBridge2.yi4 (g : Γ) (t : T) : CMat α := (N.G4 (N.r4 t g)).Xm.Φ 0 +def GBridge2.xo4 (g : Γ) (t : T) : CMat α := (N.G4 (N.r4 t g)).Xm.Φ 1 +def GBridge2.yo4 (g : Γ) (t : T) : CMat α := (N.G4 (N.r4 t g)).Xm.Φ (1 + tt (N.I.tv t)) + +/-- helper slots after the stages 0, 1, 2, 3, 4 (at the start: `cOne Γ Sl α`). -/ +def GBridge2.Z1 : Γ → Sl → CMat α := fun g _ => (N.G0 g).Xm.Φ 1 +def GBridge2.Z2 : Γ → Sl → CMat α := fun g q => N.W1 (N.s1.symm g) * N.Z1 g q +def GBridge2.Z3 : Γ → Sl → CMat α := fun g q => N.W2 (N.s2.symm g) * N.Z2 g q +def GBridge2.Z4 : Γ → Sl → CMat α := fun g q => N.W3 (N.s3.symm g) * N.Z3 g q +def GBridge2.Z5 : Γ → Sl → CMat α := fun g q => N.W4 (N.s4.symm g) * N.Z4 g q + +/-- frames: at the start; after stage 0; after stage 1; after the first idle climb of pair 2 +(first gate layer here); after stage 2; after the second idle climb of pair 2 (second gate +layer here); after stage 3; after stage 4; after the final climbs (third gate layer here). -/ +def GBridge2.S0 : BRole Γ T Sl C → CMat α := mkB N.xi0 N.yi0 N.xi0 N.yi0 (cOne Γ Sl α) (cOne Γ C α) +def GBridge2.S1 : BRole Γ T Sl C → CMat α := mkB N.xi1 N.yi1 N.xi0 N.yi0 N.Z1 (cOne Γ C α) +def GBridge2.S2 : BRole Γ T Sl C → CMat α := mkB N.xi2 N.yi2 N.xi0 N.yi0 N.Z2 (cOne Γ C α) +def GBridge2.S3 : BRole Γ T Sl C → CMat α := mkB N.xi2 N.yi2 N.xi2 N.yi2 N.Z2 (cOne Γ C α) +def GBridge2.S4 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xi2 N.yi2 N.Z3 (cOne Γ C α) +def GBridge2.S5 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xi3 N.yi3 N.Z3 (cOne Γ C α) +def GBridge2.S6 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xi4 N.yi4 N.Z4 (cOne Γ C α) +def GBridge2.S7 : BRole Γ T Sl C → CMat α := mkB N.xo2 N.yo2 N.xo4 N.yo4 N.Z5 (cOne Γ C α) +def GBridge2.S8 : BRole Γ T Sl C → CMat α := + mkB (fun _ _ => kernel α) N.YF (fun _ _ => kernel α) N.YF (fun _ _ => kernel α) (cOne Γ C α) + + +end Net +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.GBridge2.unit diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetStage.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetStage.lean new file mode 100644 index 0000000000..670f4c6a84 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__NetStage.lean @@ -0,0 +1,186 @@ +import Work.GCert.Chain.NetDef + +/-! +# (key: gx-chain) The bridged word B_2 on the generalised engine: the five stages and the idle climbs + +GENERATED by checks/wht26/gx-chain/py/netgen.py from Work/Bridge/Net.lean. The stages are +`GRoute`s (`gistage_fwd` / `gistage_bwd`, `gblift1` / `gblift2`); the idle climbs of the bank +roles are the OLD block routes, unchanged. No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB RF BR GF +noncomputable section + +section Net +variable {H T Sl C α Γ : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] [Fintype α] [DecidableEq α] + [Fintype Γ] [DecidableEq Γ] +variable (N : GBridge2 H T Sl C α Γ) + +/-- stage 0: forward on pair 1, every helper set starts at the matrix `1`. -/ +lemma GBridge2.stage0 : + GRoute N.S0 N.S1 (lift1 GF) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + have h := gistage_fwd N.I (bid Γ T) (Equiv.refl Γ) N.G0 (fun _ => 1) (fun g => (N.G0 g).Xm.Φ 1) + (fun d => by rw [N.z0, Matrix.mul_one]) (fun d => by rw [N.z0, Matrix.mul_one]) + (cOne Γ Sl α) (cOne Γ C α) (cOne Γ C α) + have e : bOut N.I.tv (bid Γ T) (fun d => (N.G0 d).Xm) + (fun g (q : Sl) => (N.G0 ((Equiv.refl Γ).symm g)).Xm.Φ 1 * cOne Γ Sl α g q) (cOne Γ C α) + = mkS N.xi1 N.yi1 N.Z1 (cOne Γ C α) := by + funext r + rcases r with (((⟨g,t⟩|⟨g,t⟩)|⟨g,q⟩)|⟨g,c⟩) + · exact N.x01 g t + · exact N.y01 g t + · show (N.G0 g).Xm.Φ 1 * 1 = (N.G0 g).Xm.Φ 1 + rw [Matrix.mul_one] + · rfl + have h' : GRoute (bIn N.I.tv (bid Γ T) (fun d => (N.G0 d).Xm) (cOne Γ Sl α) (cOne Γ C α)) + (mkS N.xi1 N.yi1 N.Z1 (cOne Γ C α)) GF (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + rw [← e] + exact h + exact gblift1 N.xi0 N.yi0 h' + +/-- stage 1: backward on pair 1; the helper set `g` serves the invocation `s1⁻¹ g`. -/ +lemma GBridge2.stage1 : + GRoute N.S1 N.S2 (lift1 GB) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + have h := gistage_bwd N.I N.r1 N.s1 N.G1 N.N1 N.W1 N.hN1 N.hW1 N.Z1 (cOne Γ C α) (cOne Γ C α) + have e : bOut N.I.tv N.r1 (fun d => (N.G1 d).Xm) (fun g q => N.W1 (N.s1.symm g) * N.Z1 g q) (cOne Γ C α) + = mkS N.xi2 N.yi2 N.Z2 (cOne Γ C α) := by + funext r + rcases r with (((⟨g,t⟩|⟨g,t⟩)|⟨g,q⟩)|⟨g,c⟩) + · exact N.x12 g t + · exact N.y12 g t + · rfl + · rfl + have h' : GRoute (bIn N.I.tv N.r1 (fun d => (N.G1 d).Xm) N.Z1 (cOne Γ C α)) + (mkS N.xi2 N.yi2 N.Z2 (cOne Γ C α)) GB (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + rw [← e] + exact h + exact gblift1 N.xi0 N.yi0 h' + +/-- stage 2: forward on pair 1. -/ +lemma GBridge2.stage2 : + GRoute N.S3 N.S4 (lift1 GF) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := + gblift1 N.xi2 N.yi2 + (gistage_fwd N.I N.r2 N.s2 N.G2 N.N2 N.W2 N.hN2 N.hW2 N.Z2 (cOne Γ C α) (cOne Γ C α)) + +/-- stage 3: backward on pair 2. -/ +lemma GBridge2.stage3 : + GRoute N.S5 N.S6 (lift2 GB) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + have h := gistage_bwd N.I N.r3 N.s3 N.G3 N.N3 N.W3 N.hN3 N.hW3 N.Z3 (cOne Γ C α) (cOne Γ C α) + have e : bOut N.I.tv N.r3 (fun d => (N.G3 d).Xm) (fun g q => N.W3 (N.s3.symm g) * N.Z3 g q) (cOne Γ C α) + = mkS N.xi4 N.yi4 N.Z4 (cOne Γ C α) := by + funext r + rcases r with (((⟨g,t⟩|⟨g,t⟩)|⟨g,q⟩)|⟨g,c⟩) + · exact N.x34 g t + · exact N.y34 g t + · rfl + · rfl + have h' : GRoute (bIn N.I.tv N.r3 (fun d => (N.G3 d).Xm) N.Z3 (cOne Γ C α)) + (mkS N.xi4 N.yi4 N.Z4 (cOne Γ C α)) GB (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := by + rw [← e] + exact h + exact gblift2 N.xo2 N.yo2 h' + +/-- stage 4: forward on pair 2. -/ +lemma GBridge2.stage4 : + GRoute N.S6 N.S7 (lift2 GF) (fun φ => (Fintype.card Γ : ℝ) * N.I.cost φ) := + gblift2 N.xo2 N.yo2 + (gistage_fwd N.I N.r4 N.s4 N.G4 N.N4 N.W4 N.hN4 N.hW4 N.Z4 (cOne Γ C α) (cOne Γ C α)) + +/-- first idle climb of pair 2 (stages 0 and 1 in ONE block per role), to the frames of +pair 1 after stage 1. -/ +lemma GBridge2.climbA : + XRoute N.S2 N.S3 id (fun φ => (Fintype.card Γ : ℝ) * + ((Fintype.card T : ℝ) * (N.caX φ + N.caY φ))) := by + have H1 := XRoute.reach_all N.S2 N.S3 + (mkB (fun _ _ _ => 0) (fun _ _ _ => 0) (fun _ _ => N.caX) + (fun _ _ => N.caY) (fun _ _ _ => 0) (fun _ _ _ => 0)) (by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact XReach.refl _ + · exact XReach.refl _ + · show XReach ((N.G0 g).Xm.Φ (tt (N.I.tv t))) ((N.G2 (N.r2 t g)).Xm.Φ (tt (N.I.tv t))) N.caX + rw [← N.x12 g t] + exact N.aX2 g t + · show XReach ((N.G0 g).Xm.Φ 0) ((N.G2 (N.r2 t g)).Xm.Φ 0) N.caY + rw [← N.y12 g t] + exact N.aY2 g t + · exact XReach.refl _ + · exact XReach.refl _) + refine H1.cast (fun φ => ?_) + simp_rw [mkB_map (fun c : (ℕ → ℝ) → ℝ => c φ)] + rw [sum_mkB] + simp only [sum_const, card_univ, nsmul_eq_mul, mul_zero, add_zero, zero_add] + ring + +/-- second idle climb of pair 2: the window of stage 2, ONE block of rank `card H - 1` per +role, to the frames of pair 1 after stage 2. -/ +lemma GBridge2.climbB : + XRoute N.S4 N.S5 id (fun φ => (Fintype.card Γ : ℝ) * + ((Fintype.card T : ℝ) * (2 * bcost φ (Fintype.card H - 1)))) := by + have H1 := XRoute.reach_all N.S4 N.S5 + (mkB (fun _ _ _ => 0) (fun _ _ _ => 0) (fun _ _ φ => bcost φ (Fintype.card H - 1)) + (fun _ _ φ => bcost φ (Fintype.card H - 1)) (fun _ _ _ => 0) (fun _ _ _ => 0)) (by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact XReach.refl _ + · exact XReach.refl _ + · show XReach ((N.G2 (N.r2 t g)).Xm.Φ (tt (N.I.tv t))) ((N.G3 (N.r3 t g)).Xm.Φ (tt (N.I.tv t))) + (fun φ => bcost φ (Fintype.card H - 1)) + rw [← N.x23 g t] + exact N.I.climbX (N.G2 (N.r2 t g)).Xm t + · show XReach ((N.G2 (N.r2 t g)).Xm.Φ 0) ((N.G3 (N.r3 t g)).Xm.Φ 0) + (fun φ => bcost φ (Fintype.card H - 1)) + rw [← N.y23 g t] + exact N.I.climbY (N.G2 (N.r2 t g)).Xm t + · exact XReach.refl _ + · exact XReach.refl _) + refine H1.cast (fun φ => ?_) + simp_rw [mkB_map (fun c : (ℕ → ℝ) → ℝ => c φ)] + rw [sum_mkB] + simp only [sum_const, card_univ, nsmul_eq_mul, mul_zero, add_zero, zero_add] + ring + +/-- the final climbs: pair 1 from its frames after stage 2 (ONE block per role for the +stages 3, 4 and the rest), pair 2 from its frames after stage 4; the helper slots are +already at the kernel. -/ +lemma GBridge2.fin : + XRoute N.S7 N.S8 id (fun φ => (Fintype.card Γ : ℝ) * + ((Fintype.card T : ℝ) * ((N.cX1 φ + N.cY1 φ) + (N.cX2 φ + N.cY2 φ)))) := by + have H1 := XRoute.reach_all N.S7 N.S8 + (mkB (fun _ _ => N.cX1) (fun _ _ => N.cY1) (fun _ _ => N.cX2) (fun _ _ => N.cY2) + (fun _ _ _ => 0) (fun _ _ _ => 0)) (by + rintro ((((⟨g,t⟩|⟨g,t⟩)|(⟨g,t⟩|⟨g,t⟩))|⟨g,q⟩)|⟨g,c⟩) + · exact N.fX1 g t + · exact N.fY1 g t + · exact N.fX2 g t + · exact N.fY2 g t + · show XReach (N.W4 (N.s4.symm g) * (N.W3 (N.s3.symm g) * (N.W2 (N.s2.symm g) * + (N.W1 (N.s1.symm g) * (N.G0 g).Xm.Φ 1)))) (kernel α) (fun _ => 0) + rw [N.sfin g] + exact XReach.refl _ + · exact XReach.refl _) + refine H1.cast (fun φ => ?_) + simp_rw [mkB_map (fun c : (ℕ → ℝ) → ℝ => c φ)] + rw [sum_mkB] + simp only [sum_const, card_univ, nsmul_eq_mul, mul_zero, add_zero, zero_add] + ring + +end Net +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.GBridge2.stage0 +#print axioms OAI.PowerSaving.GX.GBridge2.stage1 +#print axioms OAI.PowerSaving.GX.GBridge2.stage2 +#print axioms OAI.PowerSaving.GX.GBridge2.stage3 +#print axioms OAI.PowerSaving.GX.GBridge2.stage4 +#print axioms OAI.PowerSaving.GX.GBridge2.climbA +#print axioms OAI.PowerSaving.GX.GBridge2.climbB +#print axioms OAI.PowerSaving.GX.GBridge2.fin diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Phased.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Phased.lean new file mode 100644 index 0000000000..e68c42377f --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__Phased.lean @@ -0,0 +1,199 @@ +import Work.Carrier.Phases +import Work.GFrame.Labels.All + +/-! +# (key: gx-chain) The certificate as two halves: `Scal` (scalar half) and `Lab` (label half) + +`Scal T Sl C`: the scalar fields of `CR.Phased` (three facts about ONE matrix +`Mt = MB * scatM (Jr * Cc) * MA`). The scalar identities of the forward and of the backward +word (`fwd_scalar`, `bwd_scalar`) are those of `Work/Carrier/Phases.lean`, word for word. + +`Lab H S`: subspace labels (`GF.SLbl H`), routes of the three phases on the generalised engine +(`GF.GRoute`) through every stage-B frame map (`GF.BXMap H α`), and facts about dimensions at +the two ends. No projector, no `Climb`. + +No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB BR CR GF +noncomputable section + +/-- **The scalar half.** -/ +structure Scal (T Sl C : Type) [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] where + Cc : Matrix C Sl ℚ + Jr : Matrix T C ℚ + MA : Matrix (L3 T Sl) (L3 T Sl) ℚ + MAi : Matrix (L3 T Sl) (L3 T Sl) ℚ + MB : Matrix (L3 T Sl) (L3 T Sl) ℚ + MBi : Matrix (L3 T Sl) (L3 T Sl) ℚ + hAi : MAi * MA = 1 + hBi : MBi * MB = 1 + hx : ∀ t j, (MB * scatM (Jr * Cc) * MA) (lX t) j = if lX t = j then 1 else 0 + hy : ∀ i t, (MB * scatM (Jr * Cc) * MA) i (lY t) = if i = lY t then 1 else 0 + hid : ∀ S t, (MB * scatM (Jr * Cc) * MA) (lY S) (lX t) = if S = t then 1 else 0 + +/-- **The label half.** See `checks/wht26/shared/gcert-interface.md`, section CHAIN. -/ +structure Lab (H : Type) [Fintype H] [DecidableEq H] {T Sl C : Type} [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] (S : Scal T Sl C) where + tv : T → Space H + hunit : ∀ t, dot (tv t) (tv t) = 1 + hgap : ∀ t, ∃ p, tv t p = 0 + lab0 : L3 T Sl → SLbl H + labA : L3 T Sl → SLbl H + labB : L3 T Sl → SLbl H + labF : L3 T Sl → SLbl H + cen : C → SLbl H + z0 : SLbl H + hz0 : z0.dim = 0 + h0x : ∀ t, (lab0 (lX t)).dim = 1 ∧ (lab0 (lX t)).Mem (tv t) + h0y : ∀ t, (lab0 (lY t)).dim = 0 + h0s : ∀ q, (lab0 (lS q)).dim = 0 + hAy : ∀ t, labA (lY t) = z0 + hAc : ∀ k q, S.Cc k q ≠ 0 → cen k = labA (lS q) + hcen : ∀ k, 0 < (cen k).dim + hFx : ∀ t, (labF (lX t)).dim = Fintype.card H + hFs : ∀ q, (labF (lS q)).dim = Fintype.card H + hFy : ∀ t, (labF (lY t)).dim + 1 = Fintype.card H ∧ + ∀ x, (labF (lY t)).Mem x → dot (tv t) x = 0 + rA : List ℕ + rB : List ℕ + rF : List ℕ + pA : ∀ {α : Type} [Fintype α] [DecidableEq α] (X : BXMap H α), + Fintype.card H < Fintype.card α → + GRoute (fun r => X.Φ (lab0 r)) (fun r => X.Φ (labA r)) (actPoint S.MA) + (fun φ => rcost φ rA) ∧ + GRoute (fun r => X.Φ (lab0 r)) (fun r => X.Φ (labA r)) (actPoint S.MAiᵀ) + (fun φ => rcost φ rA) + pB : ∀ {α : Type} [Fintype α] [DecidableEq α] (X : BXMap H α), + Fintype.card H < Fintype.card α → + GRoute (fun r => X.Φ (labA r)) (fun r => X.Φ (labB r)) (actPoint S.MB) + (fun φ => rcost φ rB) ∧ + GRoute (fun r => X.Φ (labA r)) (fun r => X.Φ (labB r)) (actPoint S.MBiᵀ) + (fun φ => rcost φ rB) + pF : ∀ {α : Type} [Fintype α] [DecidableEq α] (X : BXMap H α), + Fintype.card H < Fintype.card α → + GRoute (fun r => X.Φ (labB r)) (fun r => X.Φ (labF r)) id (fun φ => rcost φ rF) + +/-- price of one invocation: the blocks of the three phases and one block per copy. -/ +def Lab.cost {H : Type} [Fintype H] [DecidableEq H] {T Sl C : Type} [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] {S : Scal T Sl C} (L : Lab H S) + (φ : ℕ → ℝ) : ℝ := + rcost φ L.rA + (∑ k, bcost φ (L.cen k).dim) + rcost φ L.rB + rcost φ L.rF + +section Alg +variable {H T Sl C : Type} [Fintype H] [DecidableEq H] [Fintype T] [DecidableEq T] + [Fintype Sl] [DecidableEq Sl] [Fintype C] [DecidableEq C] + +namespace Scal +variable (K : Scal T Sl C) + +/-- the product of ALL gates of the main phase (scatter with the copies eliminated). -/ +def Mt : Matrix (L3 T Sl) (L3 T Sl) ℚ := K.MB * scatM (K.Jr * K.Cc) * K.MA +/-- its inverse. -/ +def Mti : Matrix (L3 T Sl) (L3 T Sl) ℚ := K.MAi * scatMi (K.Jr * K.Cc) * K.MBi + + +lemma im : K.Mti * K.Mt = 1 := by + unfold Mti Mt + have hB : ∀ X : Matrix (L3 T Sl) (L3 T Sl) ℚ, K.MBi * (K.MB * X) = X := fun X => by + rw [← Matrix.mul_assoc, K.hBi, Matrix.one_mul] + have hS : ∀ X : Matrix (L3 T Sl) (L3 T Sl) ℚ, + scatMi (K.Jr * K.Cc) * (scatM (K.Jr * K.Cc) * X) = X := fun X => by + rw [← Matrix.mul_assoc, scat_inv, Matrix.one_mul] + rw [Matrix.mul_assoc, Matrix.mul_assoc, Matrix.mul_assoc, hB, hS, K.hAi] + +lemma mi : K.Mt * K.Mti = 1 := mul_eq_one_comm.mp K.im + +lemma hxm : PX * K.Mt = PX := PX_mul_of (M := K.Mt) K.hx +lemma hmy : K.Mt * PY = PY := mul_PY_of (M := K.Mt) K.hy +lemma hiy : K.Mti * PY = PY := dirt_iy K.hmy K.im + +/-- **the dirt rule, forward**, for the matrices of the circuit. -/ +lemma hF : g8 K.Mti * K.Mt * g1 K.Mt = 1 + PY * K.Mt * PX := by + unfold g8 g1 + exact dirt_fwd PX_sq PY_sq PX_PY PY_PX K.hxm K.hmy K.im K.mi + +/-- **the dirt rule, backward.** -/ +lemma hB : g1i K.Mt * K.Mti * h8 K.Mt = 1 - PY * K.Mt * PX := by + unfold g1i h8 + exact dirt_bwd PX_sq PY_sq PX_PY PY_PX K.hxm K.hmy K.im K.mi + +/-- live part of the forward word before the scatter: `y -= K s`, then phase A. -/ +def f1 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint K.MA (actPoint (g1 K.Mt) u) +/-- after the scatter: phase B, then the slot rows of the inverse. -/ +def f2 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint (g8 K.Mti) (actPoint K.MB u) +/-- the same for the backward word (transposed inverses). -/ +def b1 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint K.MAiᵀ (actPoint (g1i K.Mt)ᵀ u) +def b2 (u : L3 T Sl → ℂ) : L3 T Sl → ℂ := actPoint (h8 K.Mt)ᵀ (actPoint K.MBiᵀ u) + +lemma fwd_live (u : L3 T Sl → ℂ) : + K.f2 (actPoint (scatM (K.Jr * K.Cc)) (K.f1 u)) = actPoint (1 + PY * K.Mt * PX) u := by + rw [← K.hF] + show actPoint (g8 K.Mti) (actPoint K.MB (actPoint (scatM (K.Jr * K.Cc)) + (actPoint K.MA (actPoint (g1 K.Mt) u)))) + = actPoint (g8 K.Mti * (K.MB * scatM (K.Jr * K.Cc) * K.MA) * g1 K.Mt) u + rw [actPoint_mul, actPoint_mul, actPoint_mul, actPoint_mul] + +lemma bwd_live (u : L3 T Sl → ℂ) : + K.b2 (actPoint ((scatMi (K.Jr * K.Cc))ᵀ) (K.b1 u)) + = actPoint ((1 - PY * K.Mt * PX)ᵀ) u := by + rw [← K.hB] + show actPoint (h8 K.Mt)ᵀ (actPoint K.MBiᵀ (actPoint (scatMi (K.Jr * K.Cc))ᵀ + (actPoint K.MAiᵀ (actPoint (g1i K.Mt)ᵀ u)))) + = actPoint ((g1i K.Mt * (K.MAi * scatMi (K.Jr * K.Cc) * K.MBi) * h8 K.Mt)ᵀ) u + rw [Matrix.transpose_mul, Matrix.transpose_mul, Matrix.transpose_mul, Matrix.transpose_mul, + actPoint_mul, actPoint_mul, actPoint_mul, actPoint_mul] + +lemma liveAct_glue (φ : (L3 T Sl → ℂ) → (L3 T Sl → ℂ)) (u : L3 T Sl → ℂ) (c : C → ℂ) : + liveAct φ (glue u c) = glue (φ u) c := + congrArg (fun v => glue (φ v) c) (glue_up u c) + +/-- **Scalar identity of the forward word**: `y += x`, slots restored, for ARBITRARY slot +contents (the copies are erased before and after). -/ +theorem fwd_scalar (z : Box T Sl C → ℂ) : + eraseC (liveAct K.f2 (gateS bY bC K.Jr (gateS bC bS K.Cc (liveAct K.f1 (eraseC z))))) + = shearF z := by + have h1 : liveAct K.f1 (eraseC z) = glue (K.f1 (z ∘ upE)) (fun _ => 0) := by + rw [erase_glue z, liveAct_glue] + have hs : gateS bY bC K.Jr (gateS bC bS K.Cc (glue (K.f1 (z ∘ upE)) (fun _ => 0))) ∘ upE + = actPoint (scatM (K.Jr * K.Cc)) (K.f1 (z ∘ upE)) := by + have h := scat_glue K.Jr K.Cc (glue (K.f1 (z ∘ upE)) (fun _ => 0)) rfl + rw [glue_up] at h + exact h + rw [h1] + unfold liveAct + rw [erase_of_glue, hs, K.fwd_live, act_shear K.Mt K.hid] + exact glue_shearF z + +/-- **Scalar identity of the backward word**: `x -= y`, slots restored. -/ +theorem bwd_scalar (z : Box T Sl C → ℂ) : + eraseC (liveAct K.b2 (gateS bS bC (-K.Ccᵀ) (gateS bC bY K.Jrᵀ (liveAct K.b1 (eraseC z))))) + = shearB z := by + have h1 : liveAct K.b1 (eraseC z) = glue (K.b1 (z ∘ upE)) (fun _ => 0) := by + rw [erase_glue z, liveAct_glue] + have hs : gateS bS bC (-K.Ccᵀ) (gateS bC bY K.Jrᵀ (glue (K.b1 (z ∘ upE)) (fun _ => 0))) ∘ upE + = actPoint ((scatMi (K.Jr * K.Cc))ᵀ) (K.b1 (z ∘ upE)) := by + have h := scat_glueT K.Jr K.Cc (glue (K.b1 (z ∘ upE)) (fun _ => 0)) rfl + rw [glue_up] at h + exact h + rw [h1] + unfold liveAct + rw [erase_of_glue, hs, K.bwd_live, act_shearT K.Mt K.hid] + exact glue_shearB z + +end Scal +end Alg +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.Scal.fwd_scalar +#print axioms OAI.PowerSaving.GX.Scal.bwd_scalar diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__WinB.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__WinB.lean new file mode 100644 index 0000000000..951edde5cf --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Chain__WinB.lean @@ -0,0 +1,132 @@ +import Work.GCert.Chain.Win +import Work.BridgeGeom.Stage + +/-! +# (key: gx-chain) THE WINDOW LIFT (spec statement 3): the windows of the bridged geometry + +For the block frame map `BG.fmapB hB hH d q` of a stage of the bridged word (label space +`LB B H = H ⊕ (B × H)`, old frame of the projector `P`: `PhiB d q P`) the stage-B frame map is +`BXMap.ofConj d q` (`U ↦ d (U ⊕ span q)`, arbitrary subspaces `U` of `H`). At a coordinate +subspace of an orthonormal basis `A` of `H` the two name the SAME subspace of the address space +(`insub_old_new`), so the old frame and the representative of any label of that subspace +differ by a free factor (`frame_core_free`, `rep_change`): `old_to_new`, `new_to_old`. + +`gwinB hB hH d q : GWin H (LB B H)` with `(gwinB hB hH d q).Xm = fmapB hB hH d q` (`rfl`). + +No `sorry`. +-/ + +set_option linter.unusedSectionVars false +set_option linter.unusedVariables false + +namespace OAI +namespace PowerSaving +namespace GX +open Binary Matrix Finset RAM SS CB RF BR BG GF +noncomputable section + +section +variable {B H : Type} [Fintype B] [DecidableEq B] [Fintype H] [DecidableEq H] + +lemma blkT_mulVec (A : OBase H) (z : Space (LB B H)) (k : LB B H) : + ((blkB B A)ᵀ *ᵥ z) k = Sum.elim (fun i => dot (A.v i) (fun j => z (Sum.inl j))) + (fun b => z (Sum.inr b)) k := by + cases k with + | inl i => + simp [blkB, Matrix.fromBlocks_transpose, Matrix.mulVec, dotProduct, Fintype.sum_sum_type, + cmat, dot] + | inr b => + simp [blkB, Matrix.fromBlocks_transpose, Matrix.mulVec, dotProduct, Fintype.sum_sum_type, + Matrix.one_apply] + +/-- coordinates of `y` in the basis `d (A ⊕ std)`. -/ +lemma dot_cols (d : Orth (LB B H)) (A : OBase H) (y : Space (LB B H)) (k : LB B H) : + dot ((ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A))).v k) y + = Sum.elim (fun i => dot (A.v i) (fun j => (d.1ᵀ *ᵥ y) (Sum.inl j))) + (fun b => (d.1ᵀ *ᵥ y) (Sum.inr b)) k := by + rw [← blkT_mulVec A (d.1ᵀ *ᵥ y) k, Matrix.mulVec_mulVec, ← Matrix.transpose_mul] + rfl + +/-- **the old frame and the lifted label name the same subspace of the address space.** -/ +theorem insub_old_new (d : Orth (LB B H)) (q : Finset (B × H)) (A : OBase H) (s : Finset H) + (U : SLbl H) (h : ∀ x, U.Mem x ↔ InSub (coordPerm A) s x) (y : Space (LB B H)) : + InSub (coordPerm (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A)))) (JB s q) y ↔ + InSub (conjPerm d.1 d.2 (Orth.orth' d) U.G) (U.s.disjSum q) y := by + rw [insub_conj, insub_coordPerm] + have hU := h (fun i => (d.1ᵀ *ᵥ y) (Sum.inl i)) + constructor + · intro hk + refine ⟨hU.mpr ((insub_coordPerm A s _).mpr (fun i hi => ?_)), fun b hb => ?_⟩ + · have h1 := hk (Sum.inl i) (fun hm => hi (Finset.inl_mem_disjSum.mp hm)) + rw [dot_cols] at h1 + exact h1 + · have h1 := hk (Sum.inr b) (fun hm => hb (Finset.inr_mem_disjSum.mp hm)) + rw [dot_cols] at h1 + exact h1 + · rintro ⟨h1, h2⟩ k hk + rw [dot_cols] + cases k with + | inl i => + exact (insub_coordPerm A s _).mp (hU.mp h1) i + (fun hm => hk (Finset.inl_mem_disjSum.mpr hm)) + | inr b => exact h2 b (fun hm => hk (Finset.inr_mem_disjSum.mpr hm)) + +/-- old frame of a coordinate subspace → representative of any label naming it: FREE. -/ +theorem old_to_new (d : Orth (LB B H)) (q : Finset (B × H)) (A : OBase H) (s : Finset H) + (U : SLbl H) (h : ∀ x, U.Mem x ↔ InSub (coordPerm A) s x) : + GReach (PhiB d q (A.mat s)) ((BXMap.ofConj d.1 d.2 (Orth.orth' d) q).Φ U) (fun _ => 0) := by + rw [PhiB_eq] + obtain ⟨N, hN, e⟩ := repChange (LB B H) _ _ _ _ (insub_old_new d q A s U h) + have a : GReach (frame (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A))) (JB s q)) + (core (coordPerm (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A)))) (JB s q)) + (fun φ => rcost φ []) := + GReach.ofReach (fmv_old_to_core _ _).reach + have b : GReach + (core (coordPerm (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A)))) (JB s q)) + (core (conjPerm d.1 d.2 (Orth.orth' d) U.G) (U.s.disjSum q)) (fun φ => rcost φ []) := + GReach.ofReach (fmv_of_free hN e).reach + exact (a.trans b).cast (fun φ => by simp [rcost]) + +/-- the same, backwards. -/ +theorem new_to_old (d : Orth (LB B H)) (q : Finset (B × H)) (A : OBase H) (s : Finset H) + (U : SLbl H) (h : ∀ x, U.Mem x ↔ InSub (coordPerm A) s x) : + GReach ((BXMap.ofConj d.1 d.2 (Orth.orth' d) q).Φ U) (PhiB d q (A.mat s)) (fun _ => 0) := by + rw [PhiB_eq] + obtain ⟨N, hN, e⟩ := repChange (LB B H) _ _ _ _ + (fun y => (insub_old_new d q A s U h y).symm) + have a : GReach (core (conjPerm d.1 d.2 (Orth.orth' d) U.G) (U.s.disjSum q)) + (core (coordPerm (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A)))) (JB s q)) + (fun φ => rcost φ []) := + GReach.ofReach (fmv_of_free hN e).reach + have b : GReach + (core (coordPerm (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A)))) (JB s q)) + (frame (ofCols (d.1 * blkB B A) (mul_orth d.2 (blkB_orth A))) (JB s q)) + (fun φ => rcost φ []) := + GReach.ofReach (fmv_core_to_old _ _).reach + exact (a.trans b).cast (fun φ => by simp [rcost]) + +/-- **The window of a stage of the bridged geometry.** -/ +def gwinB (hB : 1 ≤ Fintype.card B) (hH : 1 ≤ Fintype.card H) (d : Orth (LB B H)) + (q : Finset (B × H)) : GWin H (LB B H) where + Xm := fmapB hB hH d q + X := BXMap.ofConj d.1 d.2 (Orth.orth' d) q + big := by + rw [card_LB] + have := Nat.mul_le_mul_right (Fintype.card H) (show 2 ≤ Fintype.card B + 1 by omega) + omega + toNew := fun A s U h => old_to_new d q A s U h + toOld := fun A s U h => new_to_old d q A s U h + +@[simp] lemma gwinB_Xm (hB : 1 ≤ Fintype.card B) (hH : 1 ≤ Fintype.card H) (d : Orth (LB B H)) + (q : Finset (B × H)) : (gwinB hB hH d q).Xm = fmapB hB hH d q := rfl + +end +end +end GX +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.GX.insub_old_new +#print axioms OAI.PowerSaving.GX.old_to_new +#print axioms OAI.PowerSaving.GX.new_to_old +#print axioms OAI.PowerSaving.GX.gwinB diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__B2Gp193Main.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__B2Gp193Main.lean new file mode 100644 index 0000000000..d7ecfebcea --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__B2Gp193Main.lean @@ -0,0 +1,33 @@ +import Work.GCert.Scalar.Main +import Work.GCert.Data.P193ScalOK +import Work.GCert.Data.B2Gp193 + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `P193`: THE CLOSED THEOREMS +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`wht_B2Gp193_of_ids` (label half, price, unit list, rate fact, gx-chain's end theorem) applied to the scalar half +`GXD.P193.scalOK : GS.ScalOK GXD.P193.raw` (kernel checks `scal_ok`, `ychk_ok`; soundness: gx-scalar). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT + +/-- **Walsh-Hadamard transform in `O(n (log n)^(1 - 74745/10^8))`-type time bounds: whole-block recursion on the bridged +word B_2 with the kernel-checked gcert/1 circuit `P193`.** -/ +theorem wht_main_B2Gp193 : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 74745/(10:ℝ)^8) W := + wht_B2Gp193_of_ids GXD.P193.scalOK.hv GXD.P193.scalOK.hAi GXD.P193.scalOK.hBi GXD.P193.scalOK.hx GXD.P193.scalOK.hy GXD.P193.scalOK.hid + +/-- **Walsh-Hadamard transform in `O(n (log n)^(1 - 7474547/10^10))`-type time bounds: whole-block recursion on the bridged +word B_2 with the kernel-checked gcert/1 circuit `P193`.** -/ +theorem wht_main_B2Gp193x : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 7474547/(10:ℝ)^10) W := + wht_B2Gp193x_of_ids GXD.P193.scalOK.hv GXD.P193.scalOK.hAi GXD.P193.scalOK.hBi GXD.P193.scalOK.hx GXD.P193.scalOK.hy GXD.P193.scalOK.hid + +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_main_B2Gp193 +#print axioms OAI.PowerSaving.WHT.wht_main_B2Gp193x diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Glue.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Glue.lean new file mode 100644 index 0000000000..c6cbac38e3 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Glue.lean @@ -0,0 +1,97 @@ +import Work.GCert.Scalar.Roles +import Work.GCert.Labels.Main + +/-! +# (key: gx-data) Glue between the scalar half (gx-scalar) and the label half (gx-labels) + +For ANY `c : GXD.Raw` (nothing is evaluated here): + +* `roles` gx-scalar's numbering `GS.emb` / `GS.unemb` is gx-labels' `GLab.Roles`; +* `scalOf` gx-chain's record `GX.Scal (Fin v) (Fin R) (Fin ret.length)` from the FIVE scalar + identities of the matrices `GS.MA`, `GS.MAi`, `GS.MB`, `GS.MBi`, `GS.Jrm`, `GS.Ccm`; +* `scalOf_MA .. scalOf_MBi` its gate matrices are the ordered products of the adds of `c`, in + the form asked by `GLab.Valid.lab` (`GLab.mic GS.toCoef`); +* `reg`, `reg_slot`, `reg_mem` copy `k` reads the retained register `(c.ret.getD k (0,0)).1`. + +So a generated instance needs from the scalar side exactly `hAi hBi hx hy hid` (see +`wht__of_ids` in `Work/GCert/Data/.lean`). No `sorry`. +-/ + +namespace GXD +open SSC OAI.PowerSaving OAI.PowerSaving.CR Matrix + +/-- the numbering of the roles: `x_t = t`, `y_t = v + t`, slot `q = 2 v + q` -/ +theorem roles (c : Raw) (hv : 0 < c.v) : GLab.Roles c.v c.R (GS.emb c) (GS.unemb c hv) where + hun := GS.unemb_emb hv + hin := GS.emb_unemb hv + hlt := fun q => by + rcases q with (t | S) | q + · have := t.isLt; show t.val < 2 * c.v + c.R; omega + · have := S.isLt; show c.v + S.val < 2 * c.v + c.R; omega + · have := q.isLt; show 2 * c.v + q.val < 2 * c.v + c.R; omega + eX := fun _ => rfl + eY := fun _ => rfl + eS := fun _ => rfl + +/-- **the scalar half as gx-chain's record**, from the five scalar identities -/ +noncomputable def scalOf (c : Raw) (hv : 0 < c.v) + (hAi : GS.MAi c hv * GS.MA c hv = 1) (hBi : GS.MBi c hv * GS.MB c hv = 1) + (hx : ∀ (t : Fin c.v) (j : GS.Rl c), (GS.MB c hv * scatM (GS.Jrm c * GS.Ccm c) * GS.MA c hv) + (lX t) j = if lX t = j then 1 else 0) + (hy : ∀ (i : GS.Rl c) (t : Fin c.v), (GS.MB c hv * scatM (GS.Jrm c * GS.Ccm c) * GS.MA c hv) + i (lY t) = if i = lY t then 1 else 0) + (hid : ∀ S t : Fin c.v, (GS.MB c hv * scatM (GS.Jrm c * GS.Ccm c) * GS.MA c hv) + (lY S) (lX t) = if S = t then 1 else 0) : + GX.Scal (Fin c.v) (Fin c.R) (Fin c.ret.length) where + Cc := GS.Ccm c + Jr := GS.Jrm c + MA := GS.MA c hv + MAi := GS.MAi c hv + MB := GS.MB c hv + MBi := GS.MBi c hv + hAi := hAi + hBi := hBi + hx := hx + hy := hy + hid := hid + +section +variable (c : Raw) (hv : 0 < c.v) (hAi) (hBi) (hx) (hy) (hid) + +theorem scalOf_MA : (scalOf c hv hAi hBi hx hy hid).MA + = matP (GS.unemb c hv) (GLab.mic GS.toCoef (c.gatesA.flatMap Gate.adds)) := rfl + +theorem scalOf_MAi : (scalOf c hv hAi hBi hx hy hid).MAi + = matPinv (GS.unemb c hv) (GLab.mic GS.toCoef (c.gatesA.flatMap Gate.adds)) := rfl + +theorem scalOf_MB : (scalOf c hv hAi hBi hx hy hid).MB + = matP (GS.unemb c hv) (GLab.mic GS.toCoef (c.gatesB.flatMap Gate.adds)) := rfl + +theorem scalOf_MBi : (scalOf c hv hAi hBi hx hy hid).MBi + = matPinv (GS.unemb c hv) (GLab.mic GS.toCoef (c.gatesB.flatMap Gate.adds)) := rfl + +end + +/-- the register read by copy `k` (the slot of the retained total `k`) -/ +def reg (c : Raw) (k : Fin c.ret.length) : Nat := (c.ret.getD k.val (0, 0)).1 + +theorem reg_slot (c : Raw) (hv : 0 < c.v) (hAi) (hBi) (hx) (hy) (hid) (k : Fin c.ret.length) + (q : Fin c.R) (h : (scalOf c hv hAi hBi hx hy hid).Cc k q ≠ 0) : + reg c k = 2 * c.v + q.val := by + have h' : (if 2 * c.v + q.val = (c.ret.getD k.val (0, 0)).1 then (1:ℚ) else 0) ≠ 0 := h + by_cases e : 2 * c.v + q.val = (c.ret.getD k.val (0, 0)).1 + · exact e.symm + · rw [if_neg e] at h'; exact absurd rfl h' + +theorem reg_mem (c : Raw) (k : Fin c.ret.length) : reg c k ∈ c.ret.map Prod.fst := by + unfold reg + rw [List.getD_eq_getElem _ _ k.isLt] + exact List.mem_map.mpr ⟨_, List.getElem_mem k.isLt, rfl⟩ + +end GXD + +#print axioms GXD.roles +#print axioms GXD.scalOf +#print axioms GXD.scalOf_MA +#print axioms GXD.reg_slot +#print axioms GXD.reg_mem diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__InstB2Gp193.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__InstB2Gp193.lean new file mode 100644 index 0000000000..9b9925ce26 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__InstB2Gp193.lean @@ -0,0 +1,55 @@ +import Work.BridgeGeom.B2 +import Work.FoldRate.Group +import Work.GCert.Data.RateB2Gp193 +import Work.GCert.Data.RateB2Gp193x + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `P193`, h = 22: the unit price is the price of the block list + +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. Arithmetic only (no certificate is imported). + +One unit: `W = 14692` live roles (`4 v + R`, `v = 1320`, `R = 9412`), label dimension `m = 110`, deficit `D = 3080`. +`invPrice φ` = the price of the blocks of ONE invocation (the kernel-counted list `GXD.P193.hist`, by rank); +`unitPrice φ = 5 * invPrice φ + v * BG.bankPrice h φ = listCost φ BlockAccounting.blocksB2Gp193` (`unit_cost`). +Whole-block `1 - 74745/10^8` (fails at 74746), ten decimals `1 - 7474547/10^10` (fails at 7474550). +-/ + +namespace OAI +namespace PowerSaving +namespace BridgeRate +namespace B2Gp193 +open Finset Binary Matrix RAM CB FoldRate +noncomputable section + +/-- price of the blocks of ONE invocation of `P193` (all roles and scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := 29178 * φ 1 + 12398 * φ 2 + 9923 * φ 3 + 4209 * φ 4 + 1950 * φ 5 + 1605 * φ 6 + 706 * φ 7 + 1531 * φ 8 + 429 * φ 9 + 930 * φ 10 + 354 * φ 11 + 1197 * φ 12 + 127 * φ 13 + 742 * φ 14 + 1879 * φ 15 + 88 * φ 16 + 81 * φ 17 + 2653 * φ 18 + 167 * φ 19 + 22 * φ 20 + +/-- price of ONE unit of the bridged word B_2 -/ +def unitPrice (φ : ℕ → ℝ) : ℝ := 5 * invPrice φ + ((1320:ℕ):ℝ) * BG.bankPrice 22 φ + +/-- **The unit price is the price of the unit block list.** -/ +theorem unit_cost (φ : ℕ → ℝ) : unitPrice φ = listCost φ BlockAccounting.blocksB2Gp193 := by + unfold unitPrice invPrice + simp only [BG.bankPrice, listCost, BlockAccounting.blocksB2Gp193, List.map_cons, List.map_nil, + List.sum_cons, List.sum_nil] + norm_num [bcost] + try ring + +theorem blocks_x : BlockAccounting.blocksB2Gp193 = BlockAccounting.blocksB2Gp193x := rfl + +theorem unit_cost_x (φ : ℕ → ℝ) : unitPrice φ = listCost φ BlockAccounting.blocksB2Gp193x := by + rw [unit_cost, blocks_x] + +/-- one unit stands for `W * m - D` unit moves -/ +theorem unit_tally : unitPrice (fun r => (r:ℝ)) = ((14692:ℕ):ℝ) * ((110:ℕ):ℝ) - ((3080:ℕ):ℝ) := by + rw [unit_cost] + exact BlockAccounting.blocksB2Gp193_tally + +end +end B2Gp193 +end BridgeRate +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.BridgeRate.B2Gp193.unit_cost +#print axioms OAI.PowerSaving.BridgeRate.B2Gp193.unit_tally diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Cert.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Cert.lean new file mode 100644 index 0000000000..3c3250279e --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Cert.lean @@ -0,0 +1,81 @@ +import Work.GCert.Labels.Main +import Work.GCert.Data.P193Price +import Work.GCert.Data.Gen.P193Tab0 +import Work.GCert.Data.Gen.P193Tab1 +import Work.GCert.Data.Gen.P193Tab2 +import Work.GCert.Data.Gen.P193Tab3 +import Work.GCert.Data.Gen.P193Seg0 +import Work.GCert.Data.Gen.P193Seg1 +import Work.GCert.Data.Gen.P193Seg2 +import Work.GCert.Data.Gen.P193Seg3 +import Work.GCert.Data.Gen.P193Seg4 +import Work.GCert.Data.Gen.P193SegF +import Work.GCert.Data.Gen.P193End +/-! # (key: gx-data) gcert/1 certificate `P193` (h = 22): THE LABEL HALF and its price +GENERATED by checks/wht26/gx-data/py/gxgen.py from gcert1-p11-pr193.json.gz. No `sorry`. +`v = 1320` ports, `R = 9412` slots, 22 scratch copies of rank 20, copy cost `cst = 440`, `N = 262944` unit moves. +* `aux : GLab.Aux`, `valid : GLab.Valid raw aux`: frame table (`tab_ok` composed by `tabK_node`), the replays of phase A + and phase B (`seg_ok` composed by `Run.append`), the final climbs (`segF_ok`, `fin_ok`), the ends (`end_ok`); +* `lab_cost`, `lab_price`: for ANY scalar half `S` the label half `valid.lab S ..` costs + `rcost rA + card C * bcost 20 + rcost rB + rcost rF` = `invPrice φ` = 29178 * φ 1 + 12398 * φ 2 + 9923 * φ 3 + 4209 * φ 4 + 1950 * φ 5 + 1605 * φ 6 + 706 * φ 7 + 1531 * φ 8 + 429 * φ 9 + 930 * φ 10 + 354 * φ 11 + 1197 * φ 12 + 127 * φ 13 + 742 * φ 14 + 1879 * φ 15 + 88 * φ 16 + 81 * φ 17 + 2653 * φ 18 + 167 * φ 19 + 22 * φ 20 + (`Gen.P193Hist`, `P193Price`) when there are 22 copies. -/ +set_option maxRecDepth 100000 +namespace GXD.P193 +open GXD OAI.PowerSaving OAI.PowerSaving.CB +theorem raw_h : raw.h = 22 := rfl +theorem raw_v : raw.v = 1320 := rfl +theorem raw_R : raw.R = 9412 := rfl +/-- what the label checks read next to `raw` -/ +noncomputable def aux : GLab.Aux := ⟨par, st0, st2, st5, st6, fins, rA, rB, rF⟩ +theorem fin_ok : GLab.noAdds fins = true := by decide +kernel +theorem cen_ok : (raw.ret.map Prod.fst).all (fun r => Nat.beq (GLab.cdim (par.tab.get (st2.get r))) 20) = true := by + decide +kernel +theorem tab_ok : GLab.tabK par.h par.tab = true := (GLab.tabK_node _ _ _ (GLab.tabK_node _ _ _ tab0_ok tab1_ok) (GLab.tabK_node _ _ _ tab2_ok tab3_ok)) +theorem gatesA_eq : raw.gatesA = seg0 ++ (seg1) := by + show List.flatten [seg0, seg1] = _ + simp only [List.flatten_cons, List.flatten_nil, List.append_nil] +/-- the replay of phase A, composed from its kernel-checked segments -/ +theorem runA : GLab.Run par st0 raw.gatesA st2 rA := by + rw [gatesA_eq] + exact GLab.Run.append (GLab.Run.of_seg seg0_ok) (GLab.Run.of_seg seg1_ok) +theorem gatesB_eq : raw.gatesB = seg2 ++ (seg3 ++ (seg4)) := by + show List.flatten [seg2, seg3, seg4] = _ + simp only [List.flatten_cons, List.flatten_nil, List.append_nil] +/-- the replay of phase B, composed from its kernel-checked segments -/ +theorem runB : GLab.Run par st2 raw.gatesB st5 rB := by + rw [gatesB_eq] + exact GLab.Run.append (GLab.Run.of_seg seg2_ok) (GLab.Run.append (GLab.Run.of_seg seg3_ok) (GLab.Run.of_seg seg4_ok)) +/-- **the kernel-checked label facts** of the certificate -/ +theorem valid : GLab.Valid raw aux where + hn := rfl + tab := tab_ok + runA := runA + runB := runB + runF := GLab.Run.of_seg segF_ok + fin := fin_ok + ends := end_ok +theorem cen_dim (r : Nat) (hr : r ∈ raw.ret.map Prod.fst) : GLab.cdim (par.tab.get (st2.get r)) = 20 := + Nat.eq_of_beq_eq_true (List.all_eq_true.mp cen_ok r hr) +/-- price of the label half over ANY scalar half -/ +theorem lab_cost {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (φ : ℕ → ℝ) : + (valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg).cost φ + = rcost φ rA + (Fintype.card C : ℝ) * bcost φ 20 + rcost φ rB + rcost φ rF := by + obtain ⟨h1, h2, h3, h4⟩ := valid.lab_ranks S Ro cf hMA hMAi hMB hMBi reg hCc hreg + have h5 : ∀ k, bcost φ (((valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg).cen k).dim) = bcost φ 20 := + fun k => by rw [h4 k]; exact congrArg (bcost φ) (cen_dim _ (hreg k)) + rw [GX.Lab.cost, h1, h2, h3, Finset.sum_congr rfl (fun k _ => h5 k), Finset.sum_const, Finset.card_univ, nsmul_eq_mul] + rfl +/-- **the label half costs one invocation price** (`invPrice`, by rank, from the kernel counts) -/ +theorem lab_price {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (hC : Fintype.card C = 22) (φ : ℕ → ℝ) : + (valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg).cost φ = invPrice φ := by + rw [lab_cost S Ro cf hMA hMAi hMB hMBi reg hCc hreg φ, hC, ← inv_cost φ] + norm_num [bcost] +end GXD.P193 +#print axioms GXD.P193.valid +#print axioms GXD.P193.lab_price diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Price.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Price.lean new file mode 100644 index 0000000000..eeed011d64 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193Price.lean @@ -0,0 +1,54 @@ +import Work.GCert.Data.Price +import Work.GCert.Data.Gen.P193Hist + +/-! +# (key: gx-data) gcert/1 certificate `P193` (h = 22): the price of one invocation + +GENERATED by checks/wht26/gx-data/py/gxgen.py from gcert1-p11-pr193.json.gz. No `sorry`. +`rA_cost`, `rB_cost`, `rF_cost`: the price of the block rank lists of phase A, phase B and the final climbs +(lists `GXD.P193.rA / rB / rF`, counted by the kernel in `Gen.P193Hist`); +`inv_cost`: with the 22 scratch copies (22 * φ 20) the blocks of ONE invocation cost +`invPrice φ` = 29178 * φ 1 + 12398 * φ 2 + 9923 * φ 3 + 4209 * φ 4 + 1950 * φ 5 + 1605 * φ 6 + 706 * φ 7 + 1531 * φ 8 + 429 * φ 9 + 930 * φ 10 + 354 * φ 11 + 1197 * φ 12 + 127 * φ 13 + 742 * φ 14 + 1879 * φ 15 + 88 * φ 16 + 81 * φ 17 + 2653 * φ 18 + 167 * φ 19 + 22 * φ 20; `inv_moves`: they stand for `R h + 2 v (h - 1) + cst = 262944` unit moves. +-/ + +namespace GXD.P193 +open GXD OAI.PowerSaving.CB + +/-- price of the blocks of phase A, from the kernel counts -/ +theorem rA_cost (φ : ℕ → ℝ) : rcost φ rA = 9900 * φ 1 + 500 * φ 2 + 2402 * φ 3 + 82 * φ 4 + 242 * φ 5 + 175 * φ 6 + 88 * φ 7 + 68 * φ 8 + 110 * φ 9 + 132 * φ 10 + 10 * φ 11 + 67 * φ 12 + 3 * φ 13 + 19 * φ 15 := by + rw [GXD.rcost_wsumK φ rA 19 rankBoundA] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, rankA0_ok, rankA1_ok, rankA2_ok, rankA3_ok, rankA4_ok, rankA5_ok, rankA6_ok, rankA7_ok, rankA8_ok, rankA9_ok, rankA10_ok, rankA11_ok, rankA12_ok, rankA13_ok, rankA14_ok, rankA15_ok, rankA16_ok, rankA17_ok, rankA18_ok, rankA19_ok] + norm_num [bcost] + +/-- price of the blocks of phase B, from the kernel counts -/ +theorem rB_cost (φ : ℕ → ℝ) : rcost φ rB = 16638 * φ 1 + 10380 * φ 2 + 4111 * φ 3 + 3476 * φ 4 + 1531 * φ 5 + 1137 * φ 6 + 531 * φ 7 + 1346 * φ 8 + 293 * φ 9 + 629 * φ 10 + 343 * φ 11 + 1067 * φ 12 + 123 * φ 13 + 712 * φ 14 + 1860 * φ 15 + 81 * φ 16 + 39 * φ 17 + 2640 * φ 18 := by + rw [GXD.rcost_wsumK φ rB 19 rankBoundB] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, rankB0_ok, rankB1_ok, rankB2_ok, rankB3_ok, rankB4_ok, rankB5_ok, rankB6_ok, rankB7_ok, rankB8_ok, rankB9_ok, rankB10_ok, rankB11_ok, rankB12_ok, rankB13_ok, rankB14_ok, rankB15_ok, rankB16_ok, rankB17_ok, rankB18_ok, rankB19_ok] + norm_num [bcost] + +/-- price of the blocks of the final climbs, from the kernel counts -/ +theorem rF_cost (φ : ℕ → ℝ) : rcost φ rF = 2640 * φ 1 + 1518 * φ 2 + 3410 * φ 3 + 651 * φ 4 + 177 * φ 5 + 293 * φ 6 + 87 * φ 7 + 117 * φ 8 + 26 * φ 9 + 169 * φ 10 + 1 * φ 11 + 63 * φ 12 + 1 * φ 13 + 30 * φ 14 + 7 * φ 16 + 42 * φ 17 + 13 * φ 18 + 167 * φ 19 := by + rw [GXD.rcost_wsumK φ rF 19 rankBoundF] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, rankF0_ok, rankF1_ok, rankF2_ok, rankF3_ok, rankF4_ok, rankF5_ok, rankF6_ok, rankF7_ok, rankF8_ok, rankF9_ok, rankF10_ok, rankF11_ok, rankF12_ok, rankF13_ok, rankF14_ok, rankF15_ok, rankF16_ok, rankF17_ok, rankF18_ok, rankF19_ok] + norm_num [bcost] + +/-- price of the blocks of ONE invocation (x roles, y roles, slots, scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := 29178 * φ 1 + 12398 * φ 2 + 9923 * φ 3 + 4209 * φ 4 + 1950 * φ 5 + 1605 * φ 6 + 706 * φ 7 + 1531 * φ 8 + 429 * φ 9 + 930 * φ 10 + 354 * φ 11 + 1197 * φ 12 + 127 * φ 13 + 742 * φ 14 + 1879 * φ 15 + 88 * φ 16 + 81 * φ 17 + 2653 * φ 18 + 167 * φ 19 + 22 * φ 20 + +/-- **Price of ONE invocation** in the shape of `GX.Lab.cost`: phase A, the scratch copies, phase B, final climbs. -/ +theorem inv_cost (φ : ℕ → ℝ) : rcost φ rA + (22 * φ 20) + rcost φ rB + rcost φ rF = invPrice φ := by + rw [rA_cost, rB_cost, rF_cost] + unfold invPrice + ring + +theorem inv_moves : invPrice (fun r => (r:ℝ)) = 9412 * 22 + 2 * 1320 * (22 - 1) + 440 := by + unfold invPrice + norm_num + +theorem inv_count : invPrice (fun _ => (1:ℝ)) = 70169 := by + unfold invPrice + norm_num + +end GXD.P193 +#print axioms GXD.P193.inv_cost +#print axioms GXD.P193.inv_moves diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193ScalOK.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193ScalOK.lean new file mode 100644 index 0000000000..3539192ac1 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__P193ScalOK.lean @@ -0,0 +1,17 @@ +import Work.GCert.Scalar.Main +import Work.GCert.Data.Gen.P193Scal0 +import Work.GCert.Data.Gen.P193Scal1 +import Work.GCert.Data.Gen.P193YChk +/-! # (key: gx-data) gcert/1 certificate `P193` (h = 22): THE SCALAR HALF `scalOK : GS.ScalOK raw` +GENERATED by checks/wht26/gx-data/py/gxgen.py from gcert1-p11-pr193.json.gz. No `sorry`. +Kernel checks `scal_ok` (2 source batches) and `ychk_ok`. -/ +namespace GXD.P193 +open GXD +theorem scalOK : GS.ScalOK raw where + hv := by decide + hs := fun t ht => + if h0 : t < 660 then ⟨0, 660, Nat.zero_le t, h0, GS.XRun.of_check scal0_ok⟩ else + ⟨660, 660, Nat.le_of_not_lt h0, Nat.lt_of_lt_of_le ht (by decide), GS.XRun.of_check scal1_ok⟩ + hyc := fun t ht => ⟨0, 1320, Nat.zero_le t, Nat.lt_of_lt_of_le ht (by decide), GS.YRun.of_check ychk_ok⟩ +end GXD.P193 +#print axioms GXD.P193.scalOK diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__RateB2Gp193x.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__RateB2Gp193x.lean new file mode 100644 index 0000000000..df563cde73 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__RateB2Gp193x.lean @@ -0,0 +1,327 @@ +import Work.BlockAccounting.Moment +import Work.BlockAccounting.Sharp +import Work.FoldRate.RankTools + +/-! +# (key: gx-data) Rate lemmas for one unit of the bridged word B_2 with the gcert/1 circuit `P193` (h = 22) + +GENERATED by checks/wht26/gx-data/py/gxrate.py with the text generators of checks/wht9/bridge-rate/py +(used read-only). No `sorry`. Arithmetic only. + +One unit: `W = 14692` live roles, label dimension `m = 110`, deficit `D = 3080`. + +* `blocksB2Gp193x` the block list (rank, count) of ONE unit; +* `fold_B2Gp193x` whole-block fact at `1 - 7474547/10^10`, fill parameter `s = 40` (slack 2.37e-12); +* `fold_B2Gp193x_sharp` `W ≤ moment` at `1 - 7474550/10^10`: fails for every table (excess 1.40e-10); +* `foldRank_B2Gp193x` per-rank fact at `1 - 4058344/10^10`, `s = 40` (slack 1.10e-07); +* `foldRank_B2Gp193x_sharp` per-rank: fails for every table at `1 - 4058349/10^10`. + +That a Lean word has `G` times this list as its block histogram is NOT proved here. +-/ + +set_option maxRecDepth 4000 + +namespace OAI.PowerSaving.BlockAccounting +open Finset + +/-- Block list `(rank, count)` of ONE unit of the bridged five-stage word B_2 with the gcert/1 circuit `P193` (h = 22, m = 110): five invocations (ALL blocks of one invocation: x roles, y roles, slots, scratch copies; the kernel-counted list `GXD.P193.hist`), and for each of the v = 1320 ports the idle climbs of its two twins (2 blocks each of rank h-1, 2h-2, 2h+2, 4); R = 9412 slots shared by the five stages. -/ +def blocksB2Gp193x : List (ℕ × ℕ) := [(1, 145890), (2, 61990), (3, 49615), (4, 23685), (5, 9750), (6, 8025), (7, 3530), (8, 7655), (9, 2145), (10, 4650), (11, 1770), (12, 5985), (13, 635), (14, 3710), (15, 9395), (16, 440), (17, 405), (18, 13265), (19, 835), (20, 110), (21, 2640), (42, 2640), (46, 2640)] + +/-- total rank of one unit (= number of unit moves it stands for): `W * m - D` -/ +theorem blocksB2Gp193x_rank : (blocksB2Gp193x.map fun b => b.1 * b.2).sum = 14692 * 110 - 3080 := by + norm_num [blocksB2Gp193x] + +/-- the same as a price: the unit list at the price list `r ↦ r` (shape of `hPid` in `RAM.engine_program_group_perRank`) -/ +theorem blocksB2Gp193x_tally : (blocksB2Gp193x.map fun b => (b.2:ℝ) * ((b.1:ℕ):ℝ)).sum = ((14692:ℕ):ℝ) * ((110:ℕ):ℝ) - ((3080:ℕ):ℝ) := by + norm_num [blocksB2Gp193x] + +theorem blocksB2Gp193x_count : (blocksB2Gp193x.map fun b => b.2).sum = 361405 := by + norm_num [blocksB2Gp193x] + +theorem blocksB2Gp193x_proper : ∀ b ∈ blocksB2Gp193x, 1 ≤ b.1 ∧ b.1 < 110 := by + decide + +/-- **whole-block fact** of `blocksB2Gp193x` at exponent `1 - 7474547/10^10`, fill parameter `s = 40`: the hypothesis `hnum` of `RAM.engine_program_group_list` (u = 110, W = 14692). Relative slack of the rational certificate: 2.37e-12. -/ +theorem fold_B2Gp193x : + ((2:ℝ)^40 - 1) * moment 110 (1 - 7474547/(10:ℝ)^10) blocksB2Gp193x + + ((14692:ℕ):ℝ) * (T 110 (1 - 7474547/(10:ℝ)^10) (110 - 1) 1 + T 110 (1 - 7474547/(10:ℝ)^10) 1 1) + < (2:ℝ)^40 * ((14692:ℕ):ℝ) := by + have hsum : moment 110 (1 - 7474547/(10:ℝ)^10) blocksB2Gp193x + = T 110 (1 - 7474547/(10:ℝ)^10) 1 145890 + (T 110 (1 - 7474547/(10:ℝ)^10) 2 61990 + (T 110 (1 - 7474547/(10:ℝ)^10) 3 49615 + (T 110 (1 - 7474547/(10:ℝ)^10) 4 23685 + (T 110 (1 - 7474547/(10:ℝ)^10) 5 9750 + (T 110 (1 - 7474547/(10:ℝ)^10) 6 8025 + (T 110 (1 - 7474547/(10:ℝ)^10) 7 3530 + (T 110 (1 - 7474547/(10:ℝ)^10) 8 7655 + (T 110 (1 - 7474547/(10:ℝ)^10) 9 2145 + (T 110 (1 - 7474547/(10:ℝ)^10) 10 4650 + (T 110 (1 - 7474547/(10:ℝ)^10) 11 1770 + (T 110 (1 - 7474547/(10:ℝ)^10) 12 5985 + (T 110 (1 - 7474547/(10:ℝ)^10) 13 635 + (T 110 (1 - 7474547/(10:ℝ)^10) 14 3710 + (T 110 (1 - 7474547/(10:ℝ)^10) 15 9395 + (T 110 (1 - 7474547/(10:ℝ)^10) 16 440 + (T 110 (1 - 7474547/(10:ℝ)^10) 17 405 + (T 110 (1 - 7474547/(10:ℝ)^10) 18 13265 + (T 110 (1 - 7474547/(10:ℝ)^10) 19 835 + (T 110 (1 - 7474547/(10:ℝ)^10) 20 110 + (T 110 (1 - 7474547/(10:ℝ)^10) 21 2640 + (T 110 (1 - 7474547/(10:ℝ)^10) 42 2640 + (T 110 (1 - 7474547/(10:ℝ)^10) 46 2640 + 0)))))))))))))))))))))) := rfl + have b0 : T 110 (1 - 7474547/(10:ℝ)^10) 1 145890 ≤ ((16636758090767:ℝ)/12500000000) := + term_le 110 1 145890 (7474547/(10:ℝ)^10) ((2350240182897:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 27 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b1 : T 110 (1 - 7474547/(10:ℝ)^10) 2 61990 ≤ ((22609438945563:ℝ)/20000000000) := + term_le 110 2 61990 (7474547/(10:ℝ)^10) ((2003666592617:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 26 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b2 : T 110 (1 - 7474547/(10:ℝ)^10) 3 49615 ≤ ((135678423202471:ℝ)/100000000000) := + term_le 110 3 49615 (7474547/(10:ℝ)^10) ((1800934038563:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 24 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b3 : T 110 (1 - 7474547/(10:ℝ)^10) 4 23685 ≤ ((43170446048157:ℝ)/50000000000) := + term_le 110 4 23685 (7474547/(10:ℝ)^10) ((1657093002337:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 24 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b4 : T 110 (1 - 7474547/(10:ℝ)^10) 5 9750 ≤ ((44420693582197:ℝ)/100000000000) := + term_le 110 5 9750 (7474547/(10:ℝ)^10) ((38638030667:ℝ)/12500000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 23 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b5 : T 110 (1 - 7474547/(10:ℝ)^10) 6 8025 ≤ ((43867998737293:ℝ)/100000000000) := + term_le 110 6 8025 (7474547/(10:ℝ)^10) ((1454360448283:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 22 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b6 : T 110 (1 - 7474547/(10:ℝ)^10) 7 3530 ≤ ((2250993477097:ℝ)/10000000000) := + term_le 110 7 3530 (7474547/(10:ℝ)^10) ((2754570216739:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 22 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b7 : T 110 (1 - 7474547/(10:ℝ)^10) 8 7655 ≤ ((55781903078171:ℝ)/100000000000) := + term_le 110 8 7655 (7474547/(10:ℝ)^10) ((1310519412057:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 21 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b8 : T 110 (1 - 7474547/(10:ℝ)^10) 9 2145 ≤ ((17582868029823:ℝ)/100000000000) := + term_le 110 9 2145 (7474547/(10:ℝ)^10) ((1251627894229:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 21 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b9 : T 110 (1 - 7474547/(10:ℝ)^10) 10 4650 ≤ ((10587140349809:ℝ)/25000000000) := + term_le 110 10 4650 (7474547/(10:ℝ)^10) ((2997369091:ℝ)/1250000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 21 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b10 : T 110 (1 - 7474547/(10:ℝ)^10) 11 1770 ≤ ((17730489316207:ℝ)/100000000000) := + term_le 110 11 1770 (7474547/(10:ℝ)^10) ((575646273249:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 20 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b11 : T 110 (1 - 7474547/(10:ℝ)^10) 12 5985 ≤ ((65399123107589:ℝ)/100000000000) := + term_le 110 12 5985 (7474547/(10:ℝ)^10) ((1107786858003:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 20 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b12 : T 110 (1 - 7474547/(10:ℝ)^10) 13 635 ≤ ((3758266936203:ℝ)/50000000000) := + term_le 110 13 635 (7474547/(10:ℝ)^10) ((533882752083:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 20 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b13 : T 110 (1 - 7474547/(10:ℝ)^10) 14 3710 ≤ ((47290992642379:ℝ)/100000000000) := + term_le 110 14 3710 (7474547/(10:ℝ)^10) ((2061423036179:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 19 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b14 : T 110 (1 - 7474547/(10:ℝ)^10) 15 9395 ≤ ((128304571925681:ℝ)/100000000000) := + term_le 110 15 9395 (7474547/(10:ℝ)^10) ((498107541173:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 19 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b15 : T 110 (1 - 7474547/(10:ℝ)^10) 16 440 ≤ ((6409229123791:ℝ)/100000000000) := + term_le 110 16 440 (7474547/(10:ℝ)^10) ((963945821777:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 19 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b16 : T 110 (1 - 7474547/(10:ℝ)^10) 17 405 ≤ ((1253566561349:ℝ)/20000000000) := + term_le 110 17 405 (7474547/(10:ℝ)^10) ((933633510869:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 19 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b17 : T 110 (1 - 7474547/(10:ℝ)^10) 18 13265 ≤ ((217357516651669:ℝ)/100000000000) := + term_le 110 18 13265 (7474547/(10:ℝ)^10) ((905054303949:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b18 : T 110 (1 - 7474547/(10:ℝ)^10) 19 835 ≤ ((14441670418763:ℝ)/100000000000) := + term_le 110 19 835 (7474547/(10:ℝ)^10) ((1756041386627:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b19 : T 110 (1 - 7474547/(10:ℝ)^10) 20 110 ≤ ((2002550068509:ℝ)/100000000000) := + term_le 110 20 110 (7474547/(10:ℝ)^10) ((21309351153:ℝ)/12500000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b20 : T 110 (1 - 7474547/(10:ℝ)^10) 21 2640 ≤ ((25231210703361:ℝ)/50000000000) := + term_le 110 21 2640 (7474547/(10:ℝ)^10) ((165595792807:ℝ)/100000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b21 : T 110 (1 - 7474547/(10:ℝ)^10) 42 2640 ≤ ((100872567578631:ℝ)/100000000000) := + term_le 110 42 2640 (7474547/(10:ℝ)^10) ((962810747511:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 15 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b22 : T 110 (1 - 7474547/(10:ℝ)^10) 46 2640 ≤ ((22094393345401:ℝ)/20000000000) := + term_le 110 46 2640 (7474547/(10:ℝ)^10) ((174367793861:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 14 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b23 : T 110 (1 - 7474547/(10:ℝ)^10) 109 1 ≤ ((198183171:ℝ)/200000000) := + term_le 110 109 1 (7474547/(10:ℝ)^10) ((1826496713:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 5 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b24 : T 110 (1 - 7474547/(10:ℝ)^10) 1 1 ≤ ((456145263:ℝ)/50000000000) := + term_le 110 1 1 (7474547/(10:ℝ)^10) ((2350240182897:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 27 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have e1 : ((2:ℝ)^40 - 1) = 1099511627775 := by norm_num + have e2 : (2:ℝ)^40 = 1099511627776 := by norm_num + have e3 : ((14692:ℕ):ℝ) = 14692 := by norm_num + have e4 : T 110 (1 - 7474547/(10:ℝ)^10) (110 - 1) 1 = T 110 (1 - 7474547/(10:ℝ)^10) 109 1 := rfl + rw [e1, e2, e3, e4, hsum] + linarith + +/-- **sharpness**: at exponent `1 - 7474550/10^10` the moment of one unit is at least its number of live roles `14692`, so the moment criterion fails for EVERY table made of copies of the unit and idle roles (`FoldRate.block_fails`). Relative excess of the rational certificate: 1.40e-10. -/ +theorem fold_B2Gp193x_sharp : ((14692:ℕ):ℝ) ≤ moment 110 (1 - 7474550/(10:ℝ)^10) blocksB2Gp193x := by + have hsum : moment 110 (1 - 7474550/(10:ℝ)^10) blocksB2Gp193x + = T 110 (1 - 7474550/(10:ℝ)^10) 1 145890 + (T 110 (1 - 7474550/(10:ℝ)^10) 2 61990 + (T 110 (1 - 7474550/(10:ℝ)^10) 3 49615 + (T 110 (1 - 7474550/(10:ℝ)^10) 4 23685 + (T 110 (1 - 7474550/(10:ℝ)^10) 5 9750 + (T 110 (1 - 7474550/(10:ℝ)^10) 6 8025 + (T 110 (1 - 7474550/(10:ℝ)^10) 7 3530 + (T 110 (1 - 7474550/(10:ℝ)^10) 8 7655 + (T 110 (1 - 7474550/(10:ℝ)^10) 9 2145 + (T 110 (1 - 7474550/(10:ℝ)^10) 10 4650 + (T 110 (1 - 7474550/(10:ℝ)^10) 11 1770 + (T 110 (1 - 7474550/(10:ℝ)^10) 12 5985 + (T 110 (1 - 7474550/(10:ℝ)^10) 13 635 + (T 110 (1 - 7474550/(10:ℝ)^10) 14 3710 + (T 110 (1 - 7474550/(10:ℝ)^10) 15 9395 + (T 110 (1 - 7474550/(10:ℝ)^10) 16 440 + (T 110 (1 - 7474550/(10:ℝ)^10) 17 405 + (T 110 (1 - 7474550/(10:ℝ)^10) 18 13265 + (T 110 (1 - 7474550/(10:ℝ)^10) 19 835 + (T 110 (1 - 7474550/(10:ℝ)^10) 20 110 + (T 110 (1 - 7474550/(10:ℝ)^10) 21 2640 + (T 110 (1 - 7474550/(10:ℝ)^10) 42 2640 + (T 110 (1 - 7474550/(10:ℝ)^10) 46 2640 + 0)))))))))))))))))))))) := rfl + have c0 : ((665470322971:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 1 145890 := + term_ge 110 1 145890 (7474550/(10:ℝ)^10) ((4700480365791:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 4 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c1 : ((565235973477:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 2 61990 := + term_ge 110 2 61990 (7474550/(10:ℝ)^10) ((4007333185231:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 4 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c2 : ((1356784232023:ℝ)/1000000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 3 49615 := + term_ge 110 3 49615 (7474550/(10:ℝ)^10) ((3601868077123:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c3 : ((431704460547:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 4 23685 := + term_ge 110 4 23685 (7474550/(10:ℝ)^10) ((3314186004671:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c4 : ((44420693593:ℝ)/100000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 5 9750 := + term_ge 110 5 9750 (7474550/(10:ℝ)^10) ((3091042453357:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c5 : ((87735997501:ℝ)/200000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 6 8025 := + term_ge 110 6 8025 (7474550/(10:ℝ)^10) ((2908720896563:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c6 : ((112549673893:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 7 3530 := + term_ge 110 7 3530 (7474550/(10:ℝ)^10) ((86080319273:ℝ)/31250000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c7 : ((557819030987:ℝ)/1000000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 8 7655 := + term_ge 110 8 7655 (7474550/(10:ℝ)^10) ((2621038824111:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c8 : ((87914340183:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 9 2145 := + term_ge 110 9 2145 (7474550/(10:ℝ)^10) ((500651157691:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c9 : ((423485614161:ℝ)/1000000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 10 4650 := + term_ge 110 10 4650 (7474550/(10:ℝ)^10) ((2397895272797:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c10 : ((88652446617:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 11 1770 := + term_ge 110 11 1770 (7474550/(10:ℝ)^10) ((2302585092993:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c11 : ((130798246269:ℝ)/200000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 12 5985 := + term_ge 110 12 5985 (7474550/(10:ℝ)^10) ((2215573716003:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c12 : ((15033067751:ℝ)/200000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 13 635 := + term_ge 110 13 635 (7474550/(10:ℝ)^10) ((2135531008329:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c13 : ((23645496331:ℝ)/50000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 14 3710 := + term_ge 110 14 3710 (7474550/(10:ℝ)^10) ((128838939761:ℝ)/62500000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c14 : ((320761429947:ℝ)/250000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 15 9395 := + term_ge 110 15 9395 (7474550/(10:ℝ)^10) ((1992430164689:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 12 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c15 : ((1001442051:ℝ)/15625000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 16 440 := + term_ge 110 16 440 (7474550/(10:ℝ)^10) ((1927891643551:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c16 : ((62678328093:ℝ)/1000000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 17 405 := + term_ge 110 17 405 (7474550/(10:ℝ)^10) ((373453404347:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c17 : ((1086787583699:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 18 13265 := + term_ge 110 18 13265 (7474550/(10:ℝ)^10) ((362021721579:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c18 : ((28883340849:ℝ)/200000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 19 835 := + term_ge 110 19 835 (7474550/(10:ℝ)^10) ((13719073333:ℝ)/7812500000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c19 : ((20025500693:ℝ)/1000000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 20 110 := + term_ge 110 20 110 (7474550/(10:ℝ)^10) ((1704748092237:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c20 : ((63078026783:ℝ)/125000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 21 2640 := + term_ge 110 21 2640 (7474550/(10:ℝ)^10) ((1655957928067:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c21 : ((126090709507:ℝ)/125000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 42 2640 := + term_ge 110 42 2640 (7474550/(10:ℝ)^10) ((240702686877:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 1 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c22 : ((552359833771:ℝ)/500000000) ≤ T 110 (1 - 7474550/(10:ℝ)^10) 46 2640 := + term_ge 110 46 2640 (7474550/(10:ℝ)^10) ((435919484651:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 1 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have e3 : ((14692:ℕ):ℝ) = 14692 := by norm_num + rw [e3, hsum] + linarith + +/-- **per-rank fact** at exponent `1 - 4058344/10^10`, fill parameter `s = 40`: the hypothesis `hnum` of `RAM.engine_program_group_perRank` (u = 110, W = 14692, D = 3080). Relative slack: 1.10e-07. -/ +theorem foldRank_B2Gp193x : + (2:ℝ)^40 * ((14692:ℕ):ℝ) * (((110:ℕ):ℝ) - ((110:ℕ):ℝ)^(1 - 4058344/(10:ℝ)^10)) < ((2:ℝ)^40 - 1) * ((3080:ℕ):ℝ) := + FoldRate.rank_fact3 110 14692 3080 40 (4058344/(10:ℝ)^10) ((2350240182897:ℝ)/500000000000) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 27 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + +/-- **per-rank sharpness**: at exponent `1 - 4058349/10^10` the deficit of one unit is at most `W (m - m^z)`, so the per-rank inequality fails for EVERY table made of copies of the unit and idle roles (`FoldRate.rank_fails`). -/ +theorem foldRank_B2Gp193x_sharp : + ((3080:ℕ):ℝ) ≤ ((14692:ℕ):ℝ) * (((110:ℕ):ℝ) - ((110:ℕ):ℝ)^(1 - 4058349/(10:ℝ)^10)) := + FoldRate.rank_fact_sharp 110 14692 3080 (4058349/(10:ℝ)^10) ((4700480365791:ℝ)/1000000000000) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 4 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + +end OAI.PowerSaving.BlockAccounting + +#print axioms OAI.PowerSaving.BlockAccounting.fold_B2Gp193x +#print axioms OAI.PowerSaving.BlockAccounting.fold_B2Gp193x_sharp +#print axioms OAI.PowerSaving.BlockAccounting.foldRank_B2Gp193x +#print axioms OAI.PowerSaving.BlockAccounting.foldRank_B2Gp193x_sharp diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Raw.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Raw.lean new file mode 100644 index 0000000000..499fa67e88 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__Raw.lean @@ -0,0 +1,93 @@ +/-! +# (key: gx-data) Raw Lean form of a `gcert/1` file (EXTENDED-CERT-SPEC section 1) + +Core Lean only (no Mathlib): the generated data modules import nothing else, so they elaborate +cheaply. Field order and meaning are those of the JSON; `pairs` and `cuts` are DERIVED by the +generator (`checks/wht26/gx-data/py/gxgen.py`) and must be tested by the label check. + +Registers: `x_t = t`, `y_t = v + t`, slot `k = 2 v + k`. Vectors are bit masks. +-/ + +namespace GXD + +/-- the rational `(-1)^neg * num / den` (`den > 0`) -/ +structure Co where + neg : Bool + num : Nat + den : Nat + deriving DecidableEq, Repr + +/-- a gate: every register named (extras too) first moves to `frame`; then the adds happen in order -/ +inductive Gate where + /-- `tgt += co * src` for each `(tgt, co)` -/ + | out (frame src : Nat) (tgts : List (Nat × Co)) (extra : List Nat) + /-- `tgt += co * src` for each `(src, co)` -/ + | inn (frame tgt : Nat) (srcs : List (Nat × Co)) + deriving Repr + +/-- the scatter `y_t += sum over k of coef(t, k) * total k` -/ +inductive Scat where + /-- star rule: `inside` if coordinate `k` is in port `t`, else `outside` -/ + | star (inside outside : Co) + /-- explicit rows: row `t` = `[(total k, coef)]` -/ + | table (rows : List (List (Nat × Co))) + deriving Repr + +/-- a `gcert/1` file -/ +structure Raw where + h : Nat + v : Nat + R : Nat + N : Nat + cst : Nat + /-- `v` masks: the unit vectors of the ports -/ + ports : List Nat + /-- CHUNKED frame table (`flatten` = the table); an entry is a reduced echelon basis, leading bits descending -/ + frames : List (List (List Nat)) + /-- frame id per register at the start -/ + start : List Nat + /-- frame id per register at the end -/ + final : List Nat + /-- position `k` = retained total `k`: (slot REGISTER, frame id) -/ + ret : List (Nat × Nat) + scat : Scat + /-- CHUNKED gates before the scatter -/ + A : List (List Gate) + /-- CHUNKED gates after the scatter -/ + B : List (List Gate) + /-- CHUNKED, derived: the distinct climbs `(a, b)`, `a ≠ b`, in order of first use -/ + pairs : List (List (Nat × Nat)) + /-- derived: replay cut points `(gates of A ++ B before the cut, frame id per register there)` -/ + cuts : List (Nat × List Nat) + /-- slots that start off the zero frame `(slot REGISTER, frame id)` (rule 2); EMPTY on the path -/ + ext : List (Nat × Nat) + /-- derived (questions.md Q1): per port `h` masks, the first is the port, pairwise dots = delta + (an orthonormal basis of `F_2^h` through the port) -/ + obase : List (List Nat) + +/-- registers of a gate, in the order they are moved -/ +def Gate.regs : Gate → List Nat + | .out _ s ts ex => s :: (ts.map Prod.fst ++ ex) + | .inn _ t ss => t :: ss.map Prod.fst + +/-- frame of a gate -/ +def Gate.frame : Gate → Nat + | .out f _ _ _ => f + | .inn f _ _ => f + +/-- single adds `(tgt, src, co)` of a gate, in order -/ +def Gate.adds : Gate → List (Nat × Nat × Co) + | .out _ s ts _ => ts.map fun p => (p.1, s, p.2) + | .inn _ t ss => ss.map fun p => (t, p.1, p.2) + +/-- the frame table -/ +def Raw.frameTab (c : Raw) : List (List Nat) := c.frames.flatten + +/-- all gates of phase A / phase B -/ +def Raw.gatesA (c : Raw) : List Gate := c.A.flatten +def Raw.gatesB (c : Raw) : List Gate := c.B.flatten + +/-- number of registers -/ +def Raw.nreg (c : Raw) : Nat := 2 * c.v + c.R + +end GXD diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__SolutionB2Gp193x.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__SolutionB2Gp193x.lean new file mode 100644 index 0000000000..0392e1f05b --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GCert__Data__SolutionB2Gp193x.lean @@ -0,0 +1,38 @@ +import Work.GCert.Data.B2Gp193Main + +/-! +Comparator solution `Work.GCert.Data.SolutionB2Gp193x` (not part of github.com/openai/math). + +The whole proof is in `Work.GCert.Data.B2Gp193Main` (and its imports), which ends with + + theorem wht_main_B2Gp193x : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 7474547/(10:ℝ)^10) W + +This module adds nothing mathematical: it defines `WHT.WHTTimeBoundsAt` with the text of the +challenge (the same definition as `BlockWHT.WHTTimeBoundsAt` of `Work.Block.WHT`) and restates +the theorem under the name the challenge uses. Its proof is that single term. +`WHTProgram`, `wht`, `whtInKind`, `whtOutKind` come from `WHTCheck.Solution`. +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open Filter Asymptotics + +/-- `W = O(2^k (k+1)^β)` and `W = o(2^k k)` (`WHTTimeBounds` is the case `β = 1 - 2/10^11`). -/ +def WHTTimeBoundsAt (β : ℝ) (W : ℕ → ℕ) : Prop := + let W' := fun k : ℕ => (W k : ℝ) + W' =O[atTop] (fun k : ℕ => (2:ℝ)^k * ((k:ℝ)+1)^β) ∧ + W' =o[atTop] (fun k : ℕ => (2:ℝ)^k * (k:ℝ)) + +/-- **Walsh-Hadamard transform with the improved exponent**: the statement `WHTGoal` of +`WHTCheck/Challenge.lean` with `1 - 2/10^11` replaced by `1 - 7474547/10^10`. -/ +theorem wht_main_block_B2Gp193x : + ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 7474547/(10:ℝ)^10) W := + wht_main_B2Gp193x + +end WHT +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.WHT.wht_main_block_B2Gp193x diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Adapt.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Adapt.lean new file mode 100644 index 0000000000..24e261ad08 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Adapt.lean @@ -0,0 +1,183 @@ +import Work.GFrame.Engine.Letters + +/-! +# GFrame engine, part 2: the free adapter letters in the RAM (agent key: eng-ram) + +One free adapter on the array of one role is ONE linear pass, no recursive call: + +* `Gear.permuted` the address of `x ↦ G.π x` (columnwise), O(1) per entry with the XOR table + (as `Gear.shifted`, through `Gear.body_additive` of `Work/Block/Address.lean`); +* `Gear.phase_row` the `f`-bit row `(z·x_j + c)_j` of an entry, O(1); +* `GRig` a rig together with the table of `lum` over `Bits f` (`i^popcount`); +* `Rig.perm_cost`, `GRig.phase_cost` the two letters, work = length of the role table. +-/ + +set_option linter.unusedSectionVars false + +namespace OAI +namespace PowerSaving.GF +open Binary Matrix Finset +noncomputable section +section +variable {α : Type*} [Fintype α] [DecidableEq α] + +/-- An address permutation acts on an array with `f` columns by moving the address. -/ +lemma act_perm (G : APerm α) (f : ℕ) (x : Sky α f → ℂ) (j : Sky α f) : + matAct f (permMat G) x j = x (fun k => G.π (j k)) := by + change ∑ i, digitProd (fun _ : Fin f => permMat G) j i * x i = _ + have h (i : Sky α f) : digitProd (fun _ : Fin f => permMat G) j i = + if (fun k => G.π (j k)) = i then 1 else 0 := + prod_delta (κ:=fun _ : Fin f => Space α) _ _ + simp_rw [h] + simp [ite_mul] + +/-- A diagonal phase acts by the scalar `lum` of the row of phase bits. -/ +lemma act_phase (z : Space α) (c : F) (f : ℕ) (x : Sky α f → ℂ) (j : Sky α f) : + matAct f (phaseMat z c) x j = lum (fun k : Fin f => dot z (j k) + c) * x j := by + unfold matAct phaseMat + rw [digitProd_diagonal, Matrix.mulVec_diagonal] + rfl + +end +end +end PowerSaving.GF + +namespace PowerSaving.RAM +open Binary Ty Finset GF +noncomputable section +universe U V +variable {ι : Type U} + +namespace Gear +variable {m : Bool} {B f : ι → ℕ} {s t : Ty} {x : ι → T s} +variable (g : Gear m B f s x) +include g +variable {α : Type*} [Fintype α] [DecidableEq α] (X : Layout α) (r : ℕ) + +/-- Address moved by an additive bijection (across the `f` columns). -/ +lemma permuted (G : APerm α) (v : ∀ i, Grid α r (f i)) + (h : Knows m B s x (fun i => (book X r (f i)).loc (v i))) : + Knows m B s x (fun i => (book X r (f i)).loc ((v i).1, + fun j => G.π ((v i).2 j))) := by + obtain ⟨hg, hh⟩ := g.grid_fetch X r (v:=v) h + let K (i : ι) : Grid α r (f i) := ((v i).1, fun j => G.π ((v i).2 j)) + apply g.grid_combine X r (v:=K) hg (g.body_set X (fun i => (K i).2) _) + intro a + exact g.body_additive X (fun y => G.π y a) (fun p q => by rw [G.add]; rfl) + (fun i => (v i).2) hh + +/-- The row of phase bits `(z·x_j + c)_j` of an address. -/ +lemma phase_row (z : Space α) (c : F) (v : ∀ i, Grid α r (f i)) + (h : Knows m B s x (fun i => (book X r (f i)).loc (v i))) : + Knows m B s x (fun i => (bits (f i)).loc (fun l : Fin (f i) => dot z ((v i).2 l) + c)) := by + obtain ⟨_, hh⟩ := g.grid_fetch X r (v:=v) h + have hv := g.body_additive X (fun y => dot z y) (fun p q => dot_add_right z p q) + (fun i => (v i).2) hh + rcases bit_cases c with hc|hc + · refine hv.cong (fun _ => rfl) (fun i => ?_) + simp [hc] + · let q i : Bits (f i) × Bits (f i) := (fun l => dot z ((v i).2 l), fun _ => 1) + have hf : Knows m B s x (fun i => (bits (f i)).loc (q i).2) := + (g.power.minus (Can.wc 1) g.bound).cong (fun _ => rfl) (fun i => by + change 2^f i-1=(bits _).loc (fun _ => 1) + rw [← bits_lit] + simp) + refine (g.addr_xor q hv hf).cong (fun _ => rfl) (fun i => ?_) + apply congr_arg (bits (f i)).loc + ext k; simp [q,hc] + +end Gear + +/-- A rig together with the table of `lum` over `Bits f` (the fourth roots `i^popcount`). -/ +structure GRig {α ρ : Type*} (m : Bool) (B f : ι → ℕ) (s : Ty) (x : ι → T s) + (cl : Paint) (X : Layout α) (R : Layout ρ) (r : ℕ) (v : ∀ i, Grain α ρ r (f i)) : Prop where + rig : Rig m B f s x cl X R r v + lumT : Has m B s (a sc) x fun i => (bits (f i)).tape (fun y : Bits (f i) => lum y) + +section +variable {α ρ : Type*} [Fintype α] [DecidableEq α] [Fintype ρ] [DecidableEq ρ] +variable {m : Bool} {B f : ι → ℕ} {s t : Ty} {x : ι → T s} + {cl : Paint} {X : Layout α} {R : Layout ρ} {r : ℕ} {v : ∀ i, Grain α ρ r (f i)} + +omit [Fintype α] [DecidableEq α] [Fintype ρ] [DecidableEq ρ] in +lemma GRig.gather (h : GRig m B f s x cl X R r v) {κ : Type V} (j : κ → ι) (y : κ → T t) + (g : Has m (fun k => B (j k)) t s y (fun k => x (j k))) : + GRig m (fun k => B (j k)) (fun k => f (j k)) t y cl X R r (fun k => v (j k)) := + ⟨h.rig.gather j y g, g.then_do (h.lumT.reindex j)⟩ + +lemma Rig.ferry_perm (h : Rig m B f s x cl X R r v) (l : ρ) (G : APerm α) + (q : ∀ i, Beach α ρ r (f i)) + (g : Knows m B s x fun i => (fleet X R r (f i)).loc (q i)) : + Has m B s (c cl) x fun i => ferryM r (f i) l (permMat G) (v i) (q i) := by + obtain ⟨hl,hk⟩ := h.addrs q g + have hb := h.read q hl hk + let t i : Beach α ρ r (f i) := ((q i).1,(q i).2.1,fun j => G.π ((q i).2.2 j)) + have hh := h.read t hl (h.gear.permuted X r G _ hk) + apply Can.cases_code (q:=fun i => (q i).1) R hl + intro p + by_cases he : p=l + · refine (hh.reindex (fun i : {i // (q i).1=p} => i.1)).cong (fun _ => rfl) + (fun i => ?_) + have hql : (q i.val).1 = l := i.property.trans he + change v i.val ((q i.val).1,(q i.val).2.1,fun j => G.π ((q i.val).2.2 j)) = _ + simp only [ferryM, roleAct, hql, if_true, act_perm] + · refine (hb.reindex (fun i : {i // (q i).1=p} => i.1)).cong (fun _ => rfl) + (fun i => ?_) + have H : (q i.val).1≠l := fun hh => he (i.property.symm.trans hh) + simp only [ferryM, roleAct, H, ite_false, Prod.mk.eta] + +/-- **Free address permutation**: one pass over the role table. -/ +lemma Rig.perm_cost (h : Rig m B f s x cl X R r v) (l : ρ) (G : APerm α) : + Can m B s (a (c cl)) x + (fun i => (fleet X R r (f i)).tape (ferryM r (f i) l (permMat G) (v i))) + (fun i => (fleet X R r (f i)).n) := by + refine h.chart _ ?_ + let S := Σ i, Beach α ρ r (f i) + have hg := h.gather (fun d : S => d.1) + (fun d => ((x d.1, (fleet X R r (f d.1)).loc d.2):T (p s w))) (t:=p s w) Can.first + exact hg.ferry_perm l G (fun d => d.2) Can.second + +lemma GRig.ferry_phase (h : GRig m B f s x cl X R r v) (l : ρ) (z : Space α) (c' : F) + (q : ∀ i, Beach α ρ r (f i)) + (g : Knows m B s x fun i => (fleet X R r (f i)).loc (q i)) : + Has m B s (c cl) x fun i => ferryM r (f i) l (phaseMat z c') (v i) (q i) := by + obtain ⟨hl,hk⟩ := h.rig.addrs q g + have hb := h.rig.read q hl hk + have hrow := h.rig.gear.phase_row X r z c' (fun i => (q i).2) hk + have hs : Has m B s sc x + (fun i => lum (fun k : Fin (f i) => dot z ((q i).2.2 k) + c')) := + Can.fetch (t:=sc) (L:=fun i => bits (f i)) (v:=fun i (y : Bits (f i)) => lum y) + (i:=fun i => (fun k : Fin (f i) => dot z ((q i).2.2 k) + c')) h.lumT hrow + have hh := hs.mul hb + apply Can.cases_code (q:=fun i => (q i).1) R hl + intro p + by_cases he : p=l + · refine (hh.reindex (fun i : {i // (q i).1=p} => i.1)).cong (fun _ => rfl) + (fun i => ?_) + have hql : (q i.val).1 = l := i.property.trans he + change lum (fun k : Fin (f i.val) => dot z ((q i.val).2.2 k) + c') * + v i.val ((q i.val).1,(q i.val).2.1,(q i.val).2.2) = _ + simp only [ferryM, roleAct, hql, if_true, act_phase] + · refine (hb.reindex (fun i : {i // (q i).1=p} => i.1)).cong (fun _ => rfl) + (fun i => ?_) + have H : (q i.val).1≠l := fun hh => he (i.property.symm.trans hh) + simp only [ferryM, roleAct, H, ite_false, Prod.mk.eta] + +/-- **Free diagonal phase**: one pass over the role table (one table look-up per entry). -/ +lemma GRig.phase_cost (h : GRig m B f s x cl X R r v) (l : ρ) (z : Space α) (c' : F) : + Can m B s (a (c cl)) x + (fun i => (fleet X R r (f i)).tape (ferryM r (f i) l (phaseMat z c') (v i))) + (fun i => (fleet X R r (f i)).n) := by + refine h.rig.chart _ ?_ + let S := Σ i, Beach α ρ r (f i) + have hg := h.gather (fun d : S => d.1) + (fun d => ((x d.1, (fleet X R r (f d.1)).loc d.2):T (p s w))) (t:=p s w) Can.first + exact hg.ferry_phase l z c' (fun d => d.2) Can.second + +end +end +end PowerSaving.RAM +end OAI + +#print axioms OAI.PowerSaving.RAM.Rig.perm_cost +#print axioms OAI.PowerSaving.RAM.GRig.phase_cost diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Letters.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Letters.lean new file mode 100644 index 0000000000..2eca6e713b --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Letters.lean @@ -0,0 +1,199 @@ +import Work.Block.Bridge + +/-! +# GFrame engine, part 1: the generalised word language (agent key: eng-ram) + +Letters = the letters of `BWord` (`localM`, `shift`, `block`) plus TWO FREE ADAPTER letters on +one role: + +* `perm l G` address permutation by an additive bijection `G` of the label space + (matrix `permMat G`, `(permMat G) x y = 1` iff `G.π x = y`); +* `phase l z c` the diagonal phase `i^[z·x + c]` IN THE STANDARD BASIS + (matrix `phaseMat z c = diagonal (fun x => tint (dot z x + c))`). + +Products of `phaseMat` are exactly the diagonal matrices `i^Q(x)`, `Q` a `ℤ/4`-valued quadratic +form plus a constant; with the old free letter `shift` the free letters generate every affine +address permutation times such a phase. A "twisted block" is NOT a primitive letter: it is the +word `free adapters ++ [block] ++ free adapters` (see `Free.lean`, `gstep_of_factor`). + +The semantics is `gwalk` (no unit-move word behind it: the new letters are not Walsh-diagonal). +Old words embed by `GWord.ofB`, and `gwalk f (ofB w) = walk f w.flat`. +-/ + +set_option linter.unusedSectionVars false + +namespace OAI +namespace PowerSaving.GF +open Binary Matrix Finset +noncomputable section + +/-- An additive bijection of the label space. -/ +structure APerm (α : Type*) where + π : Space α ≃ Space α + add : ∀ x y, π (x + y) = π x + π y + +section Mats +variable {α : Type*} [Fintype α] [DecidableEq α] + +/-- Permutation matrix of an additive bijection: `(permMat G *ᵥ v) x = v (G.π x)`. -/ +def permMat (G : APerm α) : CMat α := fun x y => if G.π x = y then 1 else 0 + +/-- Elementary diagonal phase in the standard basis: `i^[z·x + c]`. -/ +def phaseMat (z : Space α) (c : F) : CMat α := Matrix.diagonal fun x => tint (dot z x + c) + +end Mats + +/-- Letters of the generalised word language. -/ +inductive GMove (α ρ : Type*) + | old (mv : BMove α ρ) + | perm (l : ρ) (G : APerm α) + | phase (l : ρ) (z : Space α) (c : F) + +abbrev GWord (α ρ : Type*) := List (GMove α ρ) + +namespace GMove +variable {α ρ : Type*} + +/-- The letter of `BWord` with the same price (free adapters ↦ a free letter). -/ +def shadow : GMove α ρ → BMove α ρ + | .old mv => mv + | .perm _ _ => .localM 0 + | .phase _ _ _ => .localM 0 + +/-- Rank paid by a letter (`none` = free). -/ +def rk? (mv : GMove α ρ) : Option ℕ := mv.shadow.rk? +def costR (φ : ℕ → ℝ) (mv : GMove α ρ) : ℝ := mv.shadow.costR φ +def Proper (u : ℕ) (mv : GMove α ρ) : Prop := mv.shadow.Proper u + +@[simp] lemma costR_perm (φ : ℕ → ℝ) (l : ρ) (G : APerm α) : + (GMove.perm l G : GMove α ρ).costR φ = 0 := rfl +@[simp] lemma costR_phase (φ : ℕ → ℝ) (l : ρ) (z : Space α) (c : F) : + (GMove.phase l z c : GMove α ρ).costR φ = 0 := rfl +@[simp] lemma costR_old (φ : ℕ → ℝ) (mv : BMove α ρ) : (GMove.old mv).costR φ = mv.costR φ := rfl +lemma proper_perm (u : ℕ) (l : ρ) (G : APerm α) : (GMove.perm l G : GMove α ρ).Proper u := + trivial +lemma proper_phase (u : ℕ) (l : ρ) (z : Space α) (c : F) : + (GMove.phase l z c : GMove α ρ).Proper u := trivial +@[simp] lemma proper_old (u : ℕ) (mv : BMove α ρ) : (GMove.old mv).Proper u ↔ mv.Proper u := + Iff.rfl + +end GMove + +namespace GWord +variable {α ρ : Type*} + +def shadow (w : GWord α ρ) : BWord α ρ := w.map GMove.shadow +def costR (φ : ℕ → ℝ) (w : GWord α ρ) : ℝ := (w.map (GMove.costR φ)).sum +def Proper (u : ℕ) (w : GWord α ρ) : Prop := ∀ mv ∈ w, mv.Proper u +def hist (w : GWord α ρ) (r : ℕ) : ℕ := w.shadow.hist r +/-- Natural-number cost when a block of rank `rk` costs `g rk`. -/ +def cost (g : ℕ → ℕ) (w : GWord α ρ) : ℕ := w.shadow.cost g +/-- An old block word as a generalised word. -/ +def ofB (w : BWord α ρ) : GWord α ρ := w.map GMove.old + +@[simp] lemma shadow_nil : shadow ([] : GWord α ρ) = [] := rfl +@[simp] lemma shadow_cons (mv : GMove α ρ) (w : GWord α ρ) : + shadow (mv :: w) = mv.shadow :: shadow w := rfl +@[simp] lemma shadow_ofB (w : BWord α ρ) : shadow (ofB w) = w := by + simp [shadow, ofB, List.map_map, Function.comp_def, GMove.shadow] + +lemma costR_shadow (φ : ℕ → ℝ) (w : GWord α ρ) : costR φ w = BWord.costR φ w.shadow := by + unfold costR BWord.costR shadow + rw [List.map_map] + rfl +@[simp] lemma costR_nil (φ : ℕ → ℝ) : costR φ ([] : GWord α ρ) = 0 := rfl +lemma costR_cons (φ : ℕ → ℝ) (mv : GMove α ρ) (w : GWord α ρ) : + costR φ (mv :: w) = mv.costR φ + costR φ w := by simp [costR] +lemma costR_append (φ : ℕ → ℝ) (w w' : GWord α ρ) : + costR φ (w ++ w') = costR φ w + costR φ w' := by simp [costR] +lemma costR_ofB (φ : ℕ → ℝ) (w : BWord α ρ) : costR φ (ofB w) = BWord.costR φ w := by + rw [costR_shadow, shadow_ofB] +@[simp] lemma cost_nil (g : ℕ → ℕ) : cost g ([] : GWord α ρ) = 0 := rfl +lemma cost_cons (g : ℕ → ℕ) (mv : GMove α ρ) (w : GWord α ρ) : + cost g (mv :: w) = mv.shadow.cost g + cost g w := BWord.cost_cons g _ _ + +lemma Proper.shadow {u : ℕ} {w : GWord α ρ} (h : Proper u w) : BWord.Proper u w.shadow := by + intro mv hmv + obtain ⟨g, hg, rfl⟩ := List.mem_map.mp hmv + exact h g hg +lemma Proper.tail {u : ℕ} {mv : GMove α ρ} {w : GWord α ρ} (h : Proper u (mv :: w)) : + Proper u w := fun x hx => h x (List.mem_cons_of_mem _ hx) +lemma Proper.head {u : ℕ} {mv : GMove α ρ} {w : GWord α ρ} (h : Proper u (mv :: w)) : + mv.Proper u := h mv List.mem_cons_self +lemma Proper.append {u : ℕ} {w w' : GWord α ρ} (h : Proper u w) (h' : Proper u w') : + Proper u (w ++ w') := by + intro mv hmv + rcases List.mem_append.mp hmv with h1|h1 + · exact h mv h1 + · exact h' mv h1 +lemma proper_nil (u : ℕ) : Proper u ([] : GWord α ρ) := fun _ h => by simp at h +lemma proper_ofB {u : ℕ} {w : BWord α ρ} (h : w.Proper u) : Proper u (ofB w) := by + intro mv hmv + obtain ⟨g, hg, rfl⟩ := List.mem_map.mp hmv + exact h g hg + +lemma costR_eq_sum (u : ℕ) (φ : ℕ → ℝ) (w : GWord α ρ) (hw : Proper u w) : + costR φ w = ∑ r : Fin u, (w.hist r:ℝ) * φ r := by + rw [costR_shadow]; exact BWord.costR_eq_sum u φ _ hw.shadow +lemma cost_eq_sum (u : ℕ) (g : ℕ → ℕ) (w : GWord α ρ) (hw : Proper u w) : + cost g w = ∑ r : Fin u, hist w r * g r := BWord.cost_eq_sum u g _ hw.shadow +lemma hist_zero (u : ℕ) (w : GWord α ρ) (hw : Proper u w) : hist w 0 = 0 := + BWord.hist_zero u _ hw.shadow +lemma hist_large (u : ℕ) (w : GWord α ρ) (hw : Proper u w) (r : ℕ) (hr : u ≤ r) : + hist w r = 0 := BWord.hist_large u _ hw.shadow r hr + +end GWord + +section Sem +variable {α ρ σ : Type*} [Fintype α] [DecidableEq α] [Fintype ρ] [DecidableEq ρ] + +/-- The action of one letter. -/ +def GMove.act (f : ℕ) : GMove α ρ → Data α ρ f → Data α ρ f + | .old mv => mv.act f + | .perm l G => roleAct f l (permMat G) + | .phase l z c => roleAct f l (phaseMat z c) + +/-- **Semantics of a generalised word.** -/ +def gwalk (f : ℕ) (w : GWord α ρ) (x : Data α ρ f) : Data α ρ f := + w.foldl (fun y mv => mv.act f y) x + +@[simp] lemma gwalk_nil (f : ℕ) (x : Data α ρ f) : gwalk f ([] : GWord α ρ) x = x := rfl +lemma gwalk_cons (f : ℕ) (mv : GMove α ρ) (w : GWord α ρ) (x : Data α ρ f) : + gwalk f (mv :: w) x = gwalk f w (mv.act f x) := rfl +lemma gwalk_append (f : ℕ) (p q : GWord α ρ) (x : Data α ρ f) : + gwalk f (p ++ q) x = gwalk f q (gwalk f p x) := by simp [gwalk] + +/-- Old words keep their meaning. -/ +lemma gwalk_ofB (f : ℕ) (w : BWord α ρ) (x : Data α ρ f) : + gwalk f (GWord.ofB w) x = walk f w.flat x := by + induction w generalizing x with + | nil => rfl + | cons mv w ih => + rw [walk_flat_cons, ← ih] + rfl + +/-- The scratch certificate for the generalised language (cf. `RAM.LiveKernel`). -/ +def GLiveKernel (e : σ → ρ) (w : GWord α ρ) : Prop := + ∀ (f : ℕ) (v : Data α ρ f), (∀ s, (∀ l, e l ≠ s) → v s = 0) → + ∀ l, gwalk f w v (e l) = matAct f (kernel α) (v (e l)) + +/-- Every old certificate is a generalised certificate. -/ +theorem GLiveKernel.ofB {e : σ → ρ} {w : BWord α ρ} (h : RAM.LiveKernel e w.flat) : + GLiveKernel e (GWord.ofB w) := by + intro f v hv l + rw [gwalk_ofB] + exact h f v hv l + +/-- One role goes from matrix `M` to `N` by a generalised word (cf. `XStep`). -/ +def GStep (l : ρ) (M N : CMat α) (c : (ℕ → ℝ) → ℝ) : Prop := + ∃ (w : GWord α ρ) (U : CMat α), w.Proper (Fintype.card α) ∧ (∀ φ, w.costR φ = c φ) ∧ + U * M = N ∧ ∀ (f : ℕ) (x : Data α ρ f), gwalk f w x = roleAct f l U x + +end Sem +end +end PowerSaving.GF +end OAI + +#print axioms OAI.PowerSaving.GF.gwalk_ofB +#print axioms OAI.PowerSaving.GF.GLiveKernel.ofB +#print axioms OAI.PowerSaving.GF.GWord.costR_eq_sum diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Level.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Level.lean new file mode 100644 index 0000000000..6bd7cfa0c3 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/Work__GFrame__Engine__Level.lean @@ -0,0 +1,163 @@ +import Work.GFrame.Engine.Sweep +import WHTCheck.Solution + +/-! +# GFrame engine, part 4: one level of the recursion for generalised words (agent key: eng-ram) + +Copy of `amplifyB` (`Work/Block/Recursion.lean`) with two changes: + +* the word is a `GWord` with certificate `GLiveKernel e w` (semantics `gwalk`); +* after the XOR table the level also builds the table of `lum` over `Bits f` + (`WHT.lum_tables`, doubling construction, `O(2^f)` work), which the free diagonal phases + read; it is part of the environment of the sweep (`GRig`). + +Cost: the same `2^k` linear term and the same recursive calls as `amplifyB`. +-/ + +set_option linter.unusedSectionVars false + +namespace OAI +namespace PowerSaving.RAM +open Binary Matrix Ty Finset GF +noncomputable section + +section +universe U +variable {α ρ σ : Type*} [Fintype α] [DecidableEq α] [Fintype ρ] [DecidableEq ρ] + [Fintype σ] [DecidableEq σ] +variable {ι : Type U} {m : Bool} + {k f : ι → ℕ} {cl : Paint} {b : Bank (hatch cl) ι} + {v : ∀ i, Sim σ (k i)→ℂ} + +/-- **One level of the recursion for a generalised word** (replaces `amplifyB`). -/ +lemma gamplify (m : Bool) (b : Bank (hatch cl) ι) (v : ∀ i, Sim σ (k i) → ℂ) + (X : Layout α) (R : Layout ρ) (Q : Layout σ) (e : σ → ρ) (he : Function.Injective e) + (r : ℕ) (hr : 3 ≤ X.n) (hq : ∀ i, X.n*f i+r=k i) (hd : r < X.n) (hQ : 0 rk * f i) (τ rk) Q) + (hB : Small b.B (fun i => 2^k i)) + (w : GWord α ρ) (hw : GLiveKernel e w) (hP : w.Proper X.n) : + Able m b (simIn cl) (bundle cl) (fun i => loaded cl Q (k i) (v i)) + (fun i => (sim Q (k i)).tape (whole (k i) (v i))) + (fun i => 2^k i) (fun i => w.cost (fun rk => n rk i * τ rk i)) := by + let W i := 2^k i + let s := simIn cl + let eQ (i : ι) := ebb X r (f i) (k i) (hq i) (v i) + let zQ (i : ι) : Grain α σ r (f i) := + fun j => chords r (f i) (fun l => eQ i (j.1,l)) j.2 + let Z (i : ι) : Grain α ρ r (f i) := crossAct r (f i) (embM e) (zQ i) + let O (i : ι) : Grain α σ r (f i) := + crossAct r (f i) (extM e) (gcoast r (f i) w (Z i)) + let szQ i := (fleet X Q r (f i)).n + let szR i := (fleet X R r (f i)).n + have hszQ : Dom W szQ := by + refine ⟨Q.n+1, fun i => ?_⟩ + unfold W szQ fleet + rw [Layout.pair_len, book_len,hq] + simp only [mul_add,add_mul,mul_one,one_mul] + gcongr <;> simp + have hszR : Dom W szR := by + refine ⟨R.n+1, fun i => ?_⟩ + unfold W szR fleet + rw [Layout.pair_len, book_len,hq] + simp only [mul_add,add_mul,mul_one,one_mul] + gcongr <;> simp + have hn (i : ι) : 0 < W i := pow_pos (by decide) _ + have hf (i) : f i ≤ k i := by + have g := hq i + have h := Nat.le_mul_of_pos_left (f i) (show 0 < X.n by omega) + omega + have hy (i) : k i ≤ W i := Nat.lt_two_pow_self.le + have sd := hB.mono hy + have sq := sd.mono hf + let p2 i := 2^f i + have hm : Small b.B p2 := + hB.mono (fun i => Nat.pow_le_pow_right (by omega) (hf i)) + have hcube (i) : p2 i ^ 3 ≤ W i := by + unfold p2 W + rw [← pow_mul] + apply Nat.pow_le_pow_right (by omega) + have hh : 3*f i ≤ X.n*f i := Nat.mul_le_mul_right _ hr + have hg := hq i + rw [mul_comm] + omega + let env (i : ι) := loaded cl Q (k i) (v i) + -- construct fields (f,p2) + have hmf : Can m b.B s Ty.w env f W := by + have ht : Can m b.B s Ty.w env k W := Can.first + refine (ht.dvdW (Can.wc X.n) sd).cong (fun _ => rfl) ?_ + intro i + rw [← hq,mul_comm X.n] + exact Layout.div_join hd + have hmp : Can m b.B s (Ty.p Ty.w Ty.w) env (fun i => (f i,p2 i)) W := + hmf.pair (hmf.wTwo sq hm (Dom.of_le (fun i => (hf i).trans (hy i)))) + let T1 := Ty.p s (Ty.p Ty.w Ty.w) + let Y (i : ι) : T T1 := (env i,f i,p2 i) + have hmx : Can m b.B T1 (Ty.a Ty.w) Y (fun i => xorTab (f i)) W := + (Can.xor_prepare (m:=m) (f:=f) (B:=b.B) (s:=T1) (x:=Y) + (Can.fst Can.second) (Can.snd Can.second) sq hm).mono hcube + let T2 := Ty.p T1 (Ty.a Ty.w) + let Y' (i : ι) : T T2 := (Y i,xorTab (f i)) + -- NEW: the table of `lum` over `Bits f` + have hE2 : Has m b.B T2 s Y' env := Can.fst Can.first + have hml : Can m b.B T2 (Ty.a sc) Y' + (fun i => (bits (f i)).tape (fun y : Bits (f i) => lum y)) W := + (WHT.lum_tables (k:=f) (Can.fst (Can.snd Can.first)) sq hm hE2.snd.fst).1.mono + (fun i => Nat.pow_le_pow_right (by omega) (hf i)) + let T2' := Ty.p T2 (Ty.a sc) + let Y'' (i : ι) : T T2' := (Y' i,(bits (f i)).tape (fun y : Bits (f i) => lum y)) + -- the input, read as a table on the slots + have hG0 : Rig m b.B f T2 Y' cl X Q r eQ := by + refine ⟨⟨?_,?_,Can.second,hm⟩,?_,?_⟩ + · exact Can.snd (Can.snd Can.first) + · exact Can.fst (Can.snd Can.first) + · exact hE2.snd.fst + · exact hE2.snd.snd.cong (fun _ => rfl) (fun i => (ebb_eq ..).symm) + have hG : Rig m b.B f T2' Y'' cl X Q r eQ := hG0.gather id Y'' (t:=T2') Can.first + -- leftover bits, still on the slots + have HH : Can m b.B T2' (bundle cl) Y'' (fun i => (fleet X Q r (f i)).tape (zQ i)) W := + hG.dots_cost.weaken hszQ + let T3 := Ty.p T2' (bundle cl) + let A (i) : T T3 := (Y'' i,(fleet X Q r (f i)).tape (zQ i)) + have Hg := hG.gather id A (t:=T3) Can.first + have G : Rig m b.B f T3 A cl X Q r zQ := ⟨Hg.gear,Hg.imag,Can.second⟩ + -- embed the slots into the table of roles; scratch roles are created as zero + have HE : Can m b.B T3 (bundle cl) A (fun i => (fleet X R r (f i)).tape (Z i)) W := + (G.cross_point R (embM e)).weaken hszR + let T4 := Ty.p T3 (bundle cl) + let A4 (i) : T T4 := (A i,(fleet X R r (f i)).tape (Z i)) + have Hg4 := G.gather id A4 (t:=T4) Can.first + have hL4 : Has m b.B T4 (Ty.a sc) A4 + (fun i => (bits (f i)).tape (fun y : Bits (f i) => lum y)) := + Can.snd (Can.fst Can.first) + have G4 : GRig m b.B f T4 A4 cl X R r Z := ⟨⟨Hg4.gear,Hg4.imag,Can.second⟩,hL4⟩ + -- the GENERALISED word on the table of roles + have Hy := G4.gsweep n τ Q hQ hk + (fun rk h1 h2 i => by rw [book_len,hq]; exact hc rk h1 h2 i) w hP + -- extract the slots; scratch roles are dropped + let T5 := Ty.p T4 (bundle cl) + let A5 (i) : T T5 := (A4 i,(fleet X R r (f i)).tape (gcoast r (f i) w (Z i))) + have Hg5 := G4.rig.gather id A5 (t:=T5) Can.first + have G5 : Rig m b.B f T5 A5 cl X R r (fun i => gcoast r (f i) w (Z i)) := + ⟨Hg5.gear,Hg5.imag,Can.second⟩ + have HX : Can m b.B T5 (bundle cl) A5 (fun i => (fleet X Q r (f i)).tape (O i)) W := + (G5.cross_point Q (extM e)).weaken hszQ + have heq (i) : O i = ebb X r (f i) (k i) (hq i) (whole (k i) (v i)) := + gamplifies X r (f i) (k i) (hq i) e he w hw (v i) + have ha (i) : (fleet X Q r (f i)).tape (O i) = + (sim Q (k i)).tape (whole (k i) (v i)) := by + rw [heq]; exact ebb_eq .. + have Ho := ((Hy.weaken hszR (fun _ => le_rfl)).save_keep + (Able.of_can (b:=b) HX)).cong (fun _ => rfl) ha + have Hx := (Able.of_can (b:=b) hmp).save_keep + ((Able.of_can (b:=b) hmx).save_keep ((Able.of_can (b:=b) hml).save_keep + ((Able.of_can (b:=b) HH).save_keep ((Able.of_can (b:=b) HE).save_keep Ho)))) + simpa only [Nat.zero_add,Nat.add_zero] using Hx + +end +end +end PowerSaving.RAM +end OAI + +#print axioms OAI.PowerSaving.RAM.gamplify diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__ORIGIN.md b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__ORIGIN.md new file mode 100644 index 0000000000..e28b355d0a --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__ORIGIN.md @@ -0,0 +1,64 @@ +# tools/gx/ and tools/certificate/gcert1-p11-pr193.json.gz: where they come from + +Everything in this directory is Python 3 (standard library only). No Lean is run by these scripts. +"The outside repository" means github.com/CrocSwap/integer-mult-bounds (Apache-2.0, `LICENSE` and `NOTICE` +of that repository; `NOTICE`: "A sharper exponent for integer multiplication, Copyright 2026 Douglas Colkitt"). + +## The scripts (this project) + +| file | what it is | +|---|---| +| `gxcore.py` | loads a certificate of format gcert/1, brings it to normal form, and is a Python mirror of both Lean checks (labels and scalars); cut points and label data for the generator | +| `gxunit.py` | split plan of the kernel evaluations, the unit of the word, expected exponents | +| `gxbind.py` | the texts of the generated Lean modules (check, histogram, price, certificate and final modules) | +| `gxgen.py` | certificate -> Lean data modules and one module per kernel evaluation | +| `gxrate.py` | rate lemmas, unit price list, final theorem modules, comparator challenge / solution / configuration | +| `gxdry.py`, `gxmut.py` | dry run (mirror, sizes, plan, exponents); mutants that the mirror must reject | +| `gxconv.py` | converts the earlier format gcert/0 to gcert/1 when a step scales its target (the in-place pair step of #193) | +| `gsmirror.py` | a second, separately written Python mirror of the scalar check `GS.scalCheck` / `GS.yCheck`; `gxbind.py` calls it for the check parameters | +| `gx.py`, `gxrun.py` | the reference checker of the format (`gx.check1`: labels and exact scalar identity) and its command line | +| `gxpaths.py`, `regen_check.py`, `refcheck.py` | written for this repository: relative paths; regenerate and compare; `gx.check1` on a gcert/1 file | + +The scripts are the working copies with path edits only (absolute paths of the author's machine replaced through +`gxpaths.py`; templates read from `tools/gen/templates/`; `foldlib.py` / `foldgen.py` taken from `tools/gen/`). +The sentences "Generated by checks/..." that the generators print into Lean files name the scripts by their +working paths; they are kept so that the generated modules come out byte for byte. +No script of the outside repository is included, imported or executed. + +## The certificate `tools/certificate/gcert1-p11-pr193.json.gz` + +sha256 of the file: `15251deb0c11e0504d7b297c9786818888a93f08b92b03c6c122784b70488633` +(gzip stores a time stamp; sha256 of the uncompressed JSON: `c64d2a95431c3cf24452de7391cce780bd71521da44ce23923ebb235f6c7962c`). + +It is ONE explicit program (numbered registers, every addition, every frame) for the helper circuit at +h = 22: 1,320 ports, 9,412 slots, 262,944 unit moves. **The design of that circuit is not this project's.** It is the +"paired-cube" circuit of the outside repository as of pull request #193 (which builds on #191, #184, #168 and #144). +The outside repository publishes the design as generator scripts, frozen data files and a ledger; it has no file +of this kind. This file was produced by this project's own code, which + +1. loaded the following files of the outside repository **as data** (JSON; nothing was executed): + - at pull request #168, commit `4a3c769e5c5430e7114c4d3e099ff34664677f17`: + `references/paired-cube/sources/local_L1.json`, + `references/paired-cube/sources/tmod_TE_TD_TB3_1_1_4_full_6.0617964e-4.json`, + `references/paired-cube/sources/pmod_J0_full_6.0666810e-4.json`, + `references/paired-cube/sources/qmod_climb3u_best.json` (the local modules), + `references/paired-cube/selected-module/matching-arcs.json` (carrier arcs), + `references/paired-cube/physical/frames.json` (moved frames); + - at pull request #193, commit `187e1010ac8b259af8e9b5166f68b64bc27b4b47`: + `research/source-assisted-v4/data/physical-pairs.json` (the hand-over pairs); +2. rebuilt the circuit from them step by step, following the algorithms of the outside scripts (read as text), + and checked the result exactly (every published count reproduced; the scalar identity as an identity of + linear maps with arbitrary contents of the helper registers); +3. converted it to gcert/1 with `gxconv.py` (tested by `gx.check1`). + +Step 1 and step 2 (the rebuild scripts and the outside inputs they read) are NOT part of this repository; +the inputs can be fetched from the outside repository at the two commits above. +What this repository proves about the file does not depend on how it was made: the Lean kernel checks the +generated modules (labels, scalar identity, price), and `regen_check.py` shows that those modules are exactly +what `gxgen.py` / `gxrate.py` produce from this file. + +## Check it yourself + + python3 tools/gx/regen_check.py # regenerates the Lean modules and compares + python3 tools/gx/gxdry.py tools/certificate/gcert1-p11-pr193.json.gz # Python mirror of both checks + python3 tools/gx/refcheck.py # the reference checker gx.check1 on the certificate diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gx.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gx.py new file mode 100644 index 0000000000..6d14c0a976 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gx.py @@ -0,0 +1,296 @@ +#!/usr/bin/python3 -I +"""gx.py. OWN code (imports nothing of port-producer, nothing outside). +(1) convert(c0): gcert/0 (port-producer's event list) -> gcert/1, the LEAN-FACING NORMAL FORM: + only the main phase (no read0 / undo / uninj: the invocation theorem derives the dirt gate and the undo + gate from the product), every gate an elementary fan-out or fan-in add, the 4x4 K block written as three + such adds plus a sign carried by one register, the star scatter as a table. +(2) check1(c1): the local decidable conditions of EXTENDED-CERT-SPEC.md on a gcert/1 file: + E0 sizes, E1 labels (nested subspaces by containment, equal frame at a gate), E2 scatter cut, + E3 shape (kinds of gates; X1; S1), E4 bracket rule S2, E5 scalar (x-content replay: hid and X3), + E6 price data (block histograms, N), E7 exterior gauges only (Q2). Raises AssertionError(": ..."). +""" +from fractions import Fraction as Fr +from collections import Counter +from math import lcm + + +def need(c, msg): + if not c: + raise AssertionError(msg) + + +def reduce(u, basis): + """basis: reduced echelon, pivot = leading bit, descending. Returns u modulo the span.""" + for b in basis: + if u >> (b.bit_length() - 1) & 1: + u ^= b + return u + + +def echelon_ok(f): + piv = [b.bit_length() - 1 for b in f] + if any(b == 0 for b in f) or piv != sorted(piv, reverse=True) or len(set(piv)) != len(piv): + return False + return all(not (b >> p & 1) for i, b in enumerate(f) for j, p in enumerate(piv) if i != j) + + +def inside(a, b): + return all(reduce(u, b) == 0 for u in a) + + +def par(x): + return bin(x).count("1") & 1 + + +KJ = [[[1, 2] if i == j else [-1, 2] for j in range(4)] for i in range(4)] + + +def convert(c0): + need(c0["format"] == "gcert/0", "input is not gcert/0") + v, h, R = c0["v"], c0["h"], c0["R"] + ev = c0["events"] + cen = [n for n, e in enumerate(ev) if e[0] == "centre"] + need(cen == list(range(cen[0], cen[0] + len(cen))), "centres are not contiguous: no single scatter cut") + A, B, ret = [], [], [] + neg = set() # x registers currently holding MINUS their value (between the two K blocks) + openq = {} + for n, e in enumerate(ev): + k = e[0] + out = A if n < cen[0] else B + if k in ("read0", "undo", "uninj"): + continue + if k == "inj": + need(e[2] not in neg, "inj reads a negated x register") + out.append(["out", e[3], e[2], [[e[1], 1, 1]], []]) + elif k == "op": + if e[3] == -1: + out.append(["neg", e[5], e[1]]) + else: + need(e[3] == 1, "op ca") + out.append(["out", e[5], e[2], [[e[1], e[4], 1]], []]) + elif k == "centre": + ret.append([e[2], e[1], e[3]]) + elif k == "gread": + hit = set(t for t, _, _ in e[3]) + out.append(["out", e[2], e[1], [[v + t, a, b] for t, a, b in e[3]], [v + t for t in e[4] if t not in hit]]) + elif k == "rread": + out.append(["out", e[2], e[1], [[v + t, a, b] for t, a, b in e[3]], []]) + elif k == "ysh": + out.append(["out", e[4], e[2], [[e[1], e[3], 1]], []]) + elif k == "yw": + out.append(["out", e[4], e[2], [[e[1], e[3][0], e[3][1]]], []]) + elif k == "kd": + out.append(["out", e[3], e[2], [[e[1], -1 if e[2] in neg else 1, 1]], []]) + elif k == "ktr": + q = tuple(e[1]) + need(e[2] == KJ, "ktr matrix is not 1 - J/2") + x1, rest = q[0], list(q[1:]) + if q not in openq: # first block: x := M x, register x1 keeps the sign + out.append(["in", e[3], x1, [[r, 1, 1] for r in rest]]) + out.append(["out", e[3], x1, [[r, -1, 2] for r in rest], []]) + out.append(["in", e[3], x1, [[r, 1, 1] for r in rest]]) + openq[q] = n + neg.add(x1) + else: # second block: the three adds undone in reverse order + out.append(["in", e[3], x1, [[r, -1, 1] for r in rest]]) + out.append(["out", e[3], x1, [[r, 1, 2] for r in rest], []]) + out.append(["in", e[3], x1, [[r, -1, 1] for r in rest]]) + del openq[q] + neg.discard(x1) + else: + raise AssertionError("unknown event kind %r" % k) + need(not openq and not neg, "a K block is not closed") + ext = sorted([z[3], z[1]] for z in c0["gauge"] if z[5]) + c1 = dict(format="gcert/1", derived_from=c0["name"] + " (gcert/0)", p=c0["p"], h=h, v=v, R=R, cst=c0["cst"], + N=c0["N"], ports=c0["ports"], frames=c0["frames"], start=c0["start"], final=c0["final"], + ext=ext, ret=sorted(ret), scat=dict(inside=c0["scat"]["inside"], outside=c0["scat"]["outside"]), + A=A, B=B, blocks=c0["blocks"]) + return c1 + + +def scat_row(c, t): + """the scatter of target t: [(k, coefficient)], from the table or from the star rule""" + sc = c["scat"] + if "table" in sc: + return [(k, Fr(a, b)) for k, a, b in sc["table"][t]] + sin, sout = Fr(*sc["inside"]), Fr(*sc["outside"]) + return [(k, sin if c["ports"][t] >> k & 1 else sout) for k in range(c["h"])] + + +def gate_regs(g): + if g[0] == "neg": + return [g[2]], [], [] + if g[0] == "out": + return [g[2]] + [t for t, _, _ in g[3]] + list(g[4]), [(t, g[2], Fr(a, b)) for t, a, b in g[3]], g[4] + if g[0] == "in": + return [g[2]] + [s for s, _, _ in g[3]], [(g[2], s, Fr(a, b)) for s, a, b in g[3]], [] + raise AssertionError("E0: unknown gate kind %r" % (g[0],)) + + +def check1(c, scalar=True, stats=None): + need(c.get("format") == "gcert/1", "E0: format") + h, v, R = c["h"], c["v"], c["R"] + nreg = 2 * v + R + ports, fr = c["ports"], [tuple(f) for f in c["frames"]] + need(len(ports) == v == len(set(ports)) and all(par(q) and 0 < q < 1 << h for q in ports), "E0: ports") + need(fr[0] == () and fr[1] == tuple(1 << i for i in range(h - 1, -1, -1)), "E0: frames 0 and 1") + need(all(echelon_ok(f) for f in fr) and len(set(fr)) == len(fr), "E0: frame table not reduced echelon / repeats") + dim = [len(f) for f in fr] + start, final = c["start"], c["final"] + need(len(start) == len(final) == nreg, "E0: start / final") + ext = {r: f for r, f in c["ext"]} + for t in range(v): + need(fr[start[t]] == (ports[t],) and final[t] == 1, "E1: x start / final") + f = fr[final[v + t]] + need(start[v + t] == 0 and len(f) == h - 1 and all(par(u & ports[t]) == 0 for u in f), "E1: y start / final") + for r in range(2 * v, nreg): + need(start[r] == ext.get(r, 0) and final[r] == 1, "E1: slot start / final") + cls = lambda r: "x" if r < v else "y" if r < 2 * v else "s" + cur = list(start) + H = {"x": Counter(), "y": Counter(), "s": Counter(), "c": Counter()} + steps = set() + + def climb(r, f, where): + o = cur[r] + if o != f: + if (o, f) not in steps: + need(dim[o] < dim[f] and inside(fr[o], fr[f]), "E1: step not nested (%s, register %d)" % (where, r)) + steps.add((o, f)) + H[cls(r)][dim[f] - dim[o]] += 1 + cur[r] = f + okind = {("x", "s"), ("s", "s"), ("s", "y"), ("x", "y"), ("x", "x"), ("y", "y")} + ysum, piv, ytg = Counter(), set(), set() + inc = 0 + for ph, gates in (("A", c["A"]), ("B", c["B"])): + if ph == "B": # ---- E2: the scatter cut + need(sorted(k for k, _, _ in c["ret"]) == list(range(len(c["ret"]))), "E2: retained totals numbered 0..") + if "table" in c["scat"]: + need(len(c["scat"]["table"]) == v and all(0 <= k < len(c["ret"]) for row in c["scat"]["table"] for k, _, _ in row), + "E2: scatter table") + else: + need(len(c["ret"]) == h, "E2: one retained total per coordinate (star rule)") + for k, s, f in c["ret"]: + need(cls(s) == "s" and cur[s] == f, "E2: retained slot %d is not at its frame" % s) + H["c"][dim[f]] += 1 + need(all(cur[v + t] == 0 for t in range(v)), "E2: a y role left frame 0 before the scatter") + for i, g in enumerate(gates): + regs, pairs, _ = gate_regs(g) + need(all(0 <= r < nreg for r in regs) and len(set(regs)) == len(regs), "E3: registers of gate %s%d" % (ph, i)) + inc += len(regs) + for r in regs: + climb(r, g[1], "%s%d" % (ph, i)) + for t, s, co in pairs: + kd = (cls(s), cls(t)) + need(kd in okind, "E3: gate kind %s -> %s (gate %s%d)" % (kd + (ph, i))) + need(ph == "B" or kd in {("x", "s"), ("s", "s")}, "E3: bank gate before the scatter (gate A%d)" % i) + if kd == ("y", "y"): + ysum[s, t] += co + piv.add(s) + ytg.add(t) + need(ph == "B" or all(cls(r) != "y" for r in regs), "E2: y role named in phase A") + for r in range(nreg): + climb(r, final[r], "final") + need(not (piv & ytg), "E4: a pivot is the target of a gate reading y") + need(all(x == 0 for x in ysum.values()), "E4: y-reads of a (pivot, target) pair do not cancel") + Hs = {k: {str(r): n for r, n in sorted(w.items())} for k, w in H.items()} + need(Hs == c["blocks"], "E6: block histograms") + N = sum(r * n for w in H.values() for r, n in w.items()) + tails = sum(dim[f] for f in ext.values()) + need(N == c["N"] and N + tails == R * h + 2 * v * (h - 1) + c["cst"], "E6: N") + if stats is not None: + stats.update(steps=len(steps), incidences=inc, blocks=sum(sum(w.values()) for w in H.values()), + step_work=sum(dim[a] * dim[b] for a, b in steps), ysh_pairs=len(ysum)) + if scalar: + scal(c, stats) + q2(c) + return True + + +def scal(c, stats=None): + """E5: exact replay of the x-content of every register through A, scatter, B.""" + h, v, R = c["h"], c["v"], c["R"] + nreg = 2 * v + R + reg = [({r: Fr(1)} if r < v else {}) for r in range(nreg)] + den = {"x": 1, "y": 1, "s": 1} + mx = {"x": Fr(0), "y": Fr(0), "s": Fr(0)} + cls = lambda r: "x" if r < v else "y" if r < 2 * v else "s" + + def axpy(t, src, co): + d = reg[t] + for k, u in src.items(): + w = d.get(k, 0) + co * u + if w: + d[k] = w + kk = cls(t) + if w.denominator != 1: + den[kk] = lcm(den[kk], w.denominator) + if abs(w) > mx[kk]: + mx[kk] = abs(w) + else: + d.pop(k, None) + + def run(gates): + for g in gates: + if g[0] == "neg": + reg[g[2]] = {k: -u for k, u in reg[g[2]].items()} + elif g[0] == "out": + src = dict(reg[g[2]]) + for t, a, b in g[3]: + axpy(t, src, Fr(a, b)) + else: + for s, a, b in g[3]: + axpy(g[2], reg[s], Fr(a, b)) + run(c["A"]) + tot = {k: dict(reg[s]) for k, s, _ in c["ret"]} + for t in range(v): + for k, co in scat_row(c, t): + axpy(v + t, tot[k], co) + run(c["B"]) + need(all(reg[t] == {t: 1} for t in range(v)), "E5: an x role is not restored (X3)") + need(all(reg[v + t] == {t: 1} for t in range(v)), "E5: a target does not receive exactly its source (hid)") + if stats is not None: + stats.update(den=dict(den), maxabs={k: str(x) for k, x in mx.items()}, + gates_A=len(c["A"]), gates_B=len(c["B"])) + + +def q2(c): + """E7 (only for files with exterior gauges, rule (2)): for every slot q that starts off the zero frame, the + column of q in the y rows of the product is zero (its dirt is removed in line, the derived dirt gate at + frame 0 does not touch it). Replay with the gauged slots as variables, x = 0.""" + h, v, R = c["h"], c["v"], c["R"] + ext = [r for r, _ in c["ext"]] + if not ext: + return True + reg = [dict() for _ in range(2 * v + R)] + for r in ext: + reg[r] = {r: Fr(1)} + + def axpy(t, src, co): + d = reg[t] + for k, u in src.items(): + w = d.get(k, 0) + co * u + if w: + d[k] = w + else: + d.pop(k, None) + + def run(gates): + for g in gates: + if g[0] == "neg": + reg[g[2]] = {k: -u for k, u in reg[g[2]].items()} + elif g[0] == "out": + src = dict(reg[g[2]]) + for t, a, b in g[3]: + axpy(t, src, Fr(a, b)) + else: + for s, a, b in g[3]: + axpy(g[2], reg[s], Fr(a, b)) + run(c["A"]) + tot = {k: dict(reg[s]) for k, s, _ in c["ret"]} + for t in range(v): + for k, co in scat_row(c, t): + if tot[k]: + axpy(v + t, tot[k], co) + run(c["B"]) + need(all(not reg[v + t] for t in range(v)), "E7: the dirt of an exterior-gauged slot reaches a y role (Q2)") + return True diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxbind.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxbind.py new file mode 100644 index 0000000000..fcb625619c --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxbind.py @@ -0,0 +1,438 @@ +"""gxbind.py: THE BINDING of the generator to the Lean terms of gx-scalar / gx-labels / +gx-chain. Everything that names somebody else's definition is in this file (tables SCAL, LAB, CHAIN).""" +import os, re, subprocess +import gxpaths +ROOT = gxpaths.OUT +GSM = gxpaths.HERE + '/gsmirror.py' + +# gx-scalar (gcert-interface.md, SCALAR v1): GS.scalCheck c p lo n, GS.yCheck c p lo n, p : GS.SPar = +SCAL = dict(imports=['Work.GCert.Scalar.Seg'], scal='GS.scalCheck raw ⟨%(d)d, %(sw)d, %(ux)d, %(us)d, %(uy)d⟩ %(lo)d %(n)d', + ychk='GS.yCheck raw ⟨%(d)d, %(sw)d, %(ux)d, %(us)d, %(uy)d⟩ 0 %(v)d') +# gx-labels (gcert-interface.md LABELS v1 + questions.md N1): namespace GLab; frame = code, table and states = SSC.Trie, +# GLab.Par = . `end` = GLab.endK of Labels/EndDef.lean (questions.md N2; no obaseK: Q1 closed). +LAB = dict(imports=['Work.GCert.Labels.Def'], end_imports=['Work.GCert.Labels.EndDef'], par='⟨%(h)d, %(n)d, %(d)d, %(K)d, tab⟩', ns='GLab', + tab='GLab.tabK %(h)d %(sub)s', seg='GLab.segK par %(gs)s st%(i)d st%(j)d %(rs)s', + end='GLab.endK par %(v)d ports (raw.ret.map Prod.fst) st0 st%(a)d st%(f)d', noadds='GLab.noAdds fins') +# gx-chain (CHAIN v1): GX.wht_of_halves; the terms below are PLACEHOLDERS until Labels/Main and Scalar/Main compile +CHAIN = dict(imports=['Work.GCert.Chain.End', 'Work.GCert.Labels.Main'], scal='(GS.ScalOK.scal GXD.%(c)s.scalOK)', + lab='(GXD.%(c)s.valid.lab GXD.%(c)s.scalOK)', lab_cost='GXD.%(c)s.lab_cost') + + +def code(h, basis): + """gx-labels' code of a reduced echelon basis: dim + 2^8 M + 2^(8+h) P (M = pivot mask, vector of pivot p at digit p)""" + M = P = 0 + for b in basis: + p = b.bit_length() - 1 + M |= 1 << p + P |= b << (h * p) + return len(basis) + (M << 8) + (P << (8 + h)) + + +MOD = '''import %(imports)s +/-! Kernel check (%(doc)s) of the gcert/1 certificate `GXD.%(name)s.raw`. Source: %(src)s. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.%(name)s +open GXD +theorem %(thm)s : %(stmt)s := by decide +kernel +end GXD.%(name)s +#print axioms GXD.%(name)s.%(thm)s +''' + + +def spar(D, path): + """scalar parameters: from gx-scalar's mirror when it exists, else from my own replay (sw is then a GUESS)""" + import gxcore as gc + n, d = 2 * D['v'] + D['R'], 0 + while (1 << d) < n: + d += 1 + dg = gc.digits(D) + S = dict(d=d, sw=16, ux=dg['x'][0], us=dg['s'][0], uy=dg['y'][0], source='gx-data replay; sw = 16 is a GUESS', digits=dg) + if os.path.exists(GSM): + try: + o = subprocess.run(['python3', '-B', GSM, path], capture_output=True, text=True, timeout=1800).stdout + m = re.search(r'SPar[^\d]*(\d+)[, ]+(\d+)[, ]+(\d+)[, ]+(\d+)[, ]+(\d+)', o) + if m: + S.update(zip(('d', 'sw', 'ux', 'us', 'uy'), map(int, m.groups())), source='gsmirror.py') + except Exception as e: + S['source'] += ' (gsmirror.py failed: %r)' % (e,) + return S + + +def write_checks(D, M, name, src, out, L, S, plan): + base = out[len(ROOT):].replace('/', '.') + raw = '%s.Gen.%s' % (base, name) + h, v, n = D['h'], D['v'], 2 * D['v'] + D['R'] + res = [] + + def mod(suffix, imports, thm, stmt, doc): + m = '%s.Gen.%s%s' % (base, name, suffix) + open('%s/Gen/%s%s.lean' % (out, name, suffix), 'w').write(MOD % dict( + imports='\nimport '.join(imports), doc=doc, name=name, src=src, thm=thm, stmt=stmt)) + res.append((m, thm, stmt)) + for i, (lo, hi) in enumerate(M['scal']['batches']): + mod('Scal%d' % i, SCAL['imports'] + [raw], 'scal%d_ok' % i, SCAL['scal'] % dict(S, lo=lo, n=hi - lo) + ' = true', + 'scalar identity E3 E5 for the sources %d .. %d' % (lo, hi - 1)) + mod('YChk', SCAL['imports'] + [raw], 'ychk_ok', SCAL['ychk'] % dict(S, v=v) + ' = true', 'the y -> y adds, E4') + par = '%s.Gen.%sPar' % (base, name) + open('%s/Gen/%sPar.lean' % (out, name), 'w').write( + 'import %s\nimport %s\n/-! Parameters `GLab.Par` of the label check of `GXD.%s.raw` (h, registers, trie depth, K, frame table).\n' + 'Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/\nnamespace GXD.%s\nopen GXD\n' + 'noncomputable def par : GLab.Par := %s\nend GXD.%s\n' + % (LAB['imports'][0], raw, name, name, LAB['par'] % dict(h=h, n=n, d=L['d'], K=L['K']), name)) + paths = [format(i, '0%db' % L['ts']) for i in range(1 << L['ts'])] if L['ts'] else [''] + for i, pth in enumerate(paths): + mod('Tab%d' % i, LAB['imports'] + [raw], 'tab%d_ok' % i, + LAB['tab'] % dict(h=h, sub='tab_n' + pth if pth else 'tab') + ' = true', + 'E0: subtrie %d of %d of the frame table (codes of reduced echelon bases)' % (i, len(paths))) + for i in range(L['nseg']): + mod('Seg%d' % i, [par], 'seg%d_ok' % i, + LAB['seg'] % dict(gs='seg%d' % i, i=i, j=i + 1, rs='rs%d' % i) + ' = true', + 'E1: replay of the gates %d .. %d (phase %s) and their block ranks' % ( + M['cuts'][i], M['cuts'][i + 1] - 1, 'A' if i < L['nsegA'] else 'B')) + mod('SegF', [par], 'segF_ok', LAB['seg'] % dict(gs='fins', i=L['nseg'], j=L['nseg'] + 1, rs='rF') + ' = true', + 'E1: the final climbs and their block ranks') + if LAB['end']: + mod('End', LAB['end_imports'] + [par], 'end_ok', LAB['end'] % dict(v=v, a=L['nsegA'], f=L['nseg'] + 1) + ' = true', + 'E1 E2: frames at the start, at the scatter, at the end') + return res + + +def nest(xs): + return ' ++ ('.join(xs) + ')' * (len(xs) - 1) if xs else '[]' + + +def write_hist(D, M, name, src, out, L): + """kernel counts of the block ranks on the EXPLICIT rank lists rA, rB, rF (no replay)""" + base = out[len(ROOT):].replace('/', '.') + h, rs = D['h'], M['lab']['rs'] + ph = {'A': sum(rs[:L['nsegA']], []), 'B': sum(rs[L['nsegA']:], []), 'F': M['lab']['rF']} + top = max(max(x) if x else 0 for x in ph.values()) + cop = [M['dim'][f] for _, f in D['ret']] + tot = {r: sum(x.count(r) for x in ph.values()) + cop.count(r) for r in range(1, max(top, max(cop)) + 1)} + assert {r: c for r, c in tot.items() if c} == M['hist'], 'histogram of the rank lists differs from the mirror' + lines = ['/-- block ranks of phase A / phase B, in order (the lists of the replay segments) -/', + 'noncomputable def rA : List Nat := ' + nest(['rs%d' % i for i in range(L['nsegA'])]), + 'noncomputable def rB : List Nat := ' + nest(['rs%d' % i for i in range(L['nsegA'], L['nseg'])])] + names = [] + for X, lst in sorted(ph.items()): + l = 'r' + X + lines.append('theorem rankBound%s : wsumK (SSC.wGt %d) %s 0 = 0 := by decide +kernel' % (X, top, l)) + lines += ['theorem rank%s%d_ok : wsumK (SSC.wEq %d) %s 0 = %d := by decide +kernel' % (X, r, r, l, lst.count(r)) + for r in range(top + 1)] + names += ['rankBound' + X] + ['rank%s%d_ok' % (X, r) for r in range(top + 1)] + txt = ('import Work.GCert.Data.Count\nimport %s.Gen.%s\n' % (base, name) + + '/-! Kernel count of the BLOCK RANKS of the gcert/1 certificate `GXD.%s.raw` (h = %d) on the explicit rank lists\n' + '`rA`, `rB`, `rF` (phase A, phase B, final climbs): `wsumK (SSC.wEq r) l 0` blocks of rank `r`, none above %d\n' + '(`GXD.sum_of_wsumK` turns a count into `(l.map wt).sum` = `SSC.wsum wt l`).\n' + 'The %d scratch copies (ranks %s) are not in these lists. Whole invocation, by rank: %s.\n' + 'Source: %s. Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/\n' + 'set_option maxRecDepth 100000\nnamespace GXD.%s\nopen GXD\n' % ( + name, h, top, len(cop), sorted(set(cop)), M['hist'], src, name) + '\n'.join(lines) + + '\nend GXD.%s\n' % name + '\n'.join('#print axioms GXD.%s.%s' % (name, x) for x in names[:2]) + '\n') + open('%s/Gen/%sHist.lean' % (out, name), 'w').write(txt) + return '%s.Gen.%sHist' % (base, name) + + +def write_price(D, M, name, src, out, L): + """Mathlib module: the price of the rank lists rA, rB, rF from the kernel counts, and of one whole invocation""" + base = out[len(ROOT):].replace('/', '.') + rs = M['lab']['rs'] + ph = {'A': sum(rs[:L['nsegA']], []), 'B': sum(rs[L['nsegA']:], []), 'F': M['lab']['rF']} + top = max(max(x) if x else 0 for x in ph.values()) + cop = [M['dim'][f] for _, f in D['ret']] + tm = lambda cnt: ' + '.join('%d * φ %d' % (n, r) for r, n in sorted(cnt.items()) if n) or '0' + thms = '' + for X in 'ABF': + cnt = {r: ph[X].count(r) for r in range(1, top + 1)} + thms += ''' +/-- price of the blocks of %s, from the kernel counts -/ +theorem r%s_cost (φ : ℕ → ℝ) : rcost φ r%s = %s := by + rw [GXD.rcost_wsumK φ r%s %d rankBound%s] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, %s] + norm_num [bcost] +''' % ({'A': 'phase A', 'B': 'phase B', 'F': 'the final climbs'}[X], X, X, tm(cnt), X, top, X, + ', '.join('rank%s%d_ok' % (X, r) for r in range(top + 1))) + copies = tm({r: cop.count(r) for r in set(cop)}) + txt = '''import Work.GCert.Data.Price +import %(base)s.Gen.%(name)sHist + +/-! +# (key: gx-data) gcert/1 certificate `%(name)s` (h = %(h)d): the price of one invocation + +GENERATED by checks/wht26/gx-data/py/gxgen.py from %(src)s. No `sorry`. +`rA_cost`, `rB_cost`, `rF_cost`: the price of the block rank lists of phase A, phase B and the final climbs +(lists `GXD.%(name)s.rA / rB / rF`, counted by the kernel in `Gen.%(name)sHist`); +`inv_cost`: with the %(nc)d scratch copies (%(copies)s) the blocks of ONE invocation cost +`invPrice φ` = %(terms)s; `inv_moves`: they stand for `R h + 2 v (h - 1) + cst = %(N)d` unit moves. +-/ + +namespace GXD.%(name)s +open GXD OAI.PowerSaving.CB +%(thms)s +/-- price of the blocks of ONE invocation (x roles, y roles, slots, scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := %(terms)s + +/-- **Price of ONE invocation** in the shape of `GX.Lab.cost`: phase A, the scratch copies, phase B, final climbs. -/ +theorem inv_cost (φ : ℕ → ℝ) : rcost φ rA + (%(copies)s) + rcost φ rB + rcost φ rF = invPrice φ := by + rw [rA_cost, rB_cost, rF_cost] + unfold invPrice + ring + +theorem inv_moves : invPrice (fun r => (r:ℝ)) = %(R)d * %(h)d + 2 * %(v)d * (%(h)d - 1) + %(cst)d := by + unfold invPrice + norm_num + +theorem inv_count : invPrice (fun _ => (1:ℝ)) = %(count)d := by + unfold invPrice + norm_num + +end GXD.%(name)s +#print axioms GXD.%(name)s.inv_cost +#print axioms GXD.%(name)s.inv_moves +''' % dict(base=base, name=name, h=D['h'], src=src, nc=len(cop), copies=copies, terms=tm(M['hist']), N=D['N'], thms=thms, + R=D['R'], v=D['v'], cst=D['cst'], count=sum(M['hist'].values())) + open('%s/%sPrice.lean' % (out, name), 'w').write(txt) + return '%s.%sPrice' % (base, name) + + +def write_cert(D, M, name, src, out, chk, L): + """Cert: THE LABEL HALF (aux, valid : GLab.Valid raw aux, lab_cost, lab_price) -- compiles without the scalar half; + ScalOK: the scalar half `scalOK : GS.ScalOK raw` (needs Work/GCert/Scalar/Main).""" + base = out[len(ROOT):].replace('/', '.') + bs = M['scal']['batches'] + hs = '' + for i, (lo, hi) in enumerate(bs): + lo_pf = 'Nat.zero_le t' if i == 0 else 'Nat.le_of_not_lt h%d' % (i - 1) + if i + 1 < len(bs): + hs += ' if h%d : t < %d then ⟨%d, %d, %s, h%d, GS.XRun.of_check scal%d_ok⟩ else\n' % (i, hi, lo, hi - lo, lo_pf, i, i) + else: + hs += ' ⟨%d, %d, %s, Nat.lt_of_lt_of_le ht (by decide), GS.XRun.of_check scal%d_ok⟩' % (lo, hi - lo, lo_pf, i) + terms = ' + '.join('%d * φ %d' % (n, r) for r, n in M['hist'].items()) + info = dict(base=base, name=name, h=D['h'], src=src, v=D['v'], R=D['R'], nc=len(D['ret']), cst=D['cst'], N=D['N'], + nb=len(bs), terms=terms, hs=hs) + txt = '''import Work.GCert.Scalar.Main +import %(imps)s +/-! # (key: gx-data) gcert/1 certificate `%(name)s` (h = %(h)d): THE SCALAR HALF `scalOK : GS.ScalOK raw` +GENERATED by checks/wht26/gx-data/py/gxgen.py from %(src)s. No `sorry`. +Kernel checks `scal_ok` (%(nb)d source batches) and `ychk_ok`. -/ +namespace GXD.%(name)s +open GXD +theorem scalOK : GS.ScalOK raw where + hv := by decide + hs := fun t ht => +%(hs)s + hyc := fun t ht => ⟨0, %(v)d, Nat.zero_le t, Nat.lt_of_lt_of_le ht (by decide), GS.YRun.of_check ychk_ok⟩ +end GXD.%(name)s +#print axioms GXD.%(name)s.scalOK +''' % dict(info, imps='\nimport '.join(c[0] for c in chk if 'Scal' in c[0] or 'YChk' in c[0])) + open('%s/%sScalOK.lean' % (out, name), 'w').write(txt) + # ---- the label half + nA, ns, ts = L['nsegA'], L['nseg'], L['ts'] + cop = sorted(set(M['dim'][f] for _, f in D['ret'])) + assert len(cop) == 1, 'scratch copies of several ranks %s: lab_cost of gxbind.py assumes one' % cop + + def tabpf(path): + if len(path) == ts: + return 'tab%d_ok' % (int(path, 2) if path else 0) + return '(GLab.tabK_node _ _ _ %s %s)' % (tabpf(path + '0'), tabpf(path + '1')) + + def runpf(a, b): + return 'GLab.Run.of_seg seg%d_ok' % a if a + 1 == b else 'GLab.Run.append (GLab.Run.of_seg seg%d_ok) (%s)' % (a, runpf(a + 1, b)) + + def run(X, a, b): + segs = ['seg%d' % i for i in range(a, b)] + return '''theorem gates%(X)s_eq : raw.gates%(X)s = %(cat)s := by + show List.flatten %(lst)s = _ + simp only [List.flatten_cons, List.flatten_nil, List.append_nil] +/-- the replay of phase %(X)s, composed from its kernel-checked segments -/ +theorem run%(X)s : GLab.Run par st%(a)d raw.gates%(X)s st%(b)d r%(X)s := by + rw [gates%(X)s_eq] + exact %(pf)s +''' % dict(X=X, cat=nest(segs), lst=ll_(segs), a=a, b=b, pf=runpf(a, b)) + lab = 'valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg' + txt = '''import Work.GCert.Labels.Main +import %(base)s.%(name)sPrice +import %(imps)s +/-! # (key: gx-data) gcert/1 certificate `%(name)s` (h = %(h)d): THE LABEL HALF and its price +GENERATED by checks/wht26/gx-data/py/gxgen.py from %(src)s. No `sorry`. +`v = %(v)d` ports, `R = %(R)d` slots, %(nc)d scratch copies of rank %(c)d, copy cost `cst = %(cst)d`, `N = %(N)d` unit moves. +* `aux : GLab.Aux`, `valid : GLab.Valid raw aux`: frame table (`tab_ok` composed by `tabK_node`), the replays of phase A + and phase B (`seg_ok` composed by `Run.append`), the final climbs (`segF_ok`, `fin_ok`), the ends (`end_ok`); +* `lab_cost`, `lab_price`: for ANY scalar half `S` the label half `valid.lab S ..` costs + `rcost rA + card C * bcost %(c)d + rcost rB + rcost rF` = `invPrice φ` = %(terms)s + (`Gen.%(name)sHist`, `%(name)sPrice`) when there are %(nc)d copies. -/ +set_option maxRecDepth 100000 +namespace GXD.%(name)s +open GXD OAI.PowerSaving OAI.PowerSaving.CB +theorem raw_h : raw.h = %(h)d := rfl +theorem raw_v : raw.v = %(v)d := rfl +theorem raw_R : raw.R = %(R)d := rfl +/-- what the label checks read next to `raw` -/ +noncomputable def aux : GLab.Aux := ⟨par, st0, st%(a)d, st%(n)d, st%(f)d, fins, rA, rB, rF⟩ +theorem fin_ok : GLab.noAdds fins = true := by decide +kernel +theorem cen_ok : (raw.ret.map Prod.fst).all (fun r => Nat.beq (GLab.cdim (par.tab.get (st%(a)d.get r))) %(c)d) = true := by + decide +kernel +theorem tab_ok : GLab.tabK par.h par.tab = true := %(tabpf)s +%(runA)s%(runB)s/-- **the kernel-checked label facts** of the certificate -/ +theorem valid : GLab.Valid raw aux where + hn := rfl + tab := tab_ok + runA := runA + runB := runB + runF := GLab.Run.of_seg segF_ok + fin := fin_ok + ends := end_ok +theorem cen_dim (r : Nat) (hr : r ∈ raw.ret.map Prod.fst) : GLab.cdim (par.tab.get (st%(a)d.get r)) = %(c)d := + Nat.eq_of_beq_eq_true (List.all_eq_true.mp cen_ok r hr) +/-- price of the label half over ANY scalar half -/ +theorem lab_cost {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (φ : ℕ → ℝ) : + (%(lab)s).cost φ + = rcost φ rA + (Fintype.card C : ℝ) * bcost φ %(c)d + rcost φ rB + rcost φ rF := by + obtain ⟨h1, h2, h3, h4⟩ := valid.lab_ranks S Ro cf hMA hMAi hMB hMBi reg hCc hreg + have h5 : ∀ k, bcost φ (((%(lab)s).cen k).dim) = bcost φ %(c)d := + fun k => by rw [h4 k]; exact congrArg (bcost φ) (cen_dim _ (hreg k)) + rw [GX.Lab.cost, h1, h2, h3, Finset.sum_congr rfl (fun k _ => h5 k), Finset.sum_const, Finset.card_univ, nsmul_eq_mul] + rfl +/-- **the label half costs one invocation price** (`invPrice`, by rank, from the kernel counts) -/ +theorem lab_price {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (hC : Fintype.card C = %(nc)d) (φ : ℕ → ℝ) : + (%(lab)s).cost φ = invPrice φ := by + rw [lab_cost S Ro cf hMA hMAi hMB hMBi reg hCc hreg φ, hC, ← inv_cost φ] + norm_num [bcost] +end GXD.%(name)s +#print axioms GXD.%(name)s.valid +#print axioms GXD.%(name)s.lab_price +''' % dict(info, imps='\nimport '.join(c[0] for c in chk if 'Scal' not in c[0] and 'YChk' not in c[0]), c=cop[0], a=nA, n=ns, + f=ns + 1, tabpf=tabpf(''), runA=run('A', 0, nA), runB=run('B', nA, ns), lab=lab) + open('%s/%sCert.lean' % (out, name), 'w').write(txt) + return ['%s.%sCert' % (base, name), '%s.%sScalOK' % (base, name)] + + +def ll_(xs): + return '[' + ', '.join(xs) + ']' + + +def final_module(name, cname, d, dx, g, out): + """.lean: the final theorems OVER ANY SCALAR HALF (compiles as soon as Cert does): label half, price, + unit list, rate fact and gx-chain's `GX.wht_of_halves` are all closed; what is left is `S : GX.Scal` with its + gate matrices = the ordered products of the adds of `raw` (gx-scalar).""" + h, v, R, W, m, nc = g['h'], g['v'], g['R'], d['W'], d['m'], g['nc'] + X = 'GXD.%s' % cname + args = 'S Ro cf hMA hMAi hMB hMBi reg hCc hreg' + + def thm(nm, rate, A, B, s, ux): + return f''' +/-- **Walsh-Hadamard transform, whole-block recursion on the bridged word B_2 with the gcert/1 circuit `{cname}`**, +over any scalar half of `{X}.raw`: the statement `WHTGoal` of `WHTCheck/Challenge.lean` with `1 - 2/10^11` +replaced by `1 - {A}/10^{B}`. -/ +theorem {nm} (Ro : GLab.Roles {X}.raw.v {X}.raw.R emb un) + (hMA : S.MA = SSC.matP un (GLab.mic cf ({X}.raw.gatesA.flatMap GXD.Gate.adds))) + (hMAi : S.MAi = SSC.matPinv un (GLab.mic cf ({X}.raw.gatesA.flatMap GXD.Gate.adds))) + (hMB : S.MB = SSC.matP un (GLab.mic cf ({X}.raw.gatesB.flatMap GXD.Gate.adds))) + (hMBi : S.MBi = SSC.matPinv un (GLab.mic cf ({X}.raw.gatesB.flatMap GXD.Gate.adds))) + (reg : C → Nat) (hCc : ∀ k (q : Fin {X}.raw.R), S.Cc k q ≠ 0 → reg k = 2 * {X}.raw.v + q.val) + (hreg : ∀ k, reg k ∈ {X}.raw.ret.map Prod.fst) (hC : Fintype.card C = {nc}) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - {A}/(10:ℝ)^{B}) W := + GX.wht_of_halves S ({X}.valid.lab {args}) + (by rw [Fintype.card_fin]; decide) {m} {W} (by rw [Fintype.card_fin]; rfl) + (by rw [Fintype.card_fin, Fintype.card_fin]; rfl) (by norm_num) BlockAccounting.blocks{rate} + (fun φ => by + rw [{X}.lab_price {args} hC φ, Fintype.card_fin, Fintype.card_fin] + exact BridgeRate.{name}.unit_cost{ux} φ) + {s} (1 - {A}/(10:ℝ)^{B}) (by norm_num) (by norm_num) BlockAccounting.fold_{rate} + +/-- the same from the FIVE scalar identities of gx-scalar's matrices of `{X}.raw` (`Work/GCert/Data/Glue.lean`) -/ +theorem {nm.replace('_of_scal', '_of_ids')} (hv : 0 < {X}.raw.v) + (hAi : GS.MAi {X}.raw hv * GS.MA {X}.raw hv = 1) (hBi : GS.MBi {X}.raw hv * GS.MB {X}.raw hv = 1) + (hx : ∀ (t : Fin {X}.raw.v) (j : GS.Rl {X}.raw), (GS.MB {X}.raw hv * CR.scatM (GS.Jrm {X}.raw * GS.Ccm {X}.raw) + * GS.MA {X}.raw hv) (CR.lX t) j = if CR.lX t = j then 1 else 0) + (hy : ∀ (i : GS.Rl {X}.raw) (t : Fin {X}.raw.v), (GS.MB {X}.raw hv * CR.scatM (GS.Jrm {X}.raw * GS.Ccm {X}.raw) + * GS.MA {X}.raw hv) i (CR.lY t) = if i = CR.lY t then 1 else 0) + (hid : ∀ S t : Fin {X}.raw.v, (GS.MB {X}.raw hv * CR.scatM (GS.Jrm {X}.raw * GS.Ccm {X}.raw) + * GS.MA {X}.raw hv) (CR.lY S) (CR.lX t) = if S = t then 1 else 0) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - {A}/(10:ℝ)^{B}) W := + {nm} (GXD.scalOf {X}.raw hv hAi hBi hx hy hid) GS.toCoef (GXD.roles {X}.raw hv) + (GXD.scalOf_MA _ hv hAi hBi hx hy hid) (GXD.scalOf_MAi _ hv hAi hBi hx hy hid) + (GXD.scalOf_MB _ hv hAi hBi hx hy hid) (GXD.scalOf_MBi _ hv hAi hBi hx hy hid) + (GXD.reg {X}.raw) (GXD.reg_slot {X}.raw hv hAi hBi hx hy hid) (GXD.reg_mem {X}.raw) + (by rw [Fintype.card_fin]; decide) +''' + txt = f'''import Work.GCert.Chain.End +import Work.GCert.Data.Glue +import Work.GCert.Data.{cname}Cert +import Work.GCert.Data.Inst{name} + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `{cname}` (h = {h}, m = {m}): final theorems over a scalar half +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`GX.wht_of_halves` (gx-chain) on the label half `{X}.valid` (kernel checks of `Work/GCert/Data/Gen/{cname}*`), its +price `{X}.lab_price`, the unit list `BlockAccounting.blocks{name}` (`W = {W}` live roles) and the rate facts +`fold_{name}` (`1 - {d['A']}/10^{d['B']}`), `fold_{name}x` (`1 - {dx['A']}/10^{dx['B']}`). +The ONLY hypothesis left is the scalar half: `S : GX.Scal (Fin {v}) (Fin {R}) C` whose gate matrices are the ordered +products of the adds of `raw` (`hMA .. hMBi`), with `{nc}` copies read from the retained registers (`reg`, `hCc`, `hreg`, `hC`); +`wht_{name}_of_ids`, `wht_{name}x_of_ids`: the same from the five identities `hAi hBi hx hy hid` of gx-scalar's matrices +`GS.MA GS.MAi GS.MB GS.MBi GS.Jrm GS.Ccm` of `raw` (the fields of the planned `GS.ScalOK`). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT + +variable {{C : Type}} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin {X}.raw.v) (Fin {X}.raw.R) C) + {{emb : CR.L3 (Fin {X}.raw.v) (Fin {X}.raw.R) → Nat}} {{un : Nat → CR.L3 (Fin {X}.raw.v) (Fin {X}.raw.R)}} + (cf : GXD.Co → SSC.Coef) +''' + thm('wht_' + name + '_of_scal', name, d['A'], d['B'], d['s'], '') + thm('wht_' + name + 'x_of_scal', name + 'x', dx['A'], dx['B'], dx['s'], '_x') + f''' +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_{name}_of_scal +#print axioms OAI.PowerSaving.WHT.wht_{name}x_of_scal +#print axioms OAI.PowerSaving.WHT.wht_{name}_of_ids +#print axioms OAI.PowerSaving.WHT.wht_{name}x_of_ids +''' + open(out + '%s.lean' % name, 'w').write(txt) + + +def main_module(name, cname, d, dx, out): + """Main.lean: the CLOSED theorems (what the comparator solution cites). WRITTEN against gx-scalar's planned + `GS.ScalOK` (fields / theorems hv hAi hBi hx hy hid, SCALAR v2); compiles when Work/GCert/Scalar/Main.lean exists.""" + K = 'GXD.%s.scalOK' % cname + + def thm(sfx, A, B): + return f''' +/-- **Walsh-Hadamard transform in `O(n (log n)^(1 - {A}/10^{B}))`-type time bounds: whole-block recursion on the bridged +word B_2 with the kernel-checked gcert/1 circuit `{cname}`.** -/ +theorem wht_main_{name}{sfx} : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - {A}/(10:ℝ)^{B}) W := + wht_{name}{sfx}_of_ids {K}.hv {K}.hAi {K}.hBi {K}.hx {K}.hy {K}.hid +''' + txt = f'''import Work.GCert.Scalar.Main +import Work.GCert.Data.{cname}ScalOK +import Work.GCert.Data.{name} + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `{cname}`: THE CLOSED THEOREMS +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`wht_{name}_of_ids` (label half, price, unit list, rate fact, gx-chain's end theorem) applied to the scalar half +`{K} : GS.ScalOK GXD.{cname}.raw` (kernel checks `scal_ok`, `ychk_ok`; soundness: gx-scalar). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT +''' + thm('', d['A'], d['B']) + thm('x', dx['A'], dx['B']) + f''' +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_main_{name} +#print axioms OAI.PowerSaving.WHT.wht_main_{name}x +''' + open(out + '%sMain.lean' % name, 'w').write(txt) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxconv.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxconv.py new file mode 100644 index 0000000000..49ebb65973 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxconv.py @@ -0,0 +1,131 @@ +"""gxconv.py: gcert/0 -> gcert/1 for files whose in-place pair op SCALES its target +(`op dest ctrl ca cb`: dest := ca dest + cb ctrl with ca not in {1}; #193 has ca = -2), questions.md D2. +COPY of `convert` of gx.py with ONE change: a scaling is not a gate, it changes the +UNIT in which the register is stored. wanted(r) = lam[r] * stored(r), lam = 1 at the start; + op dest ctrl ca cb : lam[dest] *= ca ; stored(dest) += (cb lam[ctrl] / lam[dest]) stored(ctrl) + any other add t += k s : stored(t) += (k lam[s] / lam[t]) stored(s) + scatter y_t += coef(t, k) total_k : coefficient coef(t, k) * lam[slot of total k] (a TABLE if some lam != 1) +Only slots may be scaled (tested: lam = 1 on every x and y register, always), so the x / y rows and columns of +the product (E5: hx, hy, hid) are those of the unscaled circuit; frames, blocks and N are untouched. +The result is tested by the reference checker `gx.check1` (labels and scalars) before it is written. + +usage: gxconv.py out= [noext] +""" +import sys, time +from fractions import Fraction as Fr +import gxpaths +import gx +import gxrun +need = gx.need + + +def convert(c0): + need(c0["format"] == "gcert/0", "input is not gcert/0") + v, h, R = c0["v"], c0["h"], c0["R"] + ev = c0["events"] + cen = [n for n, e in enumerate(ev) if e[0] == "centre"] + need(cen == list(range(cen[0], cen[0] + len(cen))), "centres are not contiguous: no single scatter cut") + A, B, ret = [], [], [] + neg, openq, lam, nsc = set(), {}, {}, 0 + L = lambda r: lam.get(r, Fr(1)) + + def co(t, s, a, b=1): # stored coefficient of the wanted add t += (a/b) s + w = Fr(a, b) * L(s) / L(t) + return [w.numerator, w.denominator] + + def o(f, s, tg, ex=()): + return ["out", f, s, [[t] + co(t, s, a, b) for t, a, b in tg], list(ex)] + + def i(f, t, sr): + return ["in", f, t, [[s] + co(t, s, a, b) for s, a, b in sr]] + scat_lam = None + for n, e in enumerate(ev): + k = e[0] + out = A if n < cen[0] else B + if k in ("read0", "undo", "uninj"): + continue + if k == "inj": + need(e[2] not in neg, "inj reads a negated x register") + out.append(o(e[3], e[2], [[e[1], 1, 1]])) + elif k == "op": + if e[3] != 1: + need(e[3] != 0 and e[1] >= 2 * v, "op scales a register that is not a slot (or by 0)") + lam[e[1]] = L(e[1]) * e[3] + nsc += 1 + out.append(o(e[5], e[2], [[e[1], e[4], 1]])) + elif k == "centre": + ret.append([e[2], e[1], e[3]]) + if scat_lam is None: + scat_lam = dict(lam) + elif k == "gread": + hit = set(t for t, _, _ in e[3]) + out.append(o(e[2], e[1], [[v + t, a, b] for t, a, b in e[3]], [v + t for t in e[4] if t not in hit])) + elif k == "rread": + out.append(o(e[2], e[1], [[v + t, a, b] for t, a, b in e[3]])) + elif k == "ysh": + out.append(o(e[4], e[2], [[e[1], e[3], 1]])) + elif k == "yw": + out.append(o(e[4], e[2], [[e[1], e[3][0], e[3][1]]])) + elif k == "kd": + out.append(o(e[3], e[2], [[e[1], -1 if e[2] in neg else 1, 1]])) + elif k == "ktr": + q = tuple(e[1]) + need(e[2] == gx.KJ, "ktr matrix is not 1 - J/2") + x1, rest = q[0], list(q[1:]) + if q not in openq: + out.append(i(e[3], x1, [[r, 1, 1] for r in rest])) + out.append(o(e[3], x1, [[r, -1, 2] for r in rest])) + out.append(i(e[3], x1, [[r, 1, 1] for r in rest])) + openq[q] = n + neg.add(x1) + else: + out.append(i(e[3], x1, [[r, -1, 1] for r in rest])) + out.append(o(e[3], x1, [[r, 1, 2] for r in rest])) + out.append(i(e[3], x1, [[r, -1, 1] for r in rest])) + del openq[q] + neg.discard(x1) + else: + raise AssertionError("unknown event kind %r" % k) + need(all(r >= 2 * v for r, x in lam.items() if x != 1), "an x or y register is scaled") + need(not openq and not neg, "a K block is not closed") + ret = sorted(ret) + need([z[0] for z in ret] == list(range(len(ret))), "retained totals are not 0 .. n-1") + sin, sout = Fr(*c0["scat"]["inside"]), Fr(*c0["scat"]["outside"]) + sl = [(scat_lam or {}).get(z[1], Fr(1)) for z in ret] + if all(x == 1 for x in sl): + scat = dict(inside=c0["scat"]["inside"], outside=c0["scat"]["outside"]) + else: + need(len(ret) == h, "star rule with a number of totals other than h") + scat = dict(table=[[[kk, (w * sl[kk]).numerator, (w * sl[kk]).denominator] + for kk in range(h) for w in [sin if c0["ports"][t] >> kk & 1 else sout]] for t in range(v)]) + ext = sorted([z[3], z[1]] for z in c0["gauge"] if z[5]) + c1 = dict(format="gcert/1", derived_from=c0["name"] + " (gcert/0; %d scalings as units, gxconv.py)" % nsc, p=c0["p"], + h=h, v=v, R=R, cst=c0["cst"], N=c0["N"], ports=c0["ports"], frames=c0["frames"], start=c0["start"], + final=c0["final"], ext=ext, ret=ret, scat=scat, A=A, B=B, blocks=c0["blocks"]) + return c1, nsc, sorted(set(str(x) for x in lam.values())), sum(1 for x in sl if x != 1) + + +if __name__ == "__main__": + t0 = time.time() + opt = dict(a.split("=", 1) for a in sys.argv[2:] if "=" in a) + c0 = gxrun.load(sys.argv[1]) + c1, nsc, lams, nsl = convert(c0) + c1["two_hosts"] = sorted(2 * c0["v"] + i for i, hs in enumerate(c0["hosts"]) if len(hs) > 1) + if "noext" in sys.argv and c1["ext"]: # as gxrun.py: exterior gauges become first blocks + for r, f in c1["ext"]: + d = str(len(c1["frames"][f])) + c1["start"][r] = 0 + c1["blocks"]["s"][d] = c1["blocks"]["s"].get(d, 0) + 1 + c1["N"] += int(d) + c1["blocks"]["s"] = {k: c1["blocks"]["s"][k] for k in sorted(c1["blocks"]["s"], key=int)} + c1["derived_from"] += ", exterior gauges turned into first blocks" + c1["ext"] = [] + st = {} + gx.check1(c1, scalar=True, stats=st) + print("ACCEPTED by gx.check1: %s h=%d v=%d R=%d N=%d gates A=%d B=%d ext=%d; scalings %d, final units %s, scaled totals %d, " + "scatter %s, stats %s (%.1fs)" % (c0["name"], c1["h"], c1["v"], c1["R"], c1["N"], len(c1["A"]), len(c1["B"]), + len(c1["ext"]), nsc, lams, nsl, "table" if "table" in c1["scat"] else "star", st, + time.time() - t0)) + if "out" in opt: + gxrun.dump(c1, opt["out"]) + print("written", opt["out"]) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxcore.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxcore.py new file mode 100644 index 0000000000..3e3f0a3076 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/complex/sources/tools__gx__gxcore.py @@ -0,0 +1,375 @@ +"""gxcore.py: gcert/1 JSON -> normal data D, PYTHON MIRROR of the two Lean checks +(label side: E0 frames, E1 pairs, E1/E2/E6 replay in segments; scalar side: E3 kinds, E4 bracket, E5 replay +in source batches, E7), derived data (distinct climbs, cut states, block histogram) and kernel sizes. +Own code; the reference is gx.py (check1), not imported. Python 3, standard library only.""" +import json, gzip +from collections import Counter +from math import gcd + + +class Reject(Exception): + pass + + +def need(c, msg): + if not c: + raise Reject(msg) + + +def load(path): + c = json.load(gzip.open(path, "rt") if path.endswith(".gz") else open(path)) + need(c.get("format") == "gcert/1", "E0: format is not gcert/1") + return c + + +def co(num, den): + need(den > 0, "E0: denominator") + return (num < 0, abs(num), den) + + +def normal(c): + """the Lean-facing data: gates as tuples, coefficients (neg, num, den), ret by total""" + def gate(g): + if g[0] == "out": + return ("out", g[1], g[2], [(t, co(a, b)) for t, a, b in g[3]], list(g[4])) + need(g[0] == "in", "E0: unknown gate kind %r" % (g[0],)) + return ("in", g[1], g[2], [(s, co(a, b)) for s, a, b in g[3]]) + ret = sorted(c["ret"]) + need([k for k, _, _ in ret] == list(range(len(ret))), "E2: retained totals numbered 0..") + sc = c["scat"] + scat = ("table", [[(k, co(a, b)) for k, a, b in row] for row in sc["table"]]) if "table" in sc else \ + ("star", co(*sc["inside"]), co(*sc["outside"])) + return dict(h=c["h"], v=c["v"], R=c["R"], N=c["N"], cst=c["cst"], ports=list(c["ports"]), + frames=[list(f) for f in c["frames"]], start=list(c["start"]), final=list(c["final"]), + ext=[tuple(e) for e in c.get("ext", [])], ret=[(s, f) for _, s, f in ret], scat=scat, + A=[gate(g) for g in c["A"]], B=[gate(g) for g in c["B"]], + blocks={k: {int(r): n for r, n in c["blocks"][k].items()} for k in "xysc"}) + + +def regs(g): + return [g[2]] + [t for t, _ in g[3]] + (g[4] if g[0] == "out" else []) + + +def adds(g): + """single adds (tgt, src, coef) in order""" + return [(t, g[2], k) for t, k in g[3]] if g[0] == "out" else [(g[2], s, k) for s, k in g[3]] + + +def reduce(u, basis): + for b in basis: + if u >> (b.bit_length() - 1) & 1: + u ^= b + return u + + +def echelon_ok(f): + piv = [b.bit_length() - 1 for b in f] + if any(b == 0 for b in f) or any(piv[i] <= piv[i + 1] for i in range(len(piv) - 1)): + return False + return all(not (b >> p & 1) for i, b in enumerate(f) for j, p in enumerate(piv) if i != j) + + +def par(x): + return bin(x).count("1") & 1 + + +def cls(D, r): + return "x" if r < D["v"] else "y" if r < 2 * D["v"] else "s" + + +# ---- label side ------------------------------------------------------------------------------------------ +def chk_frames(D): + """E0: ports; frame table reduced echelon, no repeats, zero first, full second""" + h, v, fr = D["h"], D["v"], D["frames"] + p = D["ports"] + need(len(p) == v == len(set(p)) and all(par(q) and 0 < q < 1 << h for q in p), "E0: ports") + need(len(fr) >= 2 and fr[0] == [] and fr[1] == [1 << i for i in range(h - 1, -1, -1)], "E0: frames 0 and 1") + need(all(echelon_ok(f) and all(b < 1 << h for b in f) for f in fr), "E0: frame table not reduced echelon") + need(len(set(map(tuple, fr))) == len(fr), "E0: frame table has repeats") + return [len(f) for f in fr] + + +def derive(D): + """distinct climbs in order of first use (NOT a check: plain replay of the frame ids)""" + cur, seen, pairs = list(D["start"]), set(), [] + + def go(r, f): + o = cur[r] + if o != f: + if (o, f) not in seen: + seen.add((o, f)) + pairs.append((o, f)) + cur[r] = f + for g in D["A"] + D["B"]: + for r in regs(g): + go(r, g[1]) + for r, f in enumerate(D["final"]): + go(r, f) + return pairs + + +def chk_pairs(D, dim, pairs): + """E1, level 2: every listed pair is a nested pair of the table; returns the mask-operation count""" + fr, n, work = D["frames"], len(D["frames"]), 0 + for a, b in pairs: + need(a < n and b < n and dim[a] < dim[b], "E1: pair (%d, %d) does not climb" % (a, b)) + need(all(reduce(u, fr[b]) == 0 for u in fr[a]), "E1: pair (%d, %d) is not nested" % (a, b)) + work += dim[a] * dim[b] + return work + + +def cut_points(D, gmax, wmax=210000): + """replay segments: each phase (A, B) is cut into k pieces of equal gate count, k = the least number with at + most `gmax` gates AND at most `wmax` work per piece on average (work = sum over gates of the dimension of the + gate's frame; measured at h = 22: about 1 ms of kernel time per unit, NOTES.md). + Cut points = gate counts in A ++ B (always 0, |A| and the end).""" + nA, nB = len(D["A"]), len(D["B"]) + cuts = [0] + for off, gs in ((0, D["A"]), (nA, D["B"])): + n = len(gs) + k = max(1, -(-n // gmax), -(-sum(len(D["frames"][g[1]]) for g in gs) // wmax)) + cuts += [off + (n * i) // k for i in range(1, k + 1)] + return sorted(set(cuts)) + + +def label_data(D, dim, cuts): + """for gx-labels (gcert-interface.md LABELS v1): ordered block ranks per replay segment, the final climbs as + gates without adds (same final frame, at most 32 registers, only registers that still climb), their ranks, + the largest number of registers named by one gate. Plain replay (the mirror has accepted the file).""" + cur, G = list(D["start"]), D["A"] + D["B"] + rs, most = [], 0 + for a, b in zip(cuts, cuts[1:]): + r = [] + for g in G[a:b]: + most = max(most, len(regs(g))) + for x in regs(g): + if cur[x] != g[1]: + r.append(dim[g[1]] - dim[cur[x]]) + cur[x] = g[1] + rs.append(r) + by = {} + for x, f in enumerate(D["final"]): + if cur[x] != f: + by.setdefault(f, []).append(x) + fins, rF = [], [] + for f in sorted(by): + for i in range(0, len(by[f]), 32): + xs = by[f][i:i + 32] + fins.append(("out", f, xs[0], [], xs[1:])) + rF += [dim[f] - dim[cur[x]] for x in xs] + return dict(rs=rs, fins=fins, rF=rF, most=max(most, 32 if fins else 0)) + + +def chk_replay(D, dim, pairs, cuts): + """E1 (labels), E2 (scatter cut), E6 (price), in the segments given by `cuts`. + Returns (states at the cuts, histogram by class, visits per segment).""" + h, v, R, fr = D["h"], D["v"], D["R"], D["frames"] + n = 2 * v + R + start, final, ext = D["start"], D["final"], dict(D["ext"]) + need(len(start) == len(final) == n, "E0: start / final") + for t in range(v): + need(fr[start[t]] == [D["ports"][t]] and final[t] == 1, "E1: x start / final") + f = fr[final[v + t]] + need(start[v + t] == 0 and len(f) == h - 1 and all(par(u & D["ports"][t]) == 0 for u in f), "E1: y start / final") + for r in range(2 * v, n): + need(start[r] == ext.get(r, 0) and final[r] == 1, "E1: slot start / final") + ok = set(pairs) + need(len(ok) == len(pairs), "E1: pair list has repeats") + cur = list(start) + H = {k: Counter() for k in "xysc"} + + def climb(r, f, where): + o = cur[r] + if o != f: + need((o, f) in ok, "E1: climb (%d, %d) is not a tested pair (%s, register %d)" % (o, f, where, r)) + H[cls(D, r)][dim[f] - dim[o]] += 1 + seg[dim[f] - dim[o]] += 1 + cur[r] = f + seg, segs = Counter(), [] + G, nA = D["A"] + D["B"], len(D["A"]) + states, visits = [], [] + need(cuts[0] == 0 and cuts[-1] == len(G) and cuts == sorted(cuts), "cut points") + for a, b in zip(cuts, cuts[1:]): + states.append(list(cur)) + vs = 0 + for i in range(a, b): + if i == nA: + scatter_cut(D, cur, dim, H, seg) + g = G[i] + rs = regs(g) + need(all(0 <= r < n for r in rs) and len(set(rs)) == len(rs), "E3: registers of gate %d" % i) + need(i >= nA or all(r < v or r >= 2 * v for r in rs), "E2: y role named in phase A (gate %d)" % i) + vs += len(rs) + for r in rs: + climb(r, g[1], "gate %d" % i) + visits.append(vs) + if b < len(G): + segs.append(seg) + seg = Counter() + if nA == len(G): + scatter_cut(D, cur, dim, H, seg) + states.append(list(cur)) + for r in range(n): + climb(r, final[r], "final") + segs.append(seg) + Hb = {k: dict(sorted(w.items())) for k, w in H.items()} + need(Hb == D["blocks"], "E6: block histogram differs from `blocks`") + N = sum(r * c for w in H.values() for r, c in w.items()) + need(N == D["N"] and N + sum(dim[f] for f in ext.values()) == R * h + 2 * v * (h - 1) + D["cst"], "E6: N") + need(sum(r * c for r, c in H["c"].items()) == D["cst"], "E6: cst") + return states, Hb, visits, [[w[r] for r in range(h + 1)] for w in segs] + + +def scatter_cut(D, cur, dim, H, seg): + v = D["v"] + if D["scat"][0] == "table": + need(len(D["scat"][1]) == v and all(k < len(D["ret"]) for row in D["scat"][1] for k, _ in row), "E2: scatter table") + else: + need(len(D["ret"]) == D["h"], "E2: one retained total per coordinate (star rule)") + for s, f in D["ret"]: + need(s >= 2 * v and cur[s] == f, "E2: retained slot %d is not at its frame" % s) + H["c"][dim[f]] += 1 + seg[dim[f]] += 1 + need(all(cur[v + t] == 0 for t in range(v)), "E2: a y role left frame 0 before the scatter") + + +# ---- scalar side ----------------------------------------------------------------------------------------- +SC = 6 # all scalar entries are kept as integers in units of 1/6 +KINDS = {("x", "s"), ("s", "s"), ("s", "y"), ("x", "y"), ("x", "x"), ("y", "y")} + + +def chk_shape(D): + """E3 kinds, E4 bracket""" + ysum, piv, ytg = Counter(), set(), set() + for ph in "AB": + for i, g in enumerate(D[ph]): + for t, s, (ng, a, b) in adds(g): + kd = (cls(D, s), cls(D, t)) + need(kd in KINDS and t != s, "E3: gate kind %s -> %s (gate %s%d)" % (kd + (ph, i))) + need(ph == "B" or kd in {("x", "s"), ("s", "s")}, "E3: bank gate before the scatter (gate A%d)" % i) + if kd == ("y", "y"): + need(SC % b == 0, "E4: denominator beyond sixths") + ysum[s, t] += (-a if ng else a) * (SC // b) + piv.add(s) + ytg.add(t) + need(not (piv & ytg), "E4: a pivot is the target of a gate reading y") + need(all(x == 0 for x in ysum.values()), "E4: y-reads of a (pivot, target) pair do not cancel") + return len(ysum) + + +def scat_row(D, t): + sc = D["scat"] + if sc[0] == "table": + return sc[1][t] + return [(k, sc[1] if D["ports"][t] >> k & 1 else sc[2]) for k in range(D["h"])] + + + +def replay(D, init, count=None): + """exact replay through A, scatter, B of sparse vectors with entries in sixths; `init` = register -> {key: 6}""" + v = D["v"] + reg = [dict(init.get(r, ())) for r in range(2 * v + D["R"])] + + def axpy(t, src, k): + ng, a, b = k + d = reg[t] + for key, u in src.items(): + w = u * a + need(w % b == 0, "E5: an entry needs a denominator beyond sixths (register %d)" % t) + w = w // b + w = d.get(key, 0) + (-w if ng else w) + if count is not None: + count[key] += 1 + if w: + d[key] = w + else: + d.pop(key, None) + + def run(gates): + for g in gates: + if g[0] == "out": + src = dict(reg[g[2]]) + for t, k in g[3]: + axpy(t, src, k) + else: + for s, k in g[3]: + axpy(g[2], reg[s], k) + run(D["A"]) + afterA = sum(len(d) for d in reg) + tot = [dict(reg[s]) for s, _ in D["ret"]] + for t in range(v): + for k, cf in scat_row(D, t): + if tot[k]: + axpy(v + t, tot[k], cf) + run(D["B"]) + return reg, afterA + + +def chk_scalar(D, batches=1): + """E5 (+ E7 when `ext` is non-empty). Returns stats: denominators and largest numerators per class in the + units of the spec (x halves, y sixths, slots integers), updates per source batch, entries after A.""" + v = D["v"] + count = Counter() + reg, afterA = replay(D, {t: {t: SC} for t in range(v)}, count) + need(all(reg[t] == {t: SC} for t in range(v)), "E5: an x role is not restored (X3)") + need(all(reg[v + t] == {t: SC} for t in range(v)), "E5: a target does not receive exactly its source (hid)") + if D["ext"]: + rg, _ = replay(D, {r: {r: SC} for r, _ in D["ext"]}) + need(all(not rg[v + t] for t in range(v)), "E7: the dirt of an exterior-gauged slot reaches a y role") + step = -(-v // batches) + per = [sum(count[k] for k in range(lo, min(lo + step, v))) for lo in range(0, v, step)] + return dict(updates=sum(count.values()), per_batch=per, afterA=afterA, + batches=[(lo, min(lo + step, v)) for lo in range(0, v, step)]) + + +def digits(D): + """largest |entry| met and denominators per class, by a second replay that watches every write (slow path + kept separate from the check): returns {class: (lcm of denominators, largest |numerator| in units 1/den)}""" + v = D["v"] + den = {"x": 1, "y": 1, "s": 1} + mx = {"x": 0, "y": 0, "s": 0} + reg = [({r: SC} if r < v else {}) for r in range(2 * v + D["R"])] + + def axpy(t, src, k): + ng, a, b = k + d, kk = reg[t], cls(D, t) + for key, u in src.items(): + w = d.get(key, 0) + (-(u * a // b) if ng else u * a // b) + if w: + d[key] = w + q = SC // gcd(w, SC) + if den[kk] % q: + den[kk] = den[kk] * q // gcd(den[kk], q) + if abs(w) > mx[kk]: + mx[kk] = abs(w) + else: + d.pop(key, None) + for g in D["A"]: + for t, s, k in adds(g): + axpy(t, reg[s], k) + tot = [dict(reg[s]) for s, _ in D["ret"]] + for t in range(v): + for k, cf in scat_row(D, t): + axpy(v + t, tot[k], cf) + for g in D["B"]: + for t, s, k in adds(g): + axpy(t, reg[s], k) + return {k: (den[k], mx[k] * den[k] // SC if (mx[k] * den[k]) % SC == 0 else "%d/6" % mx[k]) for k in "xys"} + + +def mirror(D, gmax=12000, batches=1, pairs=None, cuts=None): + """both checks; returns everything the generator and the dry run need""" + dim = chk_frames(D) + pairs = derive(D) if pairs is None else pairs + work = chk_pairs(D, dim, pairs) + cuts = cut_points(D, gmax) if cuts is None else cuts + states, H, visits, segH = chk_replay(D, dim, pairs, cuts) + ysh = chk_shape(D) + S = chk_scalar(D, batches) + hist = Counter() + for k in "xysc": + for r, n in H[k].items(): + hist[r] += n + return dict(dim=dim, pairs=pairs, pair_work=work, cuts=cuts, states=states, H=H, visits=visits, ysh=ysh, + scal=S, hist=dict(sorted(hist.items())), segH=segH, + lab=label_data(D, dim, cuts)) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/LICENSE b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/NOTICE b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/NOTICE new file mode 100644 index 0000000000..7008ce01c1 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/NOTICE @@ -0,0 +1,489 @@ +Walsh-Hadamard power saving (wht-power-saving-lean) +Copyright 2026 Jacob Sussman + +Repository: https://github.com/jacobalansussman/wht-power-saving-lean + +This repository is not a project of OpenAI. OpenAI did not write, review or +endorse it. The package name "OAI" and the namespace "OAI.PowerSaving" are +those of openai/math and are kept only because the new files extend that +development. + +This repository is not a project of CrocSwap/integer-mult-bounds either. Its +authors did not write, review or endorse it. Section 6 says what is taken +from their repository. + +This repository contains files from, and files derived from, the repository +"openai/math" (https://github.com/openai/math), family 130, "Exact Fourier +transforms below n log n", at commit fd4aeeb2ee4fc729c18d98444fed42fd0529eeeb. +That repository is published under the Apache License, Version 2.0. A copy of +the licence is in the file LICENSE. The upstream repository has no NOTICE file +and its licence text names no copyright holder; the files are attributed here +to the authors of openai/math (OpenAI). + +1. Unmodified upstream files. + The 89 files under OAI/Computability/ are byte-for-byte copies of the files + with the same paths under lean/ in openai/math at the commit above. They + have not been changed. Modified copies of some of them are under + Work/Fourier/ and Work/FourierE8/ and are listed in section 7. + One more file of openai/math is here unchanged, outside the Lean build: + third-party/openai-math/lean/ComparatorChallenges/UniformFourier.lean is a + byte-for-byte copy of lean/ComparatorChallenges/UniformFourier.lean at the + commit above (the statement of OpenAI's Fourier challenge). It is included + so that the modified copy named in section 2 can be compared with it. + +2. Files that contain upstream text. + - Work/CarrierCheck/ChallengeB2Ke16x.lean, + Work/CarrierCheck/ChallengeB2Ke16xR.lean, + Work/GCert/Data/ChallengeB2Gp193x.lean, + Work/GCert/Data/ChallengeB2Ge8x.lean and the text template + tools/gen/templates/ChallengeB2L16x.lean.txt each contain, as their + lines 22-270, lines 9-257 of + lean/ComparatorChallenges/UniformFourier.lean of openai/math (the RAM cost + model), unchanged. Everything else in these files was written for this + repository. + - Work/Fourier/UniformFourierChallenge.lean is a modified copy of + lean/ComparatorChallenges/UniformFourier.lean of openai/math (the + statement of OpenAI's Fourier challenge, 336 lines). Changes: a comment + was added at the top; the exponent 1 - 1/(10^(13:ℕ)) was replaced by + 1 - 7474546/(10^(10:ℕ)); seven names received the suffix "Z" + (decimalExponent, decimalTime, TimeBounds, DFTGoal, ConvGoal, + transform_main, convolution_main). Everything else in the file is the + upstream text, unchanged. See section 7. + - Work/FourierE8/UniformFourierChallenge.lean is a second modified copy + of the same upstream file, for the fourth result, with the same three + kinds of change: a comment added at the top; the exponent replaced by + 1 - 8762478/(10^(10:ℕ)); the suffix "E8" on the same seven names. + Everything else in the file is the upstream text, unchanged. See + section 7. + - Work/Scratch/Engine.lean and Work/Block/Engine.lean contain copies of + proofs of openai/math, changed for this repository: sections 1, 2 and 5 + of Work/Scratch/Engine.lean are upstream proofs with the batch layout + renamed, and both files contain a copy of the private upstream theorem + "hills_project" (lean/OAI/Computability/FourierTransform/ + TensorProgram.lean) with its envelope generalised. The comments in the + two files mark these places. + - lakefile.lean is adapted from lean/lakefile.lean of openai/math: the same + package name, toolchain, package option and Mathlib pin; every other + dependency was removed and the libraries of this repository were added. + lean-toolchain is a byte-for-byte copy of lean/lean-toolchain. + lake-manifest.json lists Mathlib and its dependencies at the revisions of + lean/lake-manifest.json. + - RELATED-WORK.md reproduces the BibTeX entries of two manuscripts of + openai/math. + +3. New files that build on upstream proofs. + The other files under WHTCheck/ and Work/ were written for this + repository. They import the upstream files, and several of them generalise + or adapt proofs of upstream files (for example Work/Block/Recursion.lean, + which says so in its header). They are changes and additions made for this + repository and are not part of openai/math. + +4. How the new files were made. + Jacob Sussman made the new files on 2026-10-08, 2026-10-09 and 2026-10-10 + by directing a team of AI agents (Claude). The agents wrote the new Lean + files, the certificate data and the generator scripts. They made the + rebuild scripts under tools/rebuild/, in part by adapting programs of + CrocSwap/integer-mult-bounds (section 6): ten of the thirteen on + 2026-10-09, tidied for this repository on 2026-10-10, and three on + 2026-10-10. On 2026-10-10 they also wrote the search programs under + tools/e8/ and found with them the certificate of the fourth result + (section 8). See README.md, section 4. + +5. Ideas taken from other public work. + The network of the first result uses ideas published by others, among them + the helper circuit "NStar3" (Swapnil-jain/integer-mult-kappa, which credits + CrocSwap pull request #36 and Paureel for parts of it), its transfer to + family 130 (shea256/fourier-transform-below-nlogn), and "carrier links" and + "whole-residual batching" (pull requests to CrocSwap/integer-mult-bounds). + No file of Swapnil-jain/integer-mult-kappa or of + shea256/fourier-transform-below-nlogn is included here. One comment in + Work/Scratch/Engine.lean quotes three counts reported in + Swapnil-jain/integer-mult-kappa and names that source. The general frame + lemma that Work/GFrame proves is stated in + notes/general-clifford-frames.tex of CrocSwap/integer-mult-bounds; its Lean + proof was written for this repository. The credits, with links, are in + RELATED-WORK.md. + +6. Data derived from, and programs adapted from, + CrocSwap/integer-mult-bounds (second result). + The helper circuit of the second result is the paired-cube circuit of the + repository "CrocSwap/integer-mult-bounds" + (https://github.com/CrocSwap/integer-mult-bounds), in the state of its pull + request #193. It is the design of that community: icekylinx (pull requests + #144 and #184), eumemic (#168, and #117 behind its modules), ikeboy / + Avi Eisenberg (#191 and #193), with an664 (#128) credited there for the + workspace-sharing principle, and DaysSky (#162) and chafreaky (#163) + credited by #168 for its closure-compiled carrier arcs and for the + fusion of its single-target outputs. That repository is published under + the Apache + License, Version 2.0 (the same licence text as the file LICENSE). Its + NOTICE file begins "A sharper exponent for integer multiplication / + Copyright 2026 Douglas Colkitt" and says that the community release "is + not solely Douglas Colkitt's work". A complete copy of that NOTICE file, as + it is at the head of pull request #193, is in + third-party/CrocSwap-integer-mult-bounds/NOTICE. + + The data were taken from these files of that repository. They were loaded + as data by the programs under tools/rebuild/. No program of that + repository was run, and none is included here unchanged; six of the + programs under tools/rebuild/ are adapted from programs of that + repository ("Programs", below). + - at the head of pull request #168 (eumemic), + 4a3c769e5c5430e7114c4d3e099ff34664677f17: + references/paired-cube/sources/local_L1.json + references/paired-cube/sources/tmod_TE_TD_TB3_1_1_4_full_6.0617964e-4.json + references/paired-cube/sources/pmod_J0_full_6.0666810e-4.json + references/paired-cube/sources/qmod_climb3u_best.json + references/paired-cube/selected-module/matching-arcs.json + references/paired-cube/physical/frames.json + - at the head of pull request #193 (ikeboy), + 187e1010ac8b259af8e9b5166f68b64bc27b4b47: + research/source-assisted-v4/data/physical-pairs.json + + Two more files at the head of pull request #168 are read for comparison + only: the programs print whether their graph and their counts agree + with them. Nothing in the certificate is taken from them: + references/paired-cube/selected-module/SOURCE.json + certificates/paired-cube-complex-input.json + + One more file is fetched and read only on request. No certificate and + no Lean module of this repository is made from it; the documentation + gives its sha256 and the price that tools/gx/gxdry.py computes for + the certificate that the rebuild makes from it: + - at the head of pull request #233 (chafreaky), + 109a857a329d18ed5552d5573f17ddfa886ae57f: + research/source-assisted-v4-layer/witness/physical-pairs.json + + None of these ten files is included in this repository. + tools/rebuild/fetch_inputs.py fetches them and checks their sha256. + + Files of this repository that contain data derived from them: + tools/certificate/gcert1-p11-pr193.json.gz and the Lean data modules + generated from it, Work/GCert/Data/Gen/P193*.lean and the files they import + from Work/GCert/Data/Gen/P193/; its block counts are also in the generated + modules Work/GCert/Data/P193Price.lean, RateB2Gp193.lean, RateB2Gp193x.lean + and InstB2Gp193.lean. + Changes made: the circuit was rebuilt from those data as one explicit, + renumbered list of additions with a table of frames, in the certificate + format "gcert/1" of this repository; its 1,980 in-place steps were written + as pairs of additions with rescaled coefficients; the Lean data modules + were generated from that list. No file of that repository is included + unchanged, except the copy of its NOTICE file named above. + + Programs. The Python files under tools/rebuild/ were made by the agents + (section 4), who read programs of that repository as text and ran none + of them. Six of the thirteen files are adapted from those programs: + the parts named below follow the outside program statement by statement + or method by method, with the layout changed, some names changed and + the parts that this certificate does not use left out. Each of the six + says so in its first lines. + - tools/rebuild/compile.py: the function closure follows + compile_closure of scripts/paired_cube/closure.py; the function + select follows the first part of select of + scripts/paired_cube/gauges.py. + - tools/rebuild/graphgen.py: the class Gen follows the class Graph of + scripts/paired_cube/graph.py; its method fuse follows the branch + "f8:" of merge_outputs of scripts/paired_cube/modules.py, which + fuses the three single-target outputs of a port into one. That + branch came with pull request #168 (eumemic), which says of the + fusion that it "follows #163's same-singleton fusion" and credits + it so: "Same-singleton output fusion: @chafreaky (#163); the fold + orders here come from our own search." + - tools/rebuild/aligned.py: the functions op_tags, local_values and + build follow op_tags, local_values and main of + research/source-assisted-v4/source_aligned_local_v4.py, except its + search for pairs and the records it writes. + - tools/rebuild/stage.py: the order of the events, the backward pass + (responses) and many names are those of + research/terminal-sinks/sinks_gate.py and of + scripts/paired_cube_physical.py; the event records and the exact + arithmetic were written for this repository, and the frame scan + was rewritten so that it returns every block. + - tools/rebuild/build.py: the function target_hist and the field names + of profile follow the last part of select of + scripts/paired_cube/gauges.py; the calls that make the graph and its + hash follow regenerate of scripts/paired_cube_producer.py. + - tools/rebuild/f2.py: the function perp follows perp, and the second + half of the function rref follows the second half of basis, of + scripts/paired_cube/frames.py. + The outside programs are those at the two commits named above + (source_aligned_local_v4.py at the second, the others at the first). + Of the other seven files, rebuild.py, fetch_inputs.py, rbpaths.py, + rewrite.py, phys.py and emit.py were written for this repository. + modules.py was written for this repository too; for the three module + files it checks the contract that the outside + scripts/paired_cube/modules.py states for them in its functions + triple_module_from, pair_module_from and all_but_one_from, each of + which is marked there "eumemic, Claude assistance; Apache-2.0". + + Notices and attribution sentences in the first lines of those outside + programs, quoted with the line numbers of each file at its commit. + The other lines of each header say what the program does and name no + person: + + scripts/paired_cube/closure.py, lines 4-5 (pull request #168, + eumemic; from pull request #162, DaysSky): + Copyright 2026 DaysSky (PR162, + research/extended-links/cxlinks.py), Apache-2.0; moved here + unchanged apart from this header and the imports (eumemic, Claude + assistance). + + scripts/paired_cube/graph.py, modules.py, frames.py, gauges.py and + scripts/paired_cube_producer.py (pull request #144, icekylinx; + graph.py, modules.py and paired_cube_producer.py changed in #168, + eumemic), the two comment lines at the top of each: + Copyright 2026 icekylinx. Apache-2.0. + Developed with GPT-6 Astra assistance; integrated with Codex + assistance. + graph.py, lines 6-9: + The coarse positive query modules restrict the already adopted + PR117 DAG (eumemic; Apache-2.0; Claude assistance; + cbb05ce504d571546d9b7794c186a613c659c3bf). The paired-channel + decomposition and this assembly are new work for icekylinx with + OpenAI GPT-6 Astra assistance. + modules.py, lines 6-7: + The pair-disjoint module is a specialization of the already + adopted PR117 positive DAG (eumemic, Apache-2.0, pinned + cbb05ce504d571546d9b7794c186a613c659c3bf). + modules.py, line 272, above merge_outputs: + Output merging (pmerge.py variants; eumemic, Claude assistance; + Apache-2.0). + frames.py, line 7: + New work for icekylinx, OpenAI GPT-6 Astra assistance. + paired_cube_producer.py, line 8: + Copyright 2026 icekylinx, Apache-2.0; OpenAI GPT-6 Astra + assistance, inherited PR117 notices. + + scripts/paired_cube_physical.py, lines 4-7 (pull request #168, + eumemic): + Prepared by eumemic with Anthropic Claude assistance. Apache-2.0. + The signed word, frozen arcs, gauges, chronology and shared-core + accounting are icekylinx's PR144. Frame descent under PR130's + general Clifford frames and compensated birth-cut reuse follow + PR131 and jamesyc's PR124; deadline (late) compensation reads + follow PR143. + + research/terminal-sinks/sinks_gate.py, lines 4-6 (pull request + #168, eumemic): + The substitution is the terminal-sink lemma of PR #166 by jamesyc + (closed by its author), independently audited here: this gate's + own frame scans, replay and controls carry the soundness argument + and do not use #166's checker. Gate, audit and integration by + eumemic with Anthropic Claude assistance. Apache-2.0. + + research/source-assisted-v4/source_aligned_local_v4.py, lines 4-9 + (pull requests #191 and #193, ikeboy / Avi Eisenberg): + Derived from + research/source-assisted/decision/source_aligned_local.py + (icekylinx, GPT-6 Astra assistance, Apache-2.0). Only the three + frozen query modules change: this copy reads PR168 v4's selected + modules (eumemic, Claude assistance) from + references/paired-cube/sources instead of the PR168 fd25adb7 + modules. The local configuration, arc transport, frame + inheritance and physical layer code are unchanged. + + Notices of that NOTICE file that pertain to these data, quoted: + + Paired-cube and shared-core extension, 9 October 2026 + Copyright 2026 icekylinx + + Source-assisted common-frame extension (2026-10-09) + Copyright 2026 icekylinx. Apache-2.0. + Substantial dependency: eumemic PR168, + fd25adb7fbaa12ee761d02c733c54d1d2a7687ee + + The full text of both notices, and the notices of the work they build on, + are in the copy named above. The credits, with links and with the words of + pull request #193 about its own sources, are in README.md ("Whose circuit + this is") and in RELATED-WORK.md, section 1. + +7. Modified copies of upstream files (third and fourth results). + The files listed below are copies of files of openai/math at the commit + above, changed for this repository. Each begins with a comment that names + the upstream file it is derived from and states what was changed. The + upstream originals under lean/OAI/Computability/ are in this repository + as well, unchanged (section 1), and the copies import them. The upstream + challenge file lean/ComparatorChallenges/UniformFourier.lean is in this + repository in both forms: unchanged under third-party/openai-math/ + (section 1) and modified (section 2). + + - Work/Fourier/ArbitraryLength.lean: modified copy of + lean/OAI/Computability/FourierTransform/ArbitraryLength.lean (224 + lines; 159 of them unchanged in the copy). Changes: identifiers renamed + on 64 lines (18 names: 15 with the suffix Z, 3 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/Asymptotics.lean: modified copy of + lean/OAI/Computability/FourierTransform/Asymptotics.lean (187 lines; + 112 of them unchanged in the copy). Changes: identifiers renamed on 74 + lines (32 names: 26 with the suffix Z, 6 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + - Work/Fourier/Axioms.lean: written for this repository (not a copy of an + upstream file). + - Work/Fourier/ConvolutionProgram.lean: modified copy of + lean/OAI/Computability/FourierTransform/ConvolutionProgram.lean (100 + lines; 77 of them unchanged in the copy). Changes: identifiers renamed + on 22 lines (10 names: 9 with the suffix Z, 1 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/Goal.lean: written for this repository; contains lines of + upstream files: of its 7 code lines, 6 are lines of + lean/OAI/Computability/FourierTransform/Goal.lean (original lines 35, + 75-77, 79, 81): unchanged: its lines 25; with identifiers renamed: its + lines 21, 24, 26, 28, 30. + - Work/Fourier/Main.lean: modified copy of + lean/OAI/Computability/FourierTransform/Main.lean (151 lines; 90 of + them unchanged in the copy). Changes: identifiers renamed on 59 lines + (40 names: 35 with the suffix Z, 5 with Z inserted); 1 import line + replaced by 2; 24 comment lines added; other code lines changed: 1 of + the original, 1 of the copy (copy line 59). + - Work/Fourier/Seam.lean: written for this repository; contains lines of + upstream files: of its 122 code lines, 15 are lines of + lean/OAI/Computability/FourierTransform/TensorProgram.lean (original + lines 36-37, 95-96): unchanged: its lines 93-94, 113-114, 141-142, + 163-164, 185-187, 194-196; with identifiers renamed: its lines 184; 3 + are lines of lean/OAI/Computability/FourierTransform/TensorSaving.lean + (original lines 83-84, 114): with identifiers renamed: its lines 45-46, + 59; 1 is a line of lean/OAI/Computability/FourierTransform/Main.lean + (original line 60): with identifiers renamed: its lines 213. + - Work/Fourier/SectorAlgorithm.lean: modified copy of + lean/OAI/Computability/FourierTransform/SectorAlgorithm.lean (224 + lines; 162 of them unchanged in the copy). Changes: identifiers renamed + on 61 lines (17 names: 13 with the suffix Z, 4 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/SynchronizedAlgorithm.lean: modified copy of + lean/OAI/Computability/FourierTransform/SynchronizedAlgorithm.lean (126 + lines; 94 of them unchanged in the copy). Changes: identifiers renamed + on 31 lines (12 names: 10 with the suffix Z, 1 with Z inserted, 1 + other), the other being "canopy" to "Grove.canopy" (5 lines); 1 import + line replaced by 1; 16 comment lines added; no other change to the + code. + - Work/Fourier/TransformProgram.lean: modified copy of + lean/OAI/Computability/FourierTransform/TransformProgram.lean (146 + lines; 94 of them unchanged in the copy). Changes: identifiers renamed + on 51 lines (21 names: 19 with the suffix Z, 2 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/UniformBounds.lean: modified copy of + lean/OAI/Computability/FourierTransform/UniformBounds.lean (183 lines; + 115 of them unchanged in the copy). Changes: identifiers renamed on 67 + lines (29 names: 25 with the suffix Z, 4 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + - Work/Fourier/UniformFourierChallenge.lean: modified copy of + lean/ComparatorChallenges/UniformFourier.lean (336 lines; 328 of them + unchanged in the copy). Changes: identifiers renamed on 7 lines (7 + names: 7 with the suffix Z); 12 comment lines added; other code lines + changed: 1 of the original, 1 of the copy (copy line 281). + - Work/Fourier/WorkingCompiler.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingCompiler.lean (153 + lines; 104 of them unchanged in the copy). Changes: identifiers renamed + on 48 lines (14 names: 14 with the suffix Z); 1 import line replaced by + 1; 15 comment lines added; no other change to the code. + - Work/Fourier/WorkingPreparation.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingPreparation.lean (212 + lines; 156 of them unchanged in the copy). Changes: identifiers renamed + on 55 lines (30 names: 28 with the suffix Z, 2 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/WorkingTransform.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingTransform.lean (119 + lines; 91 of them unchanged in the copy). Changes: identifiers renamed + on 27 lines (9 names: 8 with the suffix Z, 1 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + + Changes made to the eleven copied proof files: every declaration received + the letter "Z" in its name (as a suffix of its own name, or of the name + of the declaration it belongs to), so that it does not collide with the + upstream declaration of the same name; the upstream exponent "alpha" + (1 - 2/10^11) and the bound "hills" defined from it were replaced by + "alphaZ" (1 - 7474547/10^10) and "hillsZ", which are defined in + Work/Fourier/Seam.lean, and the single use of the upstream theorem + "hills_program" by "hillsZ_program"; the five definitions of the upstream + statement that contain its exponent (decimalExponent, decimalTime, + TimeBounds, DFTGoal, ConvGoal) were replaced by the versions of + Work/Fourier/Goal.lean, whose exponent is 1 - 7474546/(10^(10:ℕ)); + the import lines point to the copies; a header comment was added. + Two further changes: in the copy of Main.lean the same constant stands + once as the literal 2/10^11 and was replaced there too, and the two + final theorems of that copy received a documentation comment; in the + copy of SynchronizedAlgorithm.lean the name "canopy" was written out as + "Grove.canopy" in 5 places, because the short name is shadowed in the + larger environment of the copy. The script also renamed three names + inside upstream comments; the comments are otherwise the upstream ones + and describe the upstream network. + The proofs are those of openai/math. The copies were made by the script + tools/fourier/mkchain.py of this repository. + + Work/Fourier/Goal.lean contains copies of those five definitions of + lean/OAI/Computability/FourierTransform/Goal.lean, with the exponent + replaced and the suffix "Z" on the five names. + + Work/Fourier/Seam.lean was written for this repository. It repeats the + statement of the upstream theorem "hills_program" (TensorProgram.lean) and + the definition of "hills" (TensorSaving.lean) with the two names replaced; + its header says so. + + Fourth result. The 15 files under Work/FourierE8/ repeat the 15 files + under Work/Fourier/ for the kernel program of the fourth result, file + for file and under the same file names: ArbitraryLength.lean, + Asymptotics.lean, ConvolutionProgram.lean, Goal.lean, Main.lean, + SectorAlgorithm.lean, SynchronizedAlgorithm.lean, TransformProgram.lean, + UniformBounds.lean, UniformFourierChallenge.lean, WorkingCompiler.lean, + WorkingPreparation.lean, WorkingTransform.lean, Seam.lean and + Axioms.lean. The eleven copied proof files, + Goal.lean and UniformFourierChallenge.lean are modified copies of the + same upstream files as their namesakes above, made by the script + tools/fourier/mkchain_e8.py (a copy of tools/fourier/mkchain.py with + its constants changed). The changes are those described above with + three differences: the suffix is "E8" where the copies of the third + result have "Z"; "alphaE8" is 1 - 8762479/10^10; and the exponent of + Work/FourierE8/Goal.lean is 1 - 8762478/(10^(10:ℕ)). Each of these + files begins with a comment that names the upstream file it is derived + from and states what was changed. Work/FourierE8/Seam.lean and + Work/FourierE8/Axioms.lean were written for this repository: they are + Work/Fourier/Seam.lean and Work/Fourier/Axioms.lean with names and + numbers replaced, and the seam repeats the same upstream statement and + definition as the seam of the third result. The proofs are those of + openai/math. + + The work of others that the third result follows (danadran01, shea256, + eumemic) is credited in README.md ("Whose reduction this is") and in + RELATED-WORK.md, section 1. No file of their repositories is included + here. + +8. The certificate of the fourth result and the search programs. + tools/certificate/gcert1-e8-r783.json.gz, the Lean data modules + generated from it (Work/GCert/Data/Gen/E8*.lean, Work/GCert/Data/Gen/E8/ + and the modules of Work/GCert/Data/ with E8 or B2Ge8 in their names) and + the Python programs under tools/e8/ were made by the agents for this + repository on 2026-10-10 (section 4). The circuit in that certificate + is not the circuit of section 6, and no data file of + CrocSwap/integer-mult-bounds was loaded to make it. It uses three + devices that were published by others in pull requests to that + repository: + - the in-place pair, a + b and a - b formed on the two arrays that held + a and b: icekylinx (#184), carried in #191 and #193 (ikeboy); + - the re-use of a finished helper with a compensating read: jamesyc + (#124) and eumemic (#143); + - the late pairing rule, the choice of which finished helper a new + value takes: Chafik Boukhalfa (the account chafreaky), #200 and #233, + and pull request #2 of this repository. The search programs apply the + idea with a greedy rule of their own; his program, his pairs and his + certificate were not used. + No program of that repository is included in tools/e8/, imported or + run by it. The programs of tools/e8/ have not been compared statement + by statement with the programs of that repository, as those of + tools/rebuild/ were (section 6). The integer programme of + tools/e8/ is solved with the open-source solver HiGHS, called through + SciPy (scipy.optimize.milp), with NumPy; none of the three is included + here. The credits, with links, are in README.md ("Whose ideas the new + unit uses") and in RELATED-WORK.md, section 8. + +Not included in this repository and fetched by the build: Mathlib +(https://github.com/leanprover-community/mathlib4, Apache License 2.0) and its +dependencies. The comparator (https://github.com/leanprover/comparator) is a +separate tool and is not included. diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8.lean new file mode 100644 index 0000000000..d1e3afba66 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8.lean @@ -0,0 +1,103 @@ +import Work.GCert.Chain.End +import Work.GCert.Data.Glue +import Work.GCert.Data.E8Cert +import Work.GCert.Data.InstB2Ge8 + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `E8` (h = 9, m = 45): final theorems over a scalar half +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`GX.wht_of_halves` (gx-chain) on the label half `GXD.E8.valid` (kernel checks of `Work/GCert/Data/Gen/E8*`), its +price `GXD.E8.lab_price`, the unit list `BlockAccounting.blocksB2Ge8` (`W = 1263` live roles) and the rate facts +`fold_B2Ge8` (`1 - 87624/10^8`), `fold_B2Ge8x` (`1 - 8762479/10^10`). +The ONLY hypothesis left is the scalar half: `S : GX.Scal (Fin 120) (Fin 783) C` whose gate matrices are the ordered +products of the adds of `raw` (`hMA .. hMBi`), with `8` copies read from the retained registers (`reg`, `hCc`, `hreg`, `hC`); +`wht_B2Ge8_of_ids`, `wht_B2Ge8x_of_ids`: the same from the five identities `hAi hBi hx hy hid` of gx-scalar's matrices +`GS.MA GS.MAi GS.MB GS.MBi GS.Jrm GS.Ccm` of `raw` (the fields of the planned `GS.ScalOK`). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT + +variable {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin GXD.E8.raw.v) (Fin GXD.E8.raw.R) C) + {emb : CR.L3 (Fin GXD.E8.raw.v) (Fin GXD.E8.raw.R) → Nat} {un : Nat → CR.L3 (Fin GXD.E8.raw.v) (Fin GXD.E8.raw.R)} + (cf : GXD.Co → SSC.Coef) + +/-- **Walsh-Hadamard transform, whole-block recursion on the bridged word B_2 with the gcert/1 circuit `E8`**, +over any scalar half of `GXD.E8.raw`: the statement `WHTGoal` of `WHTCheck/Challenge.lean` with `1 - 2/10^11` +replaced by `1 - 87624/10^8`. -/ +theorem wht_B2Ge8_of_scal (Ro : GLab.Roles GXD.E8.raw.v GXD.E8.raw.R emb un) + (hMA : S.MA = SSC.matP un (GLab.mic cf (GXD.E8.raw.gatesA.flatMap GXD.Gate.adds))) + (hMAi : S.MAi = SSC.matPinv un (GLab.mic cf (GXD.E8.raw.gatesA.flatMap GXD.Gate.adds))) + (hMB : S.MB = SSC.matP un (GLab.mic cf (GXD.E8.raw.gatesB.flatMap GXD.Gate.adds))) + (hMBi : S.MBi = SSC.matPinv un (GLab.mic cf (GXD.E8.raw.gatesB.flatMap GXD.Gate.adds))) + (reg : C → Nat) (hCc : ∀ k (q : Fin GXD.E8.raw.R), S.Cc k q ≠ 0 → reg k = 2 * GXD.E8.raw.v + q.val) + (hreg : ∀ k, reg k ∈ GXD.E8.raw.ret.map Prod.fst) (hC : Fintype.card C = 8) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 87624/(10:ℝ)^8) W := + GX.wht_of_halves S (GXD.E8.valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg) + (by rw [Fintype.card_fin]; decide) 45 1263 (by rw [Fintype.card_fin]; rfl) + (by rw [Fintype.card_fin, Fintype.card_fin]; rfl) (by norm_num) BlockAccounting.blocksB2Ge8 + (fun φ => by + rw [GXD.E8.lab_price S Ro cf hMA hMAi hMB hMBi reg hCc hreg hC φ, Fintype.card_fin, Fintype.card_fin] + exact BridgeRate.B2Ge8.unit_cost φ) + 13 (1 - 87624/(10:ℝ)^8) (by norm_num) (by norm_num) BlockAccounting.fold_B2Ge8 + +/-- the same from the FIVE scalar identities of gx-scalar's matrices of `GXD.E8.raw` (`Work/GCert/Data/Glue.lean`) -/ +theorem wht_B2Ge8_of_ids (hv : 0 < GXD.E8.raw.v) + (hAi : GS.MAi GXD.E8.raw hv * GS.MA GXD.E8.raw hv = 1) (hBi : GS.MBi GXD.E8.raw hv * GS.MB GXD.E8.raw hv = 1) + (hx : ∀ (t : Fin GXD.E8.raw.v) (j : GS.Rl GXD.E8.raw), (GS.MB GXD.E8.raw hv * CR.scatM (GS.Jrm GXD.E8.raw * GS.Ccm GXD.E8.raw) + * GS.MA GXD.E8.raw hv) (CR.lX t) j = if CR.lX t = j then 1 else 0) + (hy : ∀ (i : GS.Rl GXD.E8.raw) (t : Fin GXD.E8.raw.v), (GS.MB GXD.E8.raw hv * CR.scatM (GS.Jrm GXD.E8.raw * GS.Ccm GXD.E8.raw) + * GS.MA GXD.E8.raw hv) i (CR.lY t) = if i = CR.lY t then 1 else 0) + (hid : ∀ S t : Fin GXD.E8.raw.v, (GS.MB GXD.E8.raw hv * CR.scatM (GS.Jrm GXD.E8.raw * GS.Ccm GXD.E8.raw) + * GS.MA GXD.E8.raw hv) (CR.lY S) (CR.lX t) = if S = t then 1 else 0) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 87624/(10:ℝ)^8) W := + wht_B2Ge8_of_scal (GXD.scalOf GXD.E8.raw hv hAi hBi hx hy hid) GS.toCoef (GXD.roles GXD.E8.raw hv) + (GXD.scalOf_MA _ hv hAi hBi hx hy hid) (GXD.scalOf_MAi _ hv hAi hBi hx hy hid) + (GXD.scalOf_MB _ hv hAi hBi hx hy hid) (GXD.scalOf_MBi _ hv hAi hBi hx hy hid) + (GXD.reg GXD.E8.raw) (GXD.reg_slot GXD.E8.raw hv hAi hBi hx hy hid) (GXD.reg_mem GXD.E8.raw) + (by rw [Fintype.card_fin]; decide) + +/-- **Walsh-Hadamard transform, whole-block recursion on the bridged word B_2 with the gcert/1 circuit `E8`**, +over any scalar half of `GXD.E8.raw`: the statement `WHTGoal` of `WHTCheck/Challenge.lean` with `1 - 2/10^11` +replaced by `1 - 8762479/10^10`. -/ +theorem wht_B2Ge8x_of_scal (Ro : GLab.Roles GXD.E8.raw.v GXD.E8.raw.R emb un) + (hMA : S.MA = SSC.matP un (GLab.mic cf (GXD.E8.raw.gatesA.flatMap GXD.Gate.adds))) + (hMAi : S.MAi = SSC.matPinv un (GLab.mic cf (GXD.E8.raw.gatesA.flatMap GXD.Gate.adds))) + (hMB : S.MB = SSC.matP un (GLab.mic cf (GXD.E8.raw.gatesB.flatMap GXD.Gate.adds))) + (hMBi : S.MBi = SSC.matPinv un (GLab.mic cf (GXD.E8.raw.gatesB.flatMap GXD.Gate.adds))) + (reg : C → Nat) (hCc : ∀ k (q : Fin GXD.E8.raw.R), S.Cc k q ≠ 0 → reg k = 2 * GXD.E8.raw.v + q.val) + (hreg : ∀ k, reg k ∈ GXD.E8.raw.ret.map Prod.fst) (hC : Fintype.card C = 8) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 8762479/(10:ℝ)^10) W := + GX.wht_of_halves S (GXD.E8.valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg) + (by rw [Fintype.card_fin]; decide) 45 1263 (by rw [Fintype.card_fin]; rfl) + (by rw [Fintype.card_fin, Fintype.card_fin]; rfl) (by norm_num) BlockAccounting.blocksB2Ge8x + (fun φ => by + rw [GXD.E8.lab_price S Ro cf hMA hMAi hMB hMBi reg hCc hreg hC φ, Fintype.card_fin, Fintype.card_fin] + exact BridgeRate.B2Ge8.unit_cost_x φ) + 40 (1 - 8762479/(10:ℝ)^10) (by norm_num) (by norm_num) BlockAccounting.fold_B2Ge8x + +/-- the same from the FIVE scalar identities of gx-scalar's matrices of `GXD.E8.raw` (`Work/GCert/Data/Glue.lean`) -/ +theorem wht_B2Ge8x_of_ids (hv : 0 < GXD.E8.raw.v) + (hAi : GS.MAi GXD.E8.raw hv * GS.MA GXD.E8.raw hv = 1) (hBi : GS.MBi GXD.E8.raw hv * GS.MB GXD.E8.raw hv = 1) + (hx : ∀ (t : Fin GXD.E8.raw.v) (j : GS.Rl GXD.E8.raw), (GS.MB GXD.E8.raw hv * CR.scatM (GS.Jrm GXD.E8.raw * GS.Ccm GXD.E8.raw) + * GS.MA GXD.E8.raw hv) (CR.lX t) j = if CR.lX t = j then 1 else 0) + (hy : ∀ (i : GS.Rl GXD.E8.raw) (t : Fin GXD.E8.raw.v), (GS.MB GXD.E8.raw hv * CR.scatM (GS.Jrm GXD.E8.raw * GS.Ccm GXD.E8.raw) + * GS.MA GXD.E8.raw hv) i (CR.lY t) = if i = CR.lY t then 1 else 0) + (hid : ∀ S t : Fin GXD.E8.raw.v, (GS.MB GXD.E8.raw hv * CR.scatM (GS.Jrm GXD.E8.raw * GS.Ccm GXD.E8.raw) + * GS.MA GXD.E8.raw hv) (CR.lY S) (CR.lX t) = if S = t then 1 else 0) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 8762479/(10:ℝ)^10) W := + wht_B2Ge8x_of_scal (GXD.scalOf GXD.E8.raw hv hAi hBi hx hy hid) GS.toCoef (GXD.roles GXD.E8.raw hv) + (GXD.scalOf_MA _ hv hAi hBi hx hy hid) (GXD.scalOf_MAi _ hv hAi hBi hx hy hid) + (GXD.scalOf_MB _ hv hAi hBi hx hy hid) (GXD.scalOf_MBi _ hv hAi hBi hx hy hid) + (GXD.reg GXD.E8.raw) (GXD.reg_slot GXD.E8.raw hv hAi hBi hx hy hid) (GXD.reg_mem GXD.E8.raw) + (by rw [Fintype.card_fin]; decide) + +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_B2Ge8_of_scal +#print axioms OAI.PowerSaving.WHT.wht_B2Ge8x_of_scal +#print axioms OAI.PowerSaving.WHT.wht_B2Ge8_of_ids +#print axioms OAI.PowerSaving.WHT.wht_B2Ge8x_of_ids diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8Main.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8Main.lean new file mode 100644 index 0000000000..ef14876582 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/B2Ge8Main.lean @@ -0,0 +1,33 @@ +import Work.GCert.Scalar.Main +import Work.GCert.Data.E8ScalOK +import Work.GCert.Data.B2Ge8 + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `E8`: THE CLOSED THEOREMS +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`wht_B2Ge8_of_ids` (label half, price, unit list, rate fact, gx-chain's end theorem) applied to the scalar half +`GXD.E8.scalOK : GS.ScalOK GXD.E8.raw` (kernel checks `scal_ok`, `ychk_ok`; soundness: gx-scalar). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT + +/-- **Walsh-Hadamard transform in `O(n (log n)^(1 - 87624/10^8))`-type time bounds: whole-block recursion on the bridged +word B_2 with the kernel-checked gcert/1 circuit `E8`.** -/ +theorem wht_main_B2Ge8 : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 87624/(10:ℝ)^8) W := + wht_B2Ge8_of_ids GXD.E8.scalOK.hv GXD.E8.scalOK.hAi GXD.E8.scalOK.hBi GXD.E8.scalOK.hx GXD.E8.scalOK.hy GXD.E8.scalOK.hid + +/-- **Walsh-Hadamard transform in `O(n (log n)^(1 - 8762479/10^10))`-type time bounds: whole-block recursion on the bridged +word B_2 with the kernel-checked gcert/1 circuit `E8`.** -/ +theorem wht_main_B2Ge8x : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 8762479/(10:ℝ)^10) W := + wht_B2Ge8x_of_ids GXD.E8.scalOK.hv GXD.E8.scalOK.hAi GXD.E8.scalOK.hBi GXD.E8.scalOK.hx GXD.E8.scalOK.hy GXD.E8.scalOK.hid + +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_main_B2Ge8 +#print axioms OAI.PowerSaving.WHT.wht_main_B2Ge8x diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/ChallengeB2Ge8x.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/ChallengeB2Ge8x.lean new file mode 100644 index 0000000000..c6c1567f5d --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/ChallengeB2Ge8x.lean @@ -0,0 +1,331 @@ +import Mathlib + +/-! +Comparator challenge `Work.GCert.Data.ChallengeB2Ge8x` (not part of github.com/openai/math). + +Statement: the Walsh-Hadamard corollary with the exponent `1 - 8762479/10^10` in place of +`1 - 2/10^11`. Theorem: `OAI.PowerSaving.WHT.wht_main_block_B2Ge8x`. + +GENERATED by checks/wht9/bridge-rate/pack.py: this file is the comparator-passed +`Corollaries/WHTTwoStage/Challenge.lean` with exactly three changes: (1) this header comment; +(2) the name of the theorem (`wht_main_two_stage` there) and the exponent quoted in its doc +comment; (3) the exponent constant in the statement (`1 - 66451/(10:ℝ)^12` there, +`1 - 8762479/(10:ℝ)^10` here). All other lines are byte-for-byte the lines of that file: the RAM +cost model, `whtInKind`, `whtOutKind`, `wht`, `WHTProgram` and `WHTTimeBoundsAt`. + +The proof is `sorry` on purpose: this file is a STATEMENT. The proof is in +`Work.GCert.Data.SolutionB2Ge8x`. +-/ + +namespace OAI + +/-! +# Exact scalar and index RAM used for the algorithm + +Finite, first-order, expression/program syntax. Arrays below are random-access arrays of +registers (an array-valued register holds its address). An expression building an array uses +a fresh array; `sow` builds by a loop of writes instead of a loop supplying consecutive +entries. Programs have their usual sequential stack evaluation. Evaluation here records work +(including stack, index and array work), the high water mark on produced/logically looped-over +integer values (addresses *within* arrays are integers too), the value, and the side condition +required along the executed path (in particular no division by zero). The charged units of +work are constant time; as usual constant rescalings between ways to charge a fixed number +of scalar or address operations are immaterial. + +Enough address bits must be provided BOTH for the integer high water mark (and inputs), AND +for the work bound together with input size, as will be required in the theorem. Indeed we +use the particularly simple RAM convention where temporaries aren't reused: one work unit can +leave at most a constant number of cells (stack, pairs or array cells); whenever many array +entries are made their number is charged. So a constant number of words of those sizes also +suffices for arena addresses. Nothing charges constant work for changing an already published +array to a different array as a whole. Register and stack layouts, and the convention whether +registers hold pairs or addresses of pairs, only have constant factors (the program is fixed). + +Scalar and data field registers are separated. Tests and loop/request sizes are on nonnegative +integer registers. There is no instruction for an arbitrary complex constant. A supplied +specified root will be an input. Divisions are on prepared scalars; valid runs require every +such denominator nonzero; the side condition is *not* a test performed by the algorithm. +The Bool mode on the syntax allows or prohibits general products (two-input convolution +versus the transform); even when allowed we use separate register kinds before and after +the bilinear products. + +Definitions are mathematical operation-count semantics, not a model of running Lean code. +E.g. a function on Fin n represents the n cells of a random-access array, not a function +closure at runtime. +-/ + +namespace PowerSaving + +universe u v + +variable {α : Type u} {β : Type v} + +/-- Register arrays. -/ +structure Tape (α : Type u) where + len : ℕ + pos : Fin len → α + +namespace Tape + +def empty (α : Type u) : Tape α := ⟨0, Fin.elim0⟩ + +/-- Materialized array. -/ +def tab (n : ℕ) (f : ℕ → α) : Tape α := ⟨n, fun i => f i.val⟩ + +/-- Read with fixed out of bounds default. -/ +def look (v : Tape α) (i : ℕ) (z : α) : α := + if h : i < v.len then v.pos ⟨i,h⟩ else z + +@[simp] theorem look_of_lt (v : Tape α) (z : α) {i} (h : i < v.len) : + v.look i z = v.pos ⟨i,h⟩ := by simp [look, h] + +@[simp] theorem look_of_le (v : Tape α) (z : α) {i} (h : v.len ≤ i) : + v.look i z = z := by simp [look, Nat.not_lt.mpr h] + +/-- Semantics of a write into fresh storage; out-of-range writes are ignored. Only used + during construction, never a whole-tape functional update instruction. -/ +def set (v : Tape α) (i : ℕ) (x : α) : Tape α := + ⟨v.len, fun j => if j.val = i then x else v.pos j⟩ + +def sow (len count : ℕ) (z : α) (f : ℕ → ℕ × α) : Tape α := + iter count +where + iter : ℕ → Tape α + | 0 => tab len (fun _ => z) + | i+1 => (iter i).set (f i).1 (f i).2 + +def map (f : α → β) (v : Tape α) : Tape β := ⟨v.len, fun i => f (v.pos i)⟩ + +end Tape + +namespace RAM + +inductive Paint + | scalar + | left + | right + | both + +inductive Ty + | w + | c : Paint → Ty + | p : Ty → Ty → Ty + | a : Ty → Ty + +open Ty + +abbrev sc := c .scalar + +@[reducible] def Ty.T : Ty → Type + | w => ℕ + | c _ => ℂ + | p s b => s.T × b.T + | a b => Tape b.T + +noncomputable def Ty.blank : (t : Ty) → t.T + | w => 0 + | c _ => 0 + | p s t => (s.blank, t.blank) + | a b => Tape.empty b.T + +/-- One basic work unit below pays for O(1) primitive RAM operations; includes loop and + stack overhead. `peak` tracks produced/needed integer quantities beyond inputs + (total allocation for stack and array bases is covered separately by work). -/ +structure Bill (α : Type u) where + val : α + work : ℕ + peak : ℕ + valid : Prop + +namespace Bill + +/-- Charge some work and optionally a new word bound. -/ +def pay (b : Bill α) (n : ℕ) (m : ℕ) : Bill α := + ⟨b.val, b.work+n, max b.peak m, b.valid⟩ + +/-- Both computations are evaluated. -/ +def pass (b : Bill α) (f : α → Bill β) : Bill β := + let d := f b.val + ⟨d.val, b.work+d.work, max b.peak d.peak, b.valid ∧ d.valid⟩ + +def one (x : α) : Bill α := ⟨x,1,0,True⟩ +def word (x : ℕ) : Bill ℕ := ⟨x,1,x,True⟩ + +/-- Execute f 0 through f (n-1), iterating an accumulator. -/ +def steps (init : α) (f : ℕ → α → Bill α) : ℕ → Bill α + | 0 => Bill.one init + | i+1 => ((steps init f i).pass (f i)).pay 1 (i+1) + +/-- Build Tape len by count writes (initialized with a blank z). -/ +def sow (len count : ℕ) (z : α) (f : ℕ → Bill (ℕ × α)) : Bill (Tape α) := + (steps (Tape.tab len (fun _ => z)) + (fun i v => (f i).pass (fun s => one (v.set s.1 s.2))) count).pay (1+len) len + +/-- Build Tape len. As for sow we can first allocate then perform writes. -/ +def tab (len : ℕ) (z : α) (f : ℕ → Bill α) : Bill (Tape α) := + sow len len z (fun i => (f i).pass (fun y => one (i,y))) + +end Bill + +inductive NOp + | add | sub | mul | div | mod | lt -- truncated subtraction; compare returns 1 or 0 + +inductive Atom (allow : Bool) : Ty → Ty → Type + | lit {a} (n : ℕ) : Atom allow a w + | int (f : NOp) : Atom allow (p w w) w + | cz (t) {a} : Atom allow a (c t) + | cone {a} : Atom allow a sc + | add (t) : Atom allow (p (c t) (c t)) (c t) + | sub (t) : Atom allow (p (c t) (c t)) (c t) + | scale (t) : Atom allow (p sc (c t)) (c t) + | inv : Atom allow sc sc + | cross (h : allow = true) : + Atom allow (p (c .left) (c .right)) (c .both) + | id {a} : Atom allow a a + | fst {a b} : Atom allow (p a b) a + | snd {a b} : Atom allow (p a b) b + | len {s} : Atom allow (a s) w + | look {s} : Atom allow (p (a s) w) s + +noncomputable def NOp.run : NOp → (ℕ × ℕ) → Bill ℕ + | .add, (i,j) => Bill.word (i+j) + | .sub, (i,j) => Bill.word (i-j) + | .mul, (i,j) => Bill.word (i*j) + | .div, (i,j) => Bill.word (i/j) -- includes usual guard (returns zero) + | .mod, (i,j) => Bill.word (i%j) -- like Lean: returns i if j=0 + | .lt, (i,j) => Bill.word (if i Bill.word n + | .int f, x => f.run x + | .cz _, _ => Bill.one 0 + | .cone, _ => Bill.one 1 + | .add _, (x,y) => Bill.one (x+y) + | .sub _, (x,y) => Bill.one (x-y) + | .scale _, (x,y) => Bill.one (x*y) + | .inv, x => ⟨x⁻¹,1,0,x ≠ 0⟩ + | .cross _, (x,y) => Bill.one (x*y) + | .id, x => Bill.one x + | .fst, x => Bill.one x.1 + | .snd, x => Bill.one x.2 + | .len, x => Bill.word x.len + | @Atom.look _ s, (x,i) => Bill.one (x.look i s.blank) + +abbrev Port := Option (Ty × Ty) + +/-- `call` is internal for bounded recursion; a program has Port = none. `loop`, `tab` + and `sow` retain the input to access parameters in the body. `descend` sets up bounded + recursion, reading fuel and initial argument. -/ +inductive Code (allow : Bool) : Port → Ty → Ty → Type + | atom {r s t} (op : Atom allow s t) : Code allow r s t + | comp {r s t u} (f : Code allow r s t) (g : Code allow r t u) : Code allow r s u + | fork {r s t u} (f : Code allow r s t) (g : Code allow r s u) : Code allow r s (p t u) + | ifz {r s t} (q : Code allow r s w) (f g : Code allow r s t) : Code allow r s t + | loop {r s t} (n : Code allow r s w) (init : Code allow r s t) + (body : Code allow r (p s (p w t)) t) : Code allow r s t + | tab {r s t} (n : Code allow r s w) + (body : Code allow r (p s w) t) : Code allow r s (a t) + | sow {r s t} (n count : Code allow r s w) + (body : Code allow r (p s w) (p w t)) : Code allow r s (a t) + | importClosed {r s t} (f : Code allow none s t) : Code allow r s t + | call {s t} : Code allow (some (s,t)) s t + | descend {r s t} (base : Code allow none s t) + (body : Code allow (some (s,t)) s t) : Code allow r (p w s) t + +@[reducible] def Handler : Port → Type + | none => Unit + | some (s,t) => s.T → Bill t.T + +def depthRun (base : α → Bill β) + (step : (α → Bill β) → (α → Bill β)) : ℕ → α → Bill β + | 0, x => (base x).pay 1 0 + | n+1, x => (step (depthRun base step n) x).pay 1 (n+1) + +noncomputable def Code.run {allow r s t} : Code allow r s t → Handler r → s.T → Bill t.T + | .atom op, _, x => op.run x + | .comp f g, h, x => ((f.run h x).pass (g.run h)).pay 1 0 + | .fork f g, h, x => (f.run h x).pass (fun y => (g.run h x).pass (fun z => Bill.one (y,z))) + | .ifz q f g, h, x => ((q.run h x).pass (fun y => + if (y : ℕ) = 0 then f.run h x else g.run h x)).pay 1 0 + | .loop n init body, h, x => + ((n.run h x).pass (fun l => (init.run h x).pass (fun y => + Bill.steps y (fun i z => body.run h (x,(i,z))) l))).pay 1 0 + | @Code.tab _ _ _ t n body, h, x => + ((n.run h x).pass (fun l => + Bill.tab l t.blank (fun i => body.run h (x,i)))).pay 1 0 + | @Code.sow _ _ _ t n count body, h, x => + ((n.run h x).pass (fun l => (count.run h x).pass (fun k => + Bill.sow l k t.blank (fun i => body.run h (x,i))))).pay 1 0 + | .importClosed f, _, x => (f.run () x).pay 1 0 + | .call, h, x => (h x).pay 1 0 + | .descend base step, _, (k,x) => + (depthRun (base.run ()) (step.run) k x).pay 1 k + +abbrev Prog (allow : Bool) (s t : Ty) := Code allow none s t + +noncomputable abbrev run {allow s t} (f : Prog allow s t) (x : s.T) : Bill t.T := + f.run () x + +end RAM +end PowerSaving + +namespace PowerSaving +namespace WHT +noncomputable section + +section Statement +open RAM RAM.Ty Filter Asymptotics + +/-- Input `(k, I, x)`: the exponent, the scalar constant `I` (the RAM has no instruction +producing it), and the data array of length `2^k`. Same register kinds as `dftInKind`. -/ +abbrev whtInKind := p w (p sc (a (c Paint.left))) +abbrev whtOutKind := a (c Paint.left) + +/-- Walsh-Hadamard transform of length `2^k` in natural (Sylvester) order: +`wht k x j = ∑ l, (-1)^(number of common 1-bits of j and l) * x l`. -/ +def wht (k : ℕ) (x : Fin (2^k) → ℂ) : Fin (2^k) → ℂ := + fun j => ∑ l : Fin (2^k), + (∏ i ∈ Finset.range k, if j.val.testBit i && l.val.testBit i then (-1 : ℂ) else 1) * x l + +/-- One fixed program `solve`; on input `(k, I, x)` it returns the Walsh-Hadamard transform +of `x`, every run is valid (no division by zero), all integers produced and the work +allowance are polynomial in `N = 2^k`, and the work is at most `W k`. -/ +def WHTProgram (solve : Prog false whtInKind whtOutKind) (W : ℕ → ℕ) : Prop := + ∃ cBound : ℕ, ∀ k : ℕ, + let N := 2^k + let cap := (N+2)^cBound + W k + 10*(N+2) ≤ cap ∧ + ∀ x : Fin N → ℂ, + let result := run solve (k, Complex.I, (⟨N,x⟩ : Tape ℂ)) + result.valid ∧ result.peak ≤ cap ∧ result.work ≤ W k ∧ + result.val = (⟨N, wht k x⟩ : Tape ℂ) + +end Statement + +-- Same `open`/`universe` context as `Exponent.lean` (lines 32, 266-267, 321-322), minus the +-- namespaces that do not exist without the upstream development +-- (`Bench`, `Selection`, `Cluster`, `RAM.Bench`, `Binary`). +open RAM Filter Asymptotics +open RAM RAM.Ty Matrix Finset Complex +universe U V + +section Explicit +open Filter Asymptotics + +/-- `W = O(2^k (k+1)^β)` and `W = o(2^k k)` (`WHTTimeBounds` is the case `β = 1 - 2/10^11`). -/ +def WHTTimeBoundsAt (β : ℝ) (W : ℕ → ℕ) : Prop := + let W' := fun k : ℕ => (W k : ℝ) + W' =O[atTop] (fun k : ℕ => (2:ℝ)^k * ((k:ℝ)+1)^β) ∧ + W' =o[atTop] (fun k : ℕ => (2:ℝ)^k * (k:ℝ)) + +/-- **Walsh-Hadamard transform with the improved exponent**: the statement `WHTGoal` of +`WHTCheck/Challenge.lean` with `1 - 2/10^11` replaced by `1 - 8762479/10^10`. -/ +theorem wht_main_block_B2Ge8x : + ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 8762479/(10:ℝ)^10) W := by + sorry + +end Explicit +end +end WHT +end PowerSaving +end OAI diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Cert.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Cert.lean new file mode 100644 index 0000000000..ab43d9bf07 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Cert.lean @@ -0,0 +1,78 @@ +import Work.GCert.Labels.Main +import Work.GCert.Data.E8Price +import Work.GCert.Data.Gen.E8Tab0 +import Work.GCert.Data.Gen.E8Tab1 +import Work.GCert.Data.Gen.E8Tab2 +import Work.GCert.Data.Gen.E8Tab3 +import Work.GCert.Data.Gen.E8Seg0 +import Work.GCert.Data.Gen.E8Seg1 +import Work.GCert.Data.Gen.E8SegF +import Work.GCert.Data.Gen.E8End +/-! # (key: gx-data) gcert/1 certificate `E8` (h = 9): THE LABEL HALF and its price +GENERATED by checks/wht26/gx-data/py/gxgen.py from gcert1-e8-r783.json.gz. No `sorry`. +`v = 120` ports, `R = 783` slots, 8 scratch copies of rank 9, copy cost `cst = 72`, `N = 9039` unit moves. +* `aux : GLab.Aux`, `valid : GLab.Valid raw aux`: frame table (`tab_ok` composed by `tabK_node`), the replays of phase A + and phase B (`seg_ok` composed by `Run.append`), the final climbs (`segF_ok`, `fin_ok`), the ends (`end_ok`); +* `lab_cost`, `lab_price`: for ANY scalar half `S` the label half `valid.lab S ..` costs + `rcost rA + card C * bcost 9 + rcost rB + rcost rF` = `invPrice φ` = 2091 * φ 1 + 604 * φ 2 + 518 * φ 3 + 140 * φ 4 + 215 * φ 5 + 331 * φ 6 + 43 * φ 7 + 24 * φ 8 + 8 * φ 9 + (`Gen.E8Hist`, `E8Price`) when there are 8 copies. -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD OAI.PowerSaving OAI.PowerSaving.CB +theorem raw_h : raw.h = 9 := rfl +theorem raw_v : raw.v = 120 := rfl +theorem raw_R : raw.R = 783 := rfl +/-- what the label checks read next to `raw` -/ +noncomputable def aux : GLab.Aux := ⟨par, st0, st1, st2, st3, fins, rA, rB, rF⟩ +theorem fin_ok : GLab.noAdds fins = true := by decide +kernel +theorem cen_ok : (raw.ret.map Prod.fst).all (fun r => Nat.beq (GLab.cdim (par.tab.get (st1.get r))) 9) = true := by + decide +kernel +theorem tab_ok : GLab.tabK par.h par.tab = true := (GLab.tabK_node _ _ _ (GLab.tabK_node _ _ _ tab0_ok tab1_ok) (GLab.tabK_node _ _ _ tab2_ok tab3_ok)) +theorem gatesA_eq : raw.gatesA = seg0 := by + show List.flatten [seg0] = _ + simp only [List.flatten_cons, List.flatten_nil, List.append_nil] +/-- the replay of phase A, composed from its kernel-checked segments -/ +theorem runA : GLab.Run par st0 raw.gatesA st1 rA := by + rw [gatesA_eq] + exact GLab.Run.of_seg seg0_ok +theorem gatesB_eq : raw.gatesB = seg1 := by + show List.flatten [seg1] = _ + simp only [List.flatten_cons, List.flatten_nil, List.append_nil] +/-- the replay of phase B, composed from its kernel-checked segments -/ +theorem runB : GLab.Run par st1 raw.gatesB st2 rB := by + rw [gatesB_eq] + exact GLab.Run.of_seg seg1_ok +/-- **the kernel-checked label facts** of the certificate -/ +theorem valid : GLab.Valid raw aux where + hn := rfl + tab := tab_ok + runA := runA + runB := runB + runF := GLab.Run.of_seg segF_ok + fin := fin_ok + ends := end_ok +theorem cen_dim (r : Nat) (hr : r ∈ raw.ret.map Prod.fst) : GLab.cdim (par.tab.get (st1.get r)) = 9 := + Nat.eq_of_beq_eq_true (List.all_eq_true.mp cen_ok r hr) +/-- price of the label half over ANY scalar half -/ +theorem lab_cost {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (φ : ℕ → ℝ) : + (valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg).cost φ + = rcost φ rA + (Fintype.card C : ℝ) * bcost φ 9 + rcost φ rB + rcost φ rF := by + obtain ⟨h1, h2, h3, h4⟩ := valid.lab_ranks S Ro cf hMA hMAi hMB hMBi reg hCc hreg + have h5 : ∀ k, bcost φ (((valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg).cen k).dim) = bcost φ 9 := + fun k => by rw [h4 k]; exact congrArg (bcost φ) (cen_dim _ (hreg k)) + rw [GX.Lab.cost, h1, h2, h3, Finset.sum_congr rfl (fun k _ => h5 k), Finset.sum_const, Finset.card_univ, nsmul_eq_mul] + rfl +/-- **the label half costs one invocation price** (`invPrice`, by rank, from the kernel counts) -/ +theorem lab_price {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (hC : Fintype.card C = 8) (φ : ℕ → ℝ) : + (valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg).cost φ = invPrice φ := by + rw [lab_cost S Ro cf hMA hMAi hMB hMBi reg hCc hreg φ, hC, ← inv_cost φ] + norm_num [bcost] +end GXD.E8 +#print axioms GXD.E8.valid +#print axioms GXD.E8.lab_price diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Price.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Price.lean new file mode 100644 index 0000000000..71b561645b --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8Price.lean @@ -0,0 +1,54 @@ +import Work.GCert.Data.Price +import Work.GCert.Data.Gen.E8Hist + +/-! +# (key: gx-data) gcert/1 certificate `E8` (h = 9): the price of one invocation + +GENERATED by checks/wht26/gx-data/py/gxgen.py from gcert1-e8-r783.json.gz. No `sorry`. +`rA_cost`, `rB_cost`, `rF_cost`: the price of the block rank lists of phase A, phase B and the final climbs +(lists `GXD.E8.rA / rB / rF`, counted by the kernel in `Gen.E8Hist`); +`inv_cost`: with the 8 scratch copies (8 * φ 9) the blocks of ONE invocation cost +`invPrice φ` = 2091 * φ 1 + 604 * φ 2 + 518 * φ 3 + 140 * φ 4 + 215 * φ 5 + 331 * φ 6 + 43 * φ 7 + 24 * φ 8 + 8 * φ 9; `inv_moves`: they stand for `R h + 2 v (h - 1) + cst = 9039` unit moves. +-/ + +namespace GXD.E8 +open GXD OAI.PowerSaving.CB + +/-- price of the blocks of phase A, from the kernel counts -/ +theorem rA_cost (φ : ℕ → ℝ) : rcost φ rA = 770 * φ 1 + 229 * φ 2 + 120 * φ 3 + 3 * φ 4 + 15 * φ 5 + 50 * φ 6 + 30 * φ 7 + 22 * φ 8 := by + rw [GXD.rcost_wsumK φ rA 8 rankBoundA] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, rankA0_ok, rankA1_ok, rankA2_ok, rankA3_ok, rankA4_ok, rankA5_ok, rankA6_ok, rankA7_ok, rankA8_ok] + norm_num [bcost] + +/-- price of the blocks of phase B, from the kernel counts -/ +theorem rB_cost (φ : ℕ → ℝ) : rcost φ rB = 867 * φ 1 + 301 * φ 2 + 287 * φ 3 + 109 * φ 4 + 170 * φ 5 + 203 * φ 6 + 13 * φ 7 + 2 * φ 8 := by + rw [GXD.rcost_wsumK φ rB 8 rankBoundB] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, rankB0_ok, rankB1_ok, rankB2_ok, rankB3_ok, rankB4_ok, rankB5_ok, rankB6_ok, rankB7_ok, rankB8_ok] + norm_num [bcost] + +/-- price of the blocks of the final climbs, from the kernel counts -/ +theorem rF_cost (φ : ℕ → ℝ) : rcost φ rF = 454 * φ 1 + 74 * φ 2 + 111 * φ 3 + 28 * φ 4 + 30 * φ 5 + 78 * φ 6 := by + rw [GXD.rcost_wsumK φ rF 8 rankBoundF] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, rankF0_ok, rankF1_ok, rankF2_ok, rankF3_ok, rankF4_ok, rankF5_ok, rankF6_ok, rankF7_ok, rankF8_ok] + norm_num [bcost] + +/-- price of the blocks of ONE invocation (x roles, y roles, slots, scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := 2091 * φ 1 + 604 * φ 2 + 518 * φ 3 + 140 * φ 4 + 215 * φ 5 + 331 * φ 6 + 43 * φ 7 + 24 * φ 8 + 8 * φ 9 + +/-- **Price of ONE invocation** in the shape of `GX.Lab.cost`: phase A, the scratch copies, phase B, final climbs. -/ +theorem inv_cost (φ : ℕ → ℝ) : rcost φ rA + (8 * φ 9) + rcost φ rB + rcost φ rF = invPrice φ := by + rw [rA_cost, rB_cost, rF_cost] + unfold invPrice + ring + +theorem inv_moves : invPrice (fun r => (r:ℝ)) = 783 * 9 + 2 * 120 * (9 - 1) + 72 := by + unfold invPrice + norm_num + +theorem inv_count : invPrice (fun _ => (1:ℝ)) = 3974 := by + unfold invPrice + norm_num + +end GXD.E8 +#print axioms GXD.E8.inv_cost +#print axioms GXD.E8.inv_moves diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8ScalOK.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8ScalOK.lean new file mode 100644 index 0000000000..0657e91b99 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/E8ScalOK.lean @@ -0,0 +1,15 @@ +import Work.GCert.Scalar.Main +import Work.GCert.Data.Gen.E8Scal0 +import Work.GCert.Data.Gen.E8YChk +/-! # (key: gx-data) gcert/1 certificate `E8` (h = 9): THE SCALAR HALF `scalOK : GS.ScalOK raw` +GENERATED by checks/wht26/gx-data/py/gxgen.py from gcert1-e8-r783.json.gz. No `sorry`. +Kernel checks `scal_ok` (1 source batches) and `ychk_ok`. -/ +namespace GXD.E8 +open GXD +theorem scalOK : GS.ScalOK raw where + hv := by decide + hs := fun t ht => + ⟨0, 120, Nat.zero_le t, Nat.lt_of_lt_of_le ht (by decide), GS.XRun.of_check scal0_ok⟩ + hyc := fun t ht => ⟨0, 120, Nat.zero_le t, Nat.lt_of_lt_of_le ht (by decide), GS.YRun.of_check ychk_ok⟩ +end GXD.E8 +#print axioms GXD.E8.scalOK diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8.lean new file mode 100644 index 0000000000..c8165c355b --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8.lean @@ -0,0 +1,12 @@ +import Work.GCert.Data.Gen.E8.S0 +/-! gcert/1 certificate `E8` (h = 9, v = 120 ports, R = 783 slots, N = 9039 unit moves): the record `raw : GXD.Raw`. +Source: gcert1-e8-r783.json.gz. Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +/-- the certificate -/ +noncomputable def raw : Raw := + { h := 9, v := 120, R := 783, N := 9039, cst := 72, ports := ports, frames := frames, start := start, + final := final, ret := ret, scat := scat, A := gA, B := gB, pairs := pairs, cuts := cuts, ext := ext, + obase := obase } +end GXD.E8 diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8/S0.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8/S0.lean new file mode 100644 index 0000000000..5069b78564 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8/S0.lean @@ -0,0 +1,128 @@ +import Work.GCert.Data.Raw +import Work.SharedSumChecker.Check +/-! gcert/1 certificate `E8` (h = 9, v = 120 ports, R = 783 slots, N = 9039 unit moves): data segment 0 of 1. +Source: gcert1-e8-r783.json.gz. Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +noncomputable def k0 : Co := ⟨false, 1, 1⟩ +noncomputable def k1 : Co := ⟨true, 1, 2⟩ +noncomputable def k2 : Co := ⟨true, 1, 1⟩ +noncomputable def k3 : Co := ⟨true, 2, 1⟩ +noncomputable def k4 : Co := ⟨false, 1, 2⟩ +noncomputable def k5 : Co := ⟨false, 2, 1⟩ +noncomputable def k6 : Co := ⟨false, 1, 3⟩ +noncomputable def k7 : Co := ⟨true, 1, 6⟩ +noncomputable def ports_0 : List (Nat) := [7, 11, 19, 35, 67, 131, 259, 13, 21, 37, 69, 133, 261, 25, 41, 73, 137, 265, 49, 81, 145, 273, 97, 161, 289, 193, 321, 385, 14, 22, 38, 70, 134, 262, 26, 42, 74, 138, 266, 50, 82, 146, 274, 98, 162, 290, 194, 322, 386, 28, 44, 76, 140, 268, 52, 84, 148, 276, 100, 164, 292, 196, 324, 388, 56, 88, 152, 280, 104, 168, 296, 200, 328, 392, 112, 176, 304, 208, 336, 400, 224, 352, 416, 448, 508, 506, 502, 494, 478, 446, 382, 254, 505, 501, 493, 477, 445, 381, 253, 499, 491, 475, 443, 379, 251, 487, 471, 439, 375, 247, 463, 431, 367, 239, 415, 351, 223, 319, 191, 127] +noncomputable def ports : List (Nat) := ports_0 +noncomputable def start_0 : List (Nat) := [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +noncomputable def start_1 : List (Nat) := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +noncomputable def start_2 : List (Nat) := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +noncomputable def start_3 : List (Nat) := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +noncomputable def start_4 : List (Nat) := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +noncomputable def start : List (Nat) := start_0 ++ (start_1 ++ (start_2 ++ (start_3 ++ (start_4)))) +noncomputable def final_0 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def final_1 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def final_2 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def final_3 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def final_4 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def final : List (Nat) := final_0 ++ (final_1 ++ (final_2 ++ (final_3 ++ (final_4)))) +noncomputable def ret_0 : List (Nat × Nat) := [(504, 1), (505, 1), (506, 1), (507, 1), (508, 1), (509, 1), (510, 1), (511, 1)] +noncomputable def ret : List (Nat × Nat) := ret_0 +noncomputable def ext_0 : List (Nat × Nat) := [] +noncomputable def ext : List (Nat × Nat) := ext_0 +noncomputable def scatRows_0 : List (List (Nat × Co)) := [[(0, k6), (1, k6), (2, k6), (3, k7), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k6), (2, k7), (3, k6), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k6), (2, k7), (3, k7), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k6), (2, k7), (3, k7), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k6), (1, k6), (2, k7), (3, k7), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k6), (1, k6), (2, k7), (3, k7), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k6), (1, k6), (2, k7), (3, k7), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k6), (3, k6), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k6), (3, k7), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k6), (3, k7), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k6), (3, k7), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k6), (1, k7), (2, k6), (3, k7), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k6), (1, k7), (2, k6), (3, k7), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k6), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k6), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k6), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k6), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k6), (1, k7), (2, k7), (3, k6), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k6), (5, k6), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k6), (5, k7), (6, k6), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k6), (5, k7), (6, k7), (7, k6)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k7), (5, k6), (6, k6), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k7), (5, k6), (6, k7), (7, k6)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k7), (5, k7), (6, k6), (7, k6)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k6), (1, k7), (2, k7), (3, k7), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k6), (2, k6), (3, k6), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k6), (3, k7), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k6), (3, k7), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k6), (3, k7), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k6), (2, k6), (3, k7), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k6), (2, k6), (3, k7), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k6), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k6), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k6), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k6), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k6), (2, k7), (3, k6), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k6), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k6), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k6), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k7), (5, k6), (6, k6), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k7), (5, k6), (6, k7), (7, k6)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k7), (5, k7), (6, k6), (7, k6)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k6), (2, k7), (3, k7), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k6), (3, k6), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k6), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k6), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k6), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k6), (3, k6), (4, k7), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k6), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k6), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k6), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k7), (5, k6), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k7), (5, k6), (6, k7), (7, k6)]] +noncomputable def scatRows_1 : List (List (Nat × Co)) := [[(0, k7), (1, k7), (2, k6), (3, k7), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k7), (5, k7), (6, k6), (7, k6)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k6), (3, k7), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k6), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k6), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k6), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k6), (5, k7), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k7), (5, k6), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k7), (5, k6), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k7), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k7), (5, k7), (6, k6), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k7), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k6), (4, k7), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k6), (5, k6), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k6), (5, k6), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k6), (5, k6), (6, k7), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k6), (5, k7), (6, k6), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k6), (5, k7), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k6), (5, k7), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k7), (5, k6), (6, k6), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k7), (5, k6), (6, k6), (7, k7)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k7), (5, k6), (6, k7), (7, k6)], [(0, k7), (1, k7), (2, k7), (3, k7), (4, k7), (5, k7), (6, k6), (7, k6)], [(0, k4), (1, k1)], [(0, k4), (2, k1)], [(0, k4), (3, k1)], [(0, k4), (4, k1)], [(0, k4), (5, k1)], [(0, k4), (6, k1)], [(0, k4), (7, k1)], [(0, k4)], [(1, k4), (2, k1)], [(1, k4), (3, k1)], [(1, k4), (4, k1)], [(1, k4), (5, k1)], [(1, k4), (6, k1)], [(1, k4), (7, k1)], [(1, k4)], [(2, k4), (3, k1)], [(2, k4), (4, k1)], [(2, k4), (5, k1)], [(2, k4), (6, k1)], [(2, k4), (7, k1)], [(2, k4)], [(3, k4), (4, k1)], [(3, k4), (5, k1)], [(3, k4), (6, k1)], [(3, k4), (7, k1)], [(3, k4)], [(4, k4), (5, k1)], [(4, k4), (6, k1)], [(4, k4), (7, k1)], [(4, k4)], [(5, k4), (6, k1)], [(5, k4), (7, k1)], [(5, k4)], [(6, k4), (7, k1)], [(6, k4)], [(7, k4)]] +noncomputable def scatRows : List (List (Nat × Co)) := scatRows_0 ++ (scatRows_1) +noncomputable def scat : Scat := .table scatRows +noncomputable def obase_0 : List (List Nat) := [[7, 8, 16, 32, 64, 128, 262, 259, 261], [11, 4, 16, 32, 64, 128, 266, 259, 265], [19, 4, 8, 32, 64, 128, 274, 259, 273], [35, 4, 8, 16, 64, 128, 290, 259, 289], [67, 4, 8, 16, 32, 128, 322, 259, 321], [131, 4, 8, 16, 32, 64, 386, 259, 385], [259, 4, 8, 16, 32, 64, 386, 131, 385], [13, 2, 16, 32, 64, 128, 268, 261, 265], [21, 2, 8, 32, 64, 128, 276, 261, 273], [37, 2, 8, 16, 64, 128, 292, 261, 289], [69, 2, 8, 16, 32, 128, 324, 261, 321], [133, 2, 8, 16, 32, 64, 388, 261, 385], [261, 2, 8, 16, 32, 64, 388, 133, 385], [25, 2, 4, 32, 64, 128, 280, 265, 273], [41, 2, 4, 16, 64, 128, 296, 265, 289], [73, 2, 4, 16, 32, 128, 328, 265, 321], [137, 2, 4, 16, 32, 64, 392, 265, 385], [265, 2, 4, 16, 32, 64, 392, 137, 385], [49, 2, 4, 8, 64, 128, 304, 273, 289], [81, 2, 4, 8, 32, 128, 336, 273, 321], [145, 2, 4, 8, 32, 64, 400, 273, 385], [273, 2, 4, 8, 32, 64, 400, 145, 385], [97, 2, 4, 8, 16, 128, 352, 289, 321], [161, 2, 4, 8, 16, 64, 416, 289, 385], [289, 2, 4, 8, 16, 64, 416, 161, 385], [193, 2, 4, 8, 16, 32, 448, 321, 385], [321, 2, 4, 8, 16, 32, 448, 193, 385], [385, 2, 4, 8, 16, 32, 448, 193, 321], [14, 1, 16, 32, 64, 128, 268, 262, 266], [22, 1, 8, 32, 64, 128, 276, 262, 274], [38, 1, 8, 16, 64, 128, 292, 262, 290], [70, 1, 8, 16, 32, 128, 324, 262, 322], [134, 1, 8, 16, 32, 64, 388, 262, 386], [262, 1, 8, 16, 32, 64, 388, 134, 386], [26, 1, 4, 32, 64, 128, 280, 266, 274], [42, 1, 4, 16, 64, 128, 296, 266, 290], [74, 1, 4, 16, 32, 128, 328, 266, 322], [138, 1, 4, 16, 32, 64, 392, 266, 386], [266, 1, 4, 16, 32, 64, 392, 138, 386], [50, 1, 4, 8, 64, 128, 304, 274, 290], [82, 1, 4, 8, 32, 128, 336, 274, 322], [146, 1, 4, 8, 32, 64, 400, 274, 386], [274, 1, 4, 8, 32, 64, 400, 146, 386], [98, 1, 4, 8, 16, 128, 352, 290, 322], [162, 1, 4, 8, 16, 64, 416, 290, 386], [290, 1, 4, 8, 16, 64, 416, 162, 386], [194, 1, 4, 8, 16, 32, 448, 322, 386], [322, 1, 4, 8, 16, 32, 448, 194, 386], [386, 1, 4, 8, 16, 32, 448, 194, 322], [28, 1, 2, 32, 64, 128, 280, 268, 276], [44, 1, 2, 16, 64, 128, 296, 268, 292], [76, 1, 2, 16, 32, 128, 328, 268, 324], [140, 1, 2, 16, 32, 64, 392, 268, 388], [268, 1, 2, 16, 32, 64, 392, 140, 388], [52, 1, 2, 8, 64, 128, 304, 276, 292], [84, 1, 2, 8, 32, 128, 336, 276, 324], [148, 1, 2, 8, 32, 64, 400, 276, 388], [276, 1, 2, 8, 32, 64, 400, 148, 388], [100, 1, 2, 8, 16, 128, 352, 292, 324], [164, 1, 2, 8, 16, 64, 416, 292, 388]] +noncomputable def obase_1 : List (List Nat) := [[292, 1, 2, 8, 16, 64, 416, 164, 388], [196, 1, 2, 8, 16, 32, 448, 324, 388], [324, 1, 2, 8, 16, 32, 448, 196, 388], [388, 1, 2, 8, 16, 32, 448, 196, 324], [56, 1, 2, 4, 64, 128, 304, 280, 296], [88, 1, 2, 4, 32, 128, 336, 280, 328], [152, 1, 2, 4, 32, 64, 400, 280, 392], [280, 1, 2, 4, 32, 64, 400, 152, 392], [104, 1, 2, 4, 16, 128, 352, 296, 328], [168, 1, 2, 4, 16, 64, 416, 296, 392], [296, 1, 2, 4, 16, 64, 416, 168, 392], [200, 1, 2, 4, 16, 32, 448, 328, 392], [328, 1, 2, 4, 16, 32, 448, 200, 392], [392, 1, 2, 4, 16, 32, 448, 200, 328], [112, 1, 2, 4, 8, 128, 352, 304, 336], [176, 1, 2, 4, 8, 64, 416, 304, 400], [304, 1, 2, 4, 8, 64, 416, 176, 400], [208, 1, 2, 4, 8, 32, 448, 336, 400], [336, 1, 2, 4, 8, 32, 448, 208, 400], [400, 1, 2, 4, 8, 32, 448, 208, 336], [224, 1, 2, 4, 8, 16, 448, 352, 416], [352, 1, 2, 4, 8, 16, 448, 224, 416], [416, 1, 2, 4, 8, 16, 448, 224, 352], [448, 1, 2, 4, 8, 16, 416, 224, 352], [508, 1, 506, 14, 22, 38, 70, 134, 262], [506, 1, 508, 14, 22, 38, 70, 134, 262], [502, 1, 508, 14, 26, 42, 74, 138, 266], [494, 1, 508, 22, 26, 50, 82, 146, 274], [478, 1, 508, 38, 42, 50, 98, 162, 290], [446, 1, 508, 70, 74, 82, 98, 194, 322], [382, 1, 508, 134, 138, 146, 162, 194, 386], [254, 1, 508, 262, 266, 274, 290, 322, 386], [505, 2, 508, 13, 21, 37, 69, 133, 261], [501, 2, 508, 13, 25, 41, 73, 137, 265], [493, 2, 508, 21, 25, 49, 81, 145, 273], [477, 2, 508, 37, 41, 49, 97, 161, 289], [445, 2, 508, 69, 73, 81, 97, 193, 321], [381, 2, 508, 133, 137, 145, 161, 193, 385], [253, 2, 508, 261, 265, 273, 289, 321, 385], [499, 4, 506, 11, 25, 41, 73, 137, 265], [491, 4, 506, 19, 25, 49, 81, 145, 273], [475, 4, 506, 35, 41, 49, 97, 161, 289], [443, 4, 506, 67, 73, 81, 97, 193, 321], [379, 4, 506, 131, 137, 145, 161, 193, 385], [251, 4, 506, 259, 265, 273, 289, 321, 385], [487, 8, 502, 19, 21, 49, 81, 145, 273], [471, 8, 502, 35, 37, 49, 97, 161, 289], [439, 8, 502, 67, 69, 81, 97, 193, 321], [375, 8, 502, 131, 133, 145, 161, 193, 385], [247, 8, 502, 259, 261, 273, 289, 321, 385], [463, 16, 494, 35, 37, 41, 97, 161, 289], [431, 16, 494, 67, 69, 73, 97, 193, 321], [367, 16, 494, 131, 133, 137, 161, 193, 385], [239, 16, 494, 259, 261, 265, 289, 321, 385], [415, 32, 478, 67, 69, 73, 81, 193, 321], [351, 32, 478, 131, 133, 137, 145, 193, 385], [223, 32, 478, 259, 261, 265, 273, 321, 385], [319, 64, 446, 131, 133, 137, 145, 161, 385], [191, 64, 446, 259, 261, 265, 273, 289, 385], [127, 128, 382, 259, 261, 265, 273, 289, 321]] +noncomputable def obase : List (List Nat) := obase_0 ++ (obase_1) +noncomputable def frames : List (List (List Nat)) := [] +noncomputable def seg0_0 : List (Gate) := [.inn 2 240 [(0, k0)], .out 3 1 [(242, k0), (243, k0)] [], .out 4 2 [(244, k0), (245, k0)] [], .out 5 3 [(247, k0), (248, k0)] [], .out 6 4 [(250, k0), (251, k0)] [], .out 7 5 [(252, k0), (253, k0)] [], .out 8 6 [(255, k0), (256, k0), (257, k0)] [], .out 9 7 [(258, k0), (259, k0)] [], .out 10 8 [(260, k0), (261, k0)] [], .out 11 9 [(262, k0), (263, k0)] [], .out 12 10 [(264, k0), (265, k0)] [], .out 13 11 [(266, k0), (267, k0)] [], .inn 14 268 [(12, k0)], .out 15 13 [(269, k0), (270, k0), (271, k0)] [], .out 16 14 [(273, k0), (274, k0)] [], .out 17 15 [(275, k0), (276, k0), (277, k0)] [], .out 18 16 [(279, k0), (280, k0)] [], .out 19 17 [(281, k0), (282, k0)] [], .out 20 18 [(283, k0), (284, k0)] [], .out 21 19 [(285, k0), (286, k0)] [], .out 22 20 [(287, k0), (288, k0), (349, k1)] [], .out 23 21 [(290, k0), (291, k0)] [], .out 24 22 [(292, k0), (293, k0), (294, k0)] [], .out 25 23 [(296, k0), (297, k0)] [], .out 26 24 [(298, k0), (299, k0)] [], .out 27 25 [(300, k0), (301, k0), (302, k0)] [], .out 28 26 [(303, k0), (304, k0), (305, k0)] [], .out 29 27 [(306, k0), (307, k0)] [], .out 30 28 [(308, k0), (309, k0)] [], .out 31 29 [(310, k0), (311, k0), (312, k0)] [], .out 32 30 [(314, k0), (315, k0)] [], .out 33 31 [(316, k0), (317, k0), (318, k0)] [], .out 34 32 [(320, k0), (321, k0)] [], .out 35 33 [(322, k0), (323, k0)] [], .out 36 34 [(324, k0), (325, k0)] [], .out 37 35 [(326, k0), (327, k0)] [], .out 37 35 [(327, k1), (328, k0)] [], .out 38 36 [(329, k0), (330, k0)] [], .out 39 37 [(331, k0), (333, k0)] [], .inn 40 334 [(38, k0)], .out 41 39 [(336, k0), (337, k0)] [], .out 42 40 [(338, k0), (339, k0), (340, k0)] [], .out 43 41 [(342, k0), (343, k0)] [], .out 44 42 [(289, k0), (344, k0)] [], .out 45 43 [(346, k0), (347, k0)] [], .out 46 44 [(348, k0), (350, k0)] [], .out 47 45 [(351, k0), (504, k0)] [], .out 48 46 [(352, k0), (353, k0)] [], .out 49 47 [(354, k0), (355, k0)] [], .out 50 48 [(356, k0), (505, k0)] [], .out 51 49 [(249, k2), (357, k0), (358, k0)] [], .out 52 50 [(246, k2), (359, k0), (360, k0)] [], .out 53 51 [(254, k2), (361, k0), (362, k0)] [], .out 54 52 [(363, k0), (364, k0)] [], .out 55 53 [(335, k0), (365, k0), (366, k0), (367, k0)] [], .out 56 54 [(369, k0), (370, k0)] [], .out 57 55 [(371, k0), (372, k0)] [], .out 58 56 [(373, k0), (374, k0)] [], .out 59 57 [(376, k0), (377, k0)] [], .out 60 58 [(378, k0), (379, k0), (380, k0)] [], .out 61 59 [(382, k0), (383, k0)] [], .out 62 60 [(375, k0), (384, k0)] [], .out 63 61 [(386, k0), (387, k0)] [], .out 64 62 [(389, k0), (390, k0)] [], .out 65 63 [(391, k0), (392, k0)] [], .out 66 64 [(388, k2), (394, k0), (395, k0), (771, k0)] [], .out 67 65 [(396, k0), (397, k0), (398, k0)] [], .out 68 66 [(400, k0), (401, k0)] [], .out 69 67 [(402, k0), (403, k0)] [], .out 70 68 [(404, k0), (405, k0)] [], .out 71 69 [(406, k0), (407, k0)] [], .out 71 69 [(407, k1), (408, k0)] [], .out 72 70 [(409, k0), (506, k0)] [], .out 73 71 [(410, k0), (411, k0)] [], .out 74 72 [(412, k0), (413, k0)] [], .out 75 73 [(393, k0), (414, k0), (507, k0)] [], .inn 76 416 [(74, k0)], .out 77 75 [(417, k0), (418, k0)] [], .out 78 76 [(419, k0), (420, k0), (421, k0), (700, k0)] [], .inn 79 423 [(77, k0)], .inn 80 424 [(78, k0)], .out 81 79 [(426, k0), (427, k0)] [], .inn 82 429 [(80, k0)], .out 83 81 [(430, k0), (431, k0)] [], .inn 84 432 [(82, k0)], .out 85 83 [(425, k0), (433, k0), (434, k0), (435, k0)] [], .out 86 84 [(436, k0), (437, k0)] [], .out 87 85 [(438, k0), (439, k0)] [], .out 88 86 [(440, k0), (441, k0)] [], .out 89 87 [(442, k0), (443, k0)] [], .out 90 88 [(444, k0), (445, k0)] [], .out 91 89 [(446, k0), (447, k0)] [], .out 92 90 [(448, k0), (449, k0)] [], .out 93 91 [(450, k0), (451, k0)] [], .out 94 92 [(452, k0), (453, k0)] [], .out 95 93 [(454, k0), (455, k0)] [], .out 96 94 [(456, k0), (457, k0)] [], .out 97 95 [(458, k0), (508, k0)] [], .out 98 96 [(459, k0), (460, k0)] [], .out 99 97 [(461, k0), (509, k0)] [], .out 100 98 [(462, k0), (463, k0), (693, k0), (839, k2)] [], .inn 101 465 [(99, k0)], .out 102 100 [(466, k0), (467, k0)] [], .out 103 101 [(468, k0), (469, k0)] [], .out 104 102 [(470, k0), (471, k0)] [], .out 105 103 [(472, k0), (473, k0)] [], .out 106 104 [(474, k0), (475, k0)] [], .out 107 105 [(476, k0), (477, k0)] [], .out 108 106 [(478, k0), (510, k0)] [], .out 109 107 [(479, k0), (480, k0)] [], .out 110 108 [(481, k0), (511, k0)] [], .out 111 109 [(482, k0), (483, k0)] [], .out 112 110 [(484, k0), (485, k0)] [], .out 113 111 [(486, k0), (487, k0)] [], .out 114 112 [(488, k0), (489, k0)] [], .out 115 113 [(490, k0), (491, k0)] [], .out 116 114 [(492, k0), (493, k0)] [], .out 117 115 [(494, k0), (495, k0)] [], .out 118 116 [(496, k0), (497, k0)] [], .out 119 117 [(498, k0), (499, k0)] [], .out 120 118 [(500, k0), (501, k0)] [], .out 121 119 [(502, k0), (503, k0)] [], .out 242 19 [(295, k1), (520, k0)] [], .inn 242 295 [(23, k0)], .out 242 23 [(295, k1), (520, k0)] [], .inn 243 303 [(27, k0)], .out 244 8 [(313, k1), (528, k0)] [], .inn 244 313 [(30, k0)], .out 244 30 [(313, k1), (528, k0)] [], .out 245 10 [(319, k1), (532, k0)] [], .inn 245 319 [(32, k0)], .out 245 32 [(319, k1), (532, k0)] [], .out 246 14 [(272, k0), (535, k0)] [], .out 246 34 [(272, k0), (535, k2)] [], .out 247 16 [(278, k0), (539, k0)] [], .out 247 36 [(278, k0), (539, k2)] [], .inn 248 289 [(21, k0)], .out 249 41 [(341, k0), (548, k0)] [], .out 249 43 [(341, k0), (548, k2)] [], .inn 250 299 [(45, k0)], .inn 251 355 [(48, k0)], .inn 252 567 [(12, k0)], .inn 253 375 [(57, k0)], .inn 254 368 [(54, k0)], .out 255 55 [(399, k1), (575, k0)] [], .inn 255 399 [(66, k0)], .out 255 66 [(399, k1), (575, k0)] [], .out 256 59 [(381, k0), (579, k0)] [], .out 256 68 [(381, k0), (579, k2)] [], .inn 257 403 [(70, k0)]] +noncomputable def seg0_1 : List (Gate) := [.inn 258 389 [(72, k0)], .inn 259 393 [(63, k0)], .inn 260 415 [(74, k0)], .inn 261 422 [(77, k0)], .inn 261 428 [(80, k0)], .inn 262 597 [(82, k0)], .out 263 89 [(604, k0), (605, k0), (779, k0)] [], .out 263 90 [(604, k0), (605, k0), (779, k0)] [], .out 264 87 [(610, k0), (611, k0)] [], .out 264 94 [(610, k0), (611, k0)] [], .inn 265 445 [(95, k0)], .inn 266 460 [(97, k0)], .out 267 0 [(241, k0), (694, k0)] [], .out 267 99 [(464, k0), (694, k0)] [], .out 268 100 [(623, k0), (624, k0)] [], .out 268 101 [(623, k0), (624, k0)] [], .inn 269 477 [(106, k0)], .out 270 102 [(629, k0), (630, k0)] [], .out 270 107 [(629, k0), (630, k0)] [], .inn 271 473 [(108, k0)], .inn 272 291 [(24, k0)], .inn 273 327 [(9, k1)], .inn 274 332 [(11, k1), (37, k0)], .inn 274 332 [(37, k1)], .inn 275 302 [(39, k2)], .inn 276 349 [(44, k0)], .inn 276 349 [(44, k1)], .out 277 18 [(656, k0), (657, k0)] [], .out 277 46 [(656, k2), (657, k2)] [], .inn 278 305 [(47, k0)], .inn 279 249 [(3, k0)], .inn 280 246 [(2, k0)], .inn 281 254 [(5, k0)], .out 282 4 [(664, k0), (665, k0)] [], .out 282 52 [(664, k2), (665, k2)] [], .inn 283 335 [(38, k0)], .inn 284 391 [(62, k0)], .out 285 61 [(388, k0), (771, k2)] [], .inn 286 377 [(67, k0)], .inn 287 407 [(56, k1)], .inn 288 370 [(71, k2)], .inn 289 425 [(78, k0)], .inn 290 443 [(88, k0)], .inn 291 447 [(96, k0)], .inn 292 471 [(103, k0)], .inn 293 467 [(105, k0)], .inn 294 335 [(86, k2)], .inn 295 692 [(6, k0), (33, k0), (93, k0)], .out 296 28 [(693, k0), (839, k2)] [], .out 296 84 [(693, k2), (839, k0)] [], .inn 297 694 [(104, k0)], .inn 298 425 [(114, k2)], .inn 299 700 [(81, k0), (115, k0)], .inn 300 542 [(38, k0)], .inn 301 594 [(78, k0)], .inn 302 771 [(54, k0), (71, k2)], .inn 303 779 [(26, k0), (27, k0)], .inn 304 839 [(25, k0), (39, k2)], .inn 47 345 [(504, k0)], .inn 305 345 [(42, k0)], .inn 1 504 [(1, k0), (2, k0), (3, k0), (5, k0), (7, k0), (13, k0), (15, k0), (22, k0), (42, k2), (45, k3), (47, k2), (48, k2), (53, k2), (57, k2), (62, k2), (63, k2), (67, k2), (70, k2), (72, k2), (73, k2), (79, k2), (83, k2), (86, k0), (88, k0)], .inn 72 385 [(506, k0)], .inn 306 385 [(60, k0)], .inn 1 504 [(60, k2)], .inn 1 506 [(7, k0), (17, k2), (21, k2), (24, k2), (29, k0), (31, k0), (42, k2), (45, k2), (47, k2), (48, k2), (49, k0), (50, k0), (51, k0), (58, k0), (67, k2), (70, k3), (72, k2), (73, k2), (79, k2), (83, k2), (103, k0)], .inn 307 240 [(242, k0)], .out 307 240 [(242, k1), (512, k0), (513, k0)] [], .inn 308 244 [(247, k0)], .out 308 244 [(247, k1), (514, k0), (515, k0)] [], .inn 309 250 [(252, k0)], .out 309 250 [(252, k1), (516, k0)] [], .inn 310 255 [(281, k0)], .out 310 255 [(281, k1), (517, k0)] [], .inn 311 255 [(85, k0)], .out 1 85 [(504, k0), (506, k2)] [], .inn 312 287 [(292, k0)], .out 312 287 [(292, k1), (518, k0)] [], .inn 313 287 [(19, k0), (23, k0)], .inn 1 504 [(19, k0), (23, k0)], .inn 312 519 [(292, k3)], .inn 314 292 [(41, k1), (43, k4)], .inn 242 521 [(295, k3)], .inn 315 283 [(300, k2)], .inn 315 300 [(283, k4)], .inn 315 522 [(300, k5)], .inn 243 523 [(303, k0)], .inn 316 258 [(308, k0)], .out 316 258 [(308, k1), (524, k0), (525, k0)] [], .inn 317 262 [(310, k0)], .out 317 262 [(310, k1), (526, k0)] [], .inn 318 262 [(8, k0), (30, k0)], .out 1 8 [(504, k0), (506, k0)] [], .inn 1 506 [(30, k0)], .inn 317 527 [(310, k3)], .inn 319 310 [(14, k1), (34, k4)], .inn 1 504 [(14, k0)], .inn 244 529 [(313, k3)], .inn 320 266 [(316, k0)], .out 320 266 [(316, k1), (530, k0)] [], .inn 321 266 [(10, k0), (32, k0)], .out 1 10 [(504, k0), (506, k0)] [], .inn 1 506 [(32, k0)], .inn 320 531 [(316, k3)], .inn 322 316 [(16, k1), (36, k4)], .inn 1 504 [(16, k0)], .inn 245 533 [(319, k3)], .inn 246 534 [(272, k0)], .inn 323 269 [(326, k0)], .out 323 269 [(326, k1), (536, k0)] [], .inn 323 537 [(326, k3)], .inn 247 538 [(278, k0)], .inn 324 275 [(331, k0)], .out 324 275 [(331, k1), (540, k0)] [], .inn 324 541 [(331, k3)], .inn 325 284 [(336, k0)], .out 325 284 [(336, k1), (543, k0)] [], .inn 248 544 [(289, k0)], .inn 326 544 [(87, k2), (94, k2)], .inn 1 504 [(87, k0)], .inn 248 545 [(289, k0)], .inn 327 298 [(344, k0)], .inn 327 344 [(298, k1)], .inn 327 546 [(344, k3)], .inn 249 547 [(341, k0)], .inn 328 338 [(348, k0)], .out 328 338 [(348, k1), (549, k0)] [], .inn 328 550 [(348, k3)], .inn 329 290 [(351, k0)], .inn 329 351 [(290, k1)], .inn 329 551 [(351, k3)], .out 250 299 [(552, k0), (553, k0)] [], .inn 330 301 [(352, k0)], .out 330 301 [(352, k1), (554, k0)] [], .inn 331 337 [(353, k2)], .inn 331 353 [(337, k4)], .inn 331 555 [(353, k5)], .inn 332 306 [(354, k0)], .inn 332 354 [(306, k1)], .inn 332 556 [(354, k3)], .inn 333 304 [(356, k0)], .inn 333 356 [(304, k1)], .inn 333 557 [(356, k3)], .out 251 355 [(558, k0), (559, k0)] [], .inn 334 245 [(357, k2)], .inn 334 357 [(245, k4)], .inn 334 560 [(357, k5)], .inn 335 248 [(359, k2)], .inn 335 359 [(248, k4)], .inn 335 561 [(359, k5)], .inn 336 358 [(360, k0)]] +noncomputable def seg0_2 : List (Gate) := [.out 336 358 [(360, k1), (562, k0)] [], .inn 337 562 [(77, k2), (80, k2)], .inn 336 563 [(358, k0)], .inn 338 251 [(361, k2)], .inn 338 361 [(251, k4)], .inn 338 564 [(361, k5)], .inn 339 253 [(363, k2)], .inn 339 363 [(253, k4)], .inn 339 565 [(363, k5)], .inn 340 362 [(364, k0)], .out 340 362 [(364, k1), (566, k0)] [], .inn 341 362 [(74, k2), (75, k2)], .inn 252 567 [(365, k0)], .inn 252 365 [(12, k2)], .inn 252 568 [(567, k0)], .inn 342 567 [(92, k2)], .inn 1 506 [(92, k2)], .inn 253 569 [(375, k0)], .inn 343 569 [(100, k0), (101, k0)], .inn 1 506 [(100, k0), (101, k0)], .inn 253 570 [(375, k0)], .inn 254 368 [(386, k2)], .inn 254 386 [(368, k4)], .inn 254 571 [(386, k5)], .inn 344 369 [(394, k0)], .out 344 369 [(394, k1), (572, k0)] [], .inn 345 373 [(396, k0)], .out 345 373 [(396, k1), (573, k0)] [], .inn 346 373 [(55, k0), (66, k0)], .inn 1 506 [(55, k0)], .inn 345 574 [(396, k3)], .inn 347 396 [(59, k1), (68, k4)], .inn 1 506 [(59, k0)], .inn 255 576 [(399, k3)], .inn 348 384 [(402, k0)], .inn 348 402 [(384, k1)], .inn 348 577 [(402, k3)], .inn 256 578 [(381, k0)], .inn 349 378 [(406, k0)], .out 349 378 [(406, k1), (580, k0)] [], .inn 349 581 [(406, k3)], .inn 350 376 [(409, k0)], .inn 350 409 [(376, k1)], .inn 350 582 [(409, k3)], .out 257 403 [(583, k0), (584, k0)] [], .inn 351 387 [(410, k0)], .out 351 387 [(410, k1), (585, k0)] [], .inn 352 395 [(411, k2)], .inn 352 411 [(395, k4)], .inn 352 586 [(411, k5)], .inn 258 587 [(389, k0)], .inn 353 587 [(102, k2), (107, k2)], .inn 1 506 [(102, k0)], .inn 258 588 [(389, k0)], .inn 354 392 [(412, k0)], .inn 354 412 [(392, k1)], .inn 354 589 [(412, k3)], .inn 355 390 [(414, k0)], .inn 355 414 [(390, k1)], .inn 355 590 [(414, k3)], .out 259 393 [(591, k0), (592, k0)] [], .inn 260 415 [(417, k0)], .out 260 415 [(417, k1), (593, k0)] [], .inn 356 420 [(426, k0)], .out 356 420 [(426, k1), (595, k0)] [], .inn 357 420 [(111, k0)], .inn 261 422 [(428, k0)], .out 261 422 [(428, k1), (596, k0)] [], .inn 262 597 [(434, k0)], .inn 262 434 [(82, k2)], .inn 262 598 [(597, k0)], .inn 358 597 [(112, k2)], .inn 359 259 [(436, k0)], .out 359 259 [(436, k1), (599, k0)] [], .inn 360 599 [(91, k0)], .out 1 91 [(504, k5), (506, k0)] [], .inn 361 323 [(438, k2)], .out 361 323 [(438, k4), (600, k0), (601, k0)] [], .inn 362 268 [(440, k0)], .out 362 268 [(440, k1), (602, k0), (603, k0)] [], .inn 363 603 [(6, k0), (33, k0), (93, k0)], .inn 1 504 [(33, k2)], .inn 1 506 [(6, k2)], .inn 364 334 [(452, k0)], .out 364 334 [(452, k1), (606, k0), (607, k0)] [], .inn 365 441 [(453, k2)], .inn 365 453 [(441, k4)], .inn 366 282 [(454, k2)], .out 366 282 [(454, k4), (608, k0), (609, k0)] [], .inn 367 444 [(456, k0)], .inn 367 456 [(444, k1)], .inn 367 612 [(456, k3)], .inn 368 442 [(458, k0)], .inn 368 458 [(442, k1)], .inn 368 613 [(458, k3)], .out 265 445 [(614, k0), (615, k0)] [], .inn 369 448 [(459, k0)], .inn 369 459 [(448, k1)], .inn 369 616 [(459, k3)], .inn 370 446 [(461, k0)], .inn 370 461 [(446, k1)], .inn 370 617 [(461, k3)], .out 266 460 [(618, k0), (619, k0)] [], .inn 267 241 [(464, k0)], .inn 267 464 [(241, k1)], .inn 371 243 [(465, k2)], .out 371 243 [(465, k4), (622, k0)] [], .inn 372 622 [(109, k0)], .out 1 109 [(504, k0), (506, k0)] [], .inn 373 468 [(476, k0)], .inn 373 476 [(468, k1)], .inn 373 625 [(476, k3)], .inn 374 466 [(478, k0)], .inn 374 478 [(466, k1)], .inn 374 626 [(478, k3)], .out 269 477 [(627, k0), (628, k0)] [], .inn 375 472 [(479, k0)], .inn 375 479 [(472, k1)], .inn 375 631 [(479, k3)], .inn 376 470 [(481, k0)], .inn 376 481 [(470, k1)], .inn 376 632 [(481, k3)], .out 271 473 [(633, k0), (634, k0)] [], .inn 377 423 [(484, k0)], .out 377 423 [(484, k1), (637, k0)] [], .inn 378 637 [(113, k0)], .out 1 113 [(504, k0), (506, k0)] [], .inn 379 429 [(485, k2)], .out 379 429 [(485, k4), (638, k0)] [], .inn 380 638 [(116, k0)], .out 1 116 [(504, k0), (506, k0)] [], .inn 381 431 [(486, k2)], .out 381 431 [(486, k4), (639, k0), (640, k0)] [], .inn 382 424 [(488, k0)], .out 382 424 [(488, k1), (641, k0), (642, k0)] [], .inn 383 642 [(76, k0), (81, k0), (115, k0)], .inn 1 504 [(76, k2), (81, k2)], .inn 1 506 [(76, k2), (81, k2)], .inn 384 432 [(492, k0)], .out 384 432 [(492, k1), (643, k0), (644, k0)] [], .inn 385 489 [(493, k2)], .inn 385 493 [(489, k4)], .inn 386 427 [(494, k2)], .out 386 427 [(494, k4), (645, k0), (646, k0)] [], .inn 387 416 [(498, k0)], .out 387 416 [(498, k1), (649, k0)] [], .inn 388 649 [(118, k0)], .out 1 118 [(504, k0), (506, k0)] [], .inn 389 418 [(499, k2)], .out 389 418 [(499, k4), (650, k0)] []] +noncomputable def seg0_3 : List (Gate) := [.inn 390 650 [(119, k0)], .out 1 119 [(504, k0), (506, k0)] [], .inn 391 263 [(270, k0)], .inn 391 270 [(263, k1)], .inn 392 260 [(273, k0)], .inn 392 273 [(260, k1)], .inn 393 267 [(276, k0)], .inn 393 276 [(267, k1)], .inn 394 264 [(279, k0)], .inn 394 279 [(264, k1)], .inn 272 653 [(291, k0)], .inn 395 271 [(311, k0)], .inn 395 311 [(271, k1)], .inn 396 274 [(314, k0)], .inn 396 314 [(274, k1)], .inn 397 274 [(9, k0), (35, k0)], .out 1 9 [(504, k0), (506, k0)] [], .inn 398 277 [(317, k0)], .inn 398 317 [(277, k1)], .inn 399 280 [(320, k0)], .inn 399 320 [(280, k1)], .inn 400 280 [(11, k0), (37, k0)], .out 1 11 [(504, k0), (506, k0)] [], .inn 401 261 [(324, k0)], .inn 401 324 [(261, k1)], .inn 402 315 [(325, k0)], .inn 402 325 [(315, k1)], .inn 403 312 [(328, k0)], .inn 403 328 [(312, k1)], .inn 404 265 [(329, k0)], .inn 404 329 [(265, k1)], .inn 405 321 [(330, k0)], .inn 405 330 [(321, k1)], .inn 406 318 [(333, k0)], .inn 406 333 [(318, k1)], .inn 275 654 [(302, k0)], .inn 407 302 [(18, k2), (46, k0)], .inn 1 504 [(18, k0)], .inn 408 288 [(339, k0)], .inn 408 339 [(288, k1)], .inn 409 293 [(340, k0)], .inn 409 340 [(293, k1)], .inn 410 285 [(342, k0)], .inn 410 342 [(285, k1)], .inn 411 296 [(343, k0)], .inn 411 343 [(296, k1)], .inn 412 296 [(20, k0), (44, k0)], .inn 1 504 [(20, k0)], .inn 413 286 [(346, k0)], .inn 413 346 [(286, k1)], .inn 414 297 [(347, k0)], .inn 414 347 [(297, k1)], .inn 415 294 [(350, k0)], .inn 415 350 [(294, k1)], .inn 305 655 [(345, k0)], .inn 278 658 [(305, k0)], .inn 416 307 [(505, k0)], .inn 1 505 [(1, k0), (2, k0), (3, k0), (5, k0), (17, k2), (21, k2), (24, k2), (29, k0), (30, k0), (31, k0), (32, k0), (34, k0), (35, k0), (36, k0), (37, k0), (40, k0), (41, k0), (43, k0), (44, k0), (46, k0), (48, k2), (53, k2), (57, k2), (60, k2), (62, k2), (63, k2), (67, k2), (70, k2), (72, k2), (73, k2), (76, k2), (79, k2), (81, k2), (83, k2), (91, k0), (92, k0), (93, k0), (94, k0), (95, k0), (96, k0), (97, k0), (109, k0), (113, k0), (116, k0), (118, k0), (119, k0)], .inn 416 659 [(307, k0)], .inn 279 660 [(249, k0)], .inn 280 661 [(246, k0)], .out 281 254 [(662, k0), (663, k0)] [], .inn 417 254 [(4, k0), (52, k2)], .out 1 4 [(504, k0), (505, k0)] [], .inn 1 506 [(52, k0)], .inn 418 374 [(379, k0)], .inn 418 379 [(374, k1)], .inn 419 371 [(382, k0)], .inn 419 382 [(371, k1)], .inn 284 666 [(391, k0)], .inn 285 667 [(388, k0)], .inn 420 388 [(0, k0), (99, k0), (104, k0)], .inn 1 504 [(0, k0), (104, k0)], .inn 1 505 [(0, k0), (104, k0)], .inn 1 506 [(0, k0), (99, k0), (104, k5)], .inn 421 380 [(397, k0)], .inn 421 397 [(380, k1)], .inn 422 383 [(400, k0)], .inn 422 400 [(383, k1)], .inn 423 383 [(56, k0), (69, k0)], .inn 1 506 [(56, k0)], .inn 286 668 [(377, k0)], .inn 424 372 [(404, k0)], .inn 424 404 [(372, k1)], .inn 425 401 [(405, k0)], .inn 425 405 [(401, k1)], .inn 426 398 [(408, k0)], .inn 426 408 [(398, k1)], .inn 306 669 [(385, k0)], .inn 288 670 [(370, k0)], .inn 427 413 [(507, k0)], .inn 1 507 [(1, k0), (6, k2), (7, k0), (13, k0), (14, k0), (15, k0), (16, k0), (21, k2), (24, k2), (33, k2), (34, k0), (35, k0), (36, k0), (37, k0), (42, k2), (45, k2), (47, k2), (48, k2), (49, k0), (50, k0), (51, k0), (52, k0), (57, k2), (60, k2), (62, k2), (63, k2), (65, k0), (66, k0), (68, k0), (69, k0), (73, k2), (76, k2), (79, k2), (81, k2), (83, k2), (86, k2), (91, k0), (93, k2), (99, k2), (104, k0), (105, k0), (106, k0), (107, k0), (108, k0), (109, k5), (113, k0), (116, k0), (118, k0), (119, k0)], .inn 427 671 [(413, k0)], .inn 290 672 [(443, k0)], .inn 428 457 [(508, k0)], .inn 1 508 [(2, k0), (6, k2), (8, k0), (13, k0), (17, k2), (18, k0), (19, k0), (20, k0), (24, k2), (29, k0), (33, k2), (34, k0), (40, k0), (41, k0), (45, k2), (47, k2), (48, k2), (49, k0), (53, k2), (55, k0), (56, k0), (60, k2), (62, k2), (63, k2), (65, k0), (66, k0), (70, k2), (72, k2), (73, k2), (74, k0), (75, k0), (77, k0), (81, k2), (83, k2), (87, k2), (91, k0), (94, k2), (95, k2), (100, k2), (104, k0), (105, k2), (109, k0), (110, k0), (111, k0), (112, k0), (113, k5), (116, k0), (118, k0), (119, k0)], .inn 428 673 [(457, k0)], .inn 291 674 [(447, k0)], .inn 429 449 [(509, k0)], .inn 1 509 [(3, k0), (6, k2), (9, k0), (14, k0), (17, k2), (18, k0), (21, k2), (22, k0), (23, k0), (30, k0), (33, k2), (35, k0), (42, k2), (43, k0), (44, k0), (47, k2), (48, k2), (50, k0), (53, k2), (57, k2), (58, k0), (59, k0), (62, k2), (63, k2), (67, k2), (68, k0), (69, k0), (72, k2), (73, k2), (74, k0), (75, k0), (79, k2), (80, k0), (83, k2), (88, k2), (91, k0), (95, k2), (97, k2), (101, k2), (104, k0), (106, k2), (109, k0), (110, k2), (113, k0), (114, k0), (115, k0), (116, k5), (118, k0), (119, k0)], .inn 429 675 [(449, k0)], .inn 292 676 [(471, k0)], .inn 293 677 [(467, k0)], .inn 430 469 [(510, k0)], .inn 1 510 [(4, k0), (6, k2), (10, k0), (15, k0), (17, k2), (19, k0), (21, k2), (22, k0), (24, k2), (31, k0), (33, k2), (36, k0), (40, k0), (42, k2), (43, k0), (45, k2), (46, k0), (48, k2), (51, k0), (53, k2), (55, k0), (57, k2), (58, k0), (60, k2), (63, k2), (65, k0), (67, k2), (68, k0), (70, k2), (73, k2), (74, k0), (76, k2), (77, k0), (79, k2), (80, k0), (91, k0), (96, k2), (102, k2), (104, k0), (106, k2), (107, k2), (109, k0), (111, k2), (113, k0), (114, k2), (116, k0), (117, k0), (118, k5), (119, k0)], .inn 430 678 [(469, k0)], .inn 431 480 [(511, k0)], .inn 1 511 [(5, k0), (6, k2), (11, k0), (16, k0), (17, k2), (20, k0), (21, k2), (23, k0), (24, k2), (32, k0), (33, k2), (37, k0), (41, k0), (42, k2), (44, k0), (45, k2), (46, k0), (47, k2), (52, k0), (53, k2), (56, k0), (57, k2), (59, k0), (60, k2), (62, k2), (66, k0), (67, k2), (69, k0), (70, k2), (72, k2), (75, k0), (76, k2), (77, k0), (80, k0), (81, k2), (91, k0), (97, k2), (103, k2), (104, k0), (108, k3), (109, k0), (112, k2), (113, k0), (115, k2), (116, k0), (117, k2), (118, k0), (119, k5)], .inn 431 679 [(480, k0)], .inn 432 309 [(437, k2)], .out 432 309 [(437, k4), (451, k2)] [], .out 432 451 [(309, k4), (680, k0)] [], .inn 433 463 [(259, k2)], .out 433 463 [(259, k4), (681, k0)] [], .inn 434 475 [(243, k2)], .out 434 475 [(243, k4), (682, k0)] [], .inn 435 483 [(241, k2)], .out 435 483 [(241, k4), (683, k0)] [], .inn 436 491 [(429, k2)], .out 436 491 [(429, k4), (684, k0)] [], .inn 437 497 [(423, k2)], .out 437 497 [(423, k4), (685, k0)] [], .inn 438 501 [(418, k2)], .out 438 501 [(418, k4), (686, k0)] [], .inn 439 503 [(416, k2)], .out 439 503 [(416, k4), (687, k0)] [], .inn 311 688 [(255, k0)], .inn 294 689 [(335, k2)], .inn 360 690 [(599, k0)], .inn 342 691 [(567, k2)], .inn 372 695 [(622, k0)], .inn 357 696 [(420, k0)], .inn 358 697 [(597, k2)], .inn 378 698 [(637, k0)], .inn 298 699 [(425, k2)], .inn 380 701 [(638, k0)], .inn 388 702 [(649, k0)], .inn 390 703 [(650, k0)], .inn 440 322 [(366, k0)], .out 440 322 [(366, k1), (517, k0)] [], .out 440 517 [(322, k1), (704, k0)] [], .inn 441 517 [(12, k0)], .out 1 12 [(505, k2), (507, k2), (508, k2), (509, k2), (510, k2), (511, k2)] [], .inn 440 281 [(366, k0)], .inn 300 542 [(256, k0)], .inn 300 256 [(38, k2)], .inn 441 517 [(38, k0)], .out 1 38 [(504, k2), (506, k2), (508, k2), (509, k2), (510, k2), (511, k2)] [], .inn 300 542 [(568, k0)], .inn 300 568 [(542, k1)]] +noncomputable def seg0_4 : List (Gate) := [.inn 300 256 [(365, k2)], .inn 442 430 [(433, k0)], .out 442 430 [(433, k1), (595, k0)] [], .out 442 595 [(430, k1), (705, k0)] [], .inn 443 595 [(82, k0)], .out 1 82 [(504, k2), (505, k2), (506, k2), (507, k2), (508, k2), (510, k2)] [], .inn 442 426 [(433, k0)], .inn 301 594 [(419, k0)], .inn 301 419 [(78, k2)], .inn 443 595 [(78, k0)], .out 1 78 [(504, k2), (505, k2), (506, k2), (507, k2), (509, k2), (511, k2)] [], .inn 301 594 [(598, k0)], .inn 301 598 [(594, k1)], .inn 444 268 [(334, k2)], .out 444 268 [(334, k4), (706, k0), (707, k0)] [], .inn 445 323 [(282, k2)], .out 445 323 [(282, k4), (708, k0), (709, k0)] [], .inn 446 424 [(432, k2)], .out 446 424 [(432, k4), (710, k0), (711, k0)] [], .inn 447 431 [(427, k2)], .out 447 431 [(427, k4), (712, k0), (713, k0)] [], .inn 448 263 [(260, k0)], .inn 448 714 [(263, k0)], .inn 449 267 [(264, k0)], .inn 449 715 [(267, k0)], .inn 313 716 [(287, k0)], .inn 318 717 [(262, k0)], .inn 450 311 [(314, k0)], .inn 450 718 [(311, k3)], .inn 321 719 [(266, k0)], .inn 451 317 [(320, k0)], .inn 451 720 [(317, k3)], .inn 452 271 [(261, k0)], .inn 452 721 [(271, k0)], .inn 319 722 [(310, k3)], .inn 453 270 [(325, k0)], .inn 453 723 [(270, k3)], .inn 454 528 [(535, k2)], .inn 454 535 [(528, k4)], .inn 454 313 [(272, k1)], .inn 454 272 [(313, k0)], .inn 455 273 [(328, k0)], .inn 455 724 [(273, k3)], .inn 456 529 [(537, k0)], .inn 456 725 [(529, k0)], .inn 397 726 [(274, k0)], .inn 457 324 [(327, k0)], .inn 457 727 [(324, k3)], .inn 458 534 [(536, k0)], .inn 458 728 [(534, k0)], .inn 459 315 [(312, k0)], .inn 459 729 [(315, k0)], .inn 460 729 [(25, k2), (28, k0), (39, k0), (84, k2), (98, k0)], .inn 1 504 [(25, k0), (84, k0), (98, k0)], .inn 1 505 [(28, k0), (39, k0), (84, k2), (98, k5)], .inn 1 506 [(28, k0), (98, k0)], .inn 1 507 [(28, k0), (98, k0)], .inn 1 508 [(39, k0), (98, k0)], .inn 1 509 [(39, k0), (98, k0)], .inn 1 510 [(25, k0), (98, k0)], .inn 1 511 [(25, k0), (98, k0)], .inn 461 277 [(265, k0)], .inn 461 730 [(277, k0)], .inn 322 731 [(316, k3)], .inn 462 276 [(330, k0)], .inn 462 732 [(276, k3)], .inn 463 319 [(278, k1)], .inn 463 278 [(319, k0)], .inn 464 279 [(333, k0)], .inn 464 733 [(279, k3)], .inn 465 533 [(541, k0)], .inn 465 734 [(533, k0)], .inn 400 735 [(280, k0)], .inn 466 329 [(332, k0)], .inn 466 736 [(329, k3)], .inn 467 538 [(540, k0)], .inn 467 737 [(538, k0)], .inn 468 321 [(318, k0)], .inn 468 738 [(321, k0)], .inn 469 258 [(284, k2)], .inn 469 739 [(258, k0)], .inn 470 288 [(285, k0)], .inn 470 740 [(288, k0)], .inn 471 340 [(343, k0)], .inn 471 741 [(340, k3)], .inn 472 293 [(286, k0)], .inn 472 742 [(293, k0)], .inn 473 339 [(347, k0)], .inn 473 743 [(339, k3)], .inn 314 744 [(292, k3)], .inn 474 295 [(341, k1)], .inn 474 341 [(295, k0)], .inn 474 520 [(548, k2)], .inn 474 548 [(520, k4)], .inn 475 348 [(518, k4)], .inn 475 518 [(348, k2)], .inn 476 521 [(550, k0)], .inn 476 745 [(521, k0)], .inn 477 342 [(350, k0)], .inn 477 746 [(342, k3)], .inn 412 747 [(296, k0)], .inn 478 346 [(349, k0)], .inn 478 748 [(346, k3)], .inn 479 297 [(294, k0)], .inn 479 749 [(297, k0)], .inn 480 547 [(549, k0)], .inn 480 750 [(547, k0)], .inn 481 289 [(299, k0)], .out 481 289 [(299, k1), (751, k0)] [], .inn 482 524 [(301, k0)], .inn 482 301 [(524, k1)], .inn 482 752 [(301, k3)], .inn 407 753 [(302, k0)], .inn 483 302 [(54, k2), (61, k0), (64, k2), (71, k0)], .inn 1 506 [(54, k0), (61, k0)], .inn 1 507 [(64, k0), (71, k0)], .inn 1 508 [(54, k0), (64, k0)], .inn 1 509 [(54, k0), (64, k0)], .inn 1 510 [(61, k0), (71, k0)], .inn 1 511 [(61, k0), (71, k0)], .inn 484 303 [(355, k0)], .out 484 303 [(355, k1), (754, k0)] [], .inn 485 244 [(358, k2)], .inn 417 755 [(254, k0)], .inn 486 374 [(371, k0)], .inn 486 756 [(374, k0)], .inn 487 240 [(369, k2)], .inn 487 757 [(240, k0)], .inn 346 758 [(373, k0)], .inn 488 397 [(400, k0)], .inn 488 759 [(397, k3)], .inn 489 380 [(372, k0)], .inn 489 760 [(380, k0)], .inn 347 761 [(396, k3)], .inn 490 379 [(405, k0)], .inn 490 762 [(379, k3)], .inn 491 382 [(408, k0)], .inn 491 763 [(382, k3)], .inn 492 576 [(581, k0)], .inn 492 764 [(576, k0)], .inn 423 765 [(383, k0)], .inn 493 404 [(407, k0)], .inn 493 766 [(404, k3)], .inn 494 578 [(580, k0)], .inn 494 767 [(578, k0)], .inn 495 401 [(398, k0)], .inn 495 768 [(401, k0)], .inn 496 375 [(403, k0)], .out 496 375 [(403, k1), (769, k0)] [], .inn 497 512 [(387, k0)]] +noncomputable def seg0_5 : List (Gate) := [.inn 497 387 [(512, k1)], .inn 497 770 [(387, k3)], .inn 498 389 [(393, k0)], .out 498 389 [(393, k1), (772, k0)] [], .inn 499 250 [(415, k0)], .inn 499 415 [(250, k1)], .inn 499 773 [(415, k3)], .inn 341 774 [(362, k0)], .inn 500 514 [(422, k0)], .inn 500 422 [(514, k1)], .inn 500 775 [(422, k3)], .inn 337 776 [(562, k0)], .inn 501 291 [(443, k0)], .inn 501 777 [(291, k0)], .inn 502 291 [(26, k0), (27, k0), (89, k0), (90, k0)], .inn 1 504 [(89, k0), (90, k0)], .inn 1 505 [(26, k2), (27, k2)], .inn 1 506 [(26, k2), (27, k2)], .inn 1 507 [(26, k2), (27, k2)], .inn 1 508 [(26, k2), (27, k2)], .inn 1 509 [(26, k2), (27, k2)], .inn 1 510 [(27, k2), (89, k2)], .inn 1 511 [(26, k2), (90, k2)]] +noncomputable def seg0 : List (Gate) := seg0_0 ++ (seg0_1 ++ (seg0_2 ++ (seg0_3 ++ (seg0_4 ++ (seg0_5))))) +noncomputable def rs0_0 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def rs0_1 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 3, 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 1, 1, 1, 8, 8, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 8, 7, 7, 7, 7, 7, 7, 8, 8, 8, 6, 7, 1, 1, 1, 7, 8, 8, 7, 7, 8, 8, 8, 8, 8, 8, 7, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 6, 1, 1, 2, 1, 1, 1, 6, 6, 2, 1, 1] +noncomputable def rs0_2 : List (Nat) := [1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 6, 6, 2, 1, 1, 1, 6, 2, 1, 1, 2, 1, 1, 1, 6, 6, 2, 1, 1, 1, 6, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 6, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 6, 2, 1, 1, 1, 6, 6, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 6, 2, 1, 1, 1, 6, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 6, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 6, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 5, 5, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 6, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2] +noncomputable def rs0_3 : List (Nat) := [2, 2, 1, 1, 2, 1, 2, 6, 1, 1, 2, 1, 2, 6, 1, 1, 2, 2, 1, 1, 2, 2, 2, 3, 1, 1, 5, 5, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 6, 1, 1, 2, 1, 2, 6, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 6, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 6, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 7, 6, 6, 6, 6, 8, 6, 6, 6, 6, 5, 6, 7, 7, 7, 2, 2, 2, 2, 2, 1, 1, 1, 6, 6, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 5, 5, 5, 1, 1, 1, 1, 1, 1, 2, 6, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 7, 8, 6, 6, 6, 7, 7, 6, 7, 2, 2, 1, 1, 7, 6, 6, 6, 8, 6, 6, 2, 2, 1, 1, 7, 6, 6, 5, 2, 2, 2, 1, 1, 7, 8, 2, 1, 1, 7, 2, 2, 2, 2, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2] +noncomputable def rs0_4 : List (Nat) := [1, 3, 1, 2, 5, 1, 2, 1, 5, 1, 1, 2, 2, 1, 3, 1, 2, 5, 1, 2, 1, 5, 1, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 3, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 2, 3, 2, 3, 5, 3, 3, 3, 3, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 3, 3, 4, 5, 3, 3, 3, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3] +noncomputable def rs0 : List (Nat) := rs0_0 ++ (rs0_1 ++ (rs0_2 ++ (rs0_3 ++ (rs0_4)))) +noncomputable def seg1_0 : List (Gate) := [.inn 503 345 [(672, k2)], .inn 503 778 [(345, k0)], .inn 504 558 [(604, k2)], .inn 504 780 [(558, k0)], .inn 326 781 [(544, k0)], .inn 505 552 [(610, k0)], .inn 505 782 [(552, k0)], .inn 506 344 [(444, k1)], .inn 506 444 [(344, k0)], .inn 507 351 [(612, k1)], .inn 507 783 [(351, k3)], .inn 508 546 [(458, k3)], .inn 508 784 [(546, k0)], .inn 509 545 [(445, k0)], .inn 509 785 [(545, k0)], .inn 510 553 [(614, k2)], .inn 510 786 [(553, k0)], .inn 511 653 [(457, k2)], .inn 511 787 [(653, k0)], .inn 512 655 [(673, k0)], .inn 512 788 [(655, k0)], .inn 513 611 [(615, k0)], .out 513 611 [(615, k1), (789, k0)] [], .inn 514 305 [(447, k2)], .inn 515 307 [(674, k0)], .inn 515 790 [(307, k0)], .inn 516 459 [(306, k4)], .inn 516 306 [(459, k2)], .inn 517 356 [(616, k1)], .inn 517 791 [(356, k3)], .inn 518 556 [(461, k3)], .inn 518 792 [(556, k0)], .inn 519 557 [(446, k0)], .inn 519 446 [(557, k1)], .inn 520 658 [(449, k0)], .inn 520 793 [(658, k0)], .inn 521 659 [(675, k2)], .inn 521 794 [(659, k0)], .inn 522 523 [(460, k2)], .inn 522 795 [(523, k0)], .inn 523 559 [(618, k0)], .inn 523 796 [(559, k0)], .inn 524 605 [(619, k0)], .out 524 605 [(619, k1), (797, k0)] [], .inn 343 801 [(569, k0)], .inn 525 583 [(623, k2)], .inn 525 802 [(583, k0)], .inn 526 391 [(471, k0)], .inn 526 803 [(391, k0)], .inn 527 413 [(676, k2)], .inn 527 804 [(413, k0)], .inn 528 377 [(467, k2)], .inn 528 805 [(377, k0)], .inn 529 385 [(677, k0)], .inn 529 806 [(385, k0)], .inn 530 476 [(384, k4)], .inn 530 384 [(476, k2)], .inn 531 409 [(625, k1)], .inn 531 807 [(409, k3)], .inn 532 577 [(478, k3)], .inn 532 808 [(577, k0)], .inn 533 582 [(466, k0)], .inn 533 466 [(582, k1)], .inn 533 376 [(626, k2)], .inn 533 626 [(376, k4)], .inn 534 668 [(469, k0)], .inn 534 809 [(668, k0)], .inn 535 669 [(678, k2)], .inn 535 810 [(669, k0)], .inn 536 570 [(477, k2)], .inn 536 811 [(570, k0)], .inn 537 584 [(627, k0)], .inn 537 812 [(584, k0)], .inn 538 624 [(628, k0)], .out 538 624 [(628, k1), (813, k0)] [], .inn 353 814 [(587, k0)], .inn 539 591 [(629, k0)], .inn 539 815 [(591, k0)], .inn 540 412 [(472, k1)], .inn 540 472 [(412, k0)], .inn 541 414 [(631, k1)], .inn 541 816 [(414, k3)], .inn 542 589 [(481, k3)], .inn 542 817 [(589, k0)], .inn 543 590 [(470, k0)], .inn 543 470 [(590, k1)], .inn 544 588 [(473, k0)], .inn 544 818 [(588, k0)], .inn 545 592 [(633, k2)], .inn 545 819 [(592, k0)], .inn 546 666 [(480, k2)], .inn 546 820 [(666, k0)], .inn 547 671 [(679, k0)], .inn 547 821 [(671, k0)], .inn 548 630 [(634, k0)], .out 548 630 [(634, k1), (822, k0)] [], .inn 549 439 [(455, k2)], .inn 549 455 [(439, k4)], .inn 550 487 [(495, k2)], .inn 550 495 [(487, k4)], .inn 441 865 [(517, k0)], .inn 443 866 [(595, k0)], .inn 551 255 [(602, k0)], .inn 552 600 [(335, k0)], .inn 552 832 [(600, k0)], .inn 553 654 [(599, k0)], .inn 554 656 [(690, k0)], .inn 555 688 [(606, k0)], .inn 555 834 [(688, k0)], .inn 556 601 [(567, k0)], .inn 363 835 [(603, k0)], .inn 557 689 [(608, k2)], .inn 557 836 [(689, k0)], .inn 558 607 [(692, k0)], .inn 558 837 [(607, k0)], .inn 559 691 [(609, k2)], .inn 559 838 [(691, k0)], .inn 560 657 [(693, k2)], .inn 560 840 [(657, k0)], .inn 420 843 [(388, k0)], .inn 561 370 [(694, k0)], .inn 561 844 [(370, k0)], .inn 562 667 [(622, k2)], .inn 562 845 [(667, k0)], .inn 563 670 [(695, k2)], .inn 563 846 [(670, k0)], .inn 564 420 [(641, k0)], .inn 564 848 [(420, k0)], .inn 565 639 [(597, k0)], .inn 565 849 [(639, k0)], .inn 566 249 [(637, k2)], .inn 567 246 [(698, k0)], .inn 568 696 [(643, k0)], .inn 568 851 [(696, k0)], .inn 569 640 [(425, k0)], .inn 383 852 [(642, k0)], .inn 570 697 [(645, k2)], .inn 570 853 [(697, k0)], .inn 571 644 [(700, k0)], .inn 571 854 [(644, k0)], .inn 572 699 [(646, k2)], .inn 572 855 [(699, k0)], .inn 573 660 [(638, k0)], .inn 573 857 [(660, k0)], .inn 574 661 [(701, k2)], .inn 574 858 [(661, k0)], .inn 575 662 [(649, k2)], .inn 575 859 [(662, k0)], .inn 576 664 [(702, k0)], .inn 576 860 [(664, k0)]] +noncomputable def seg1_1 : List (Gate) := [.inn 577 663 [(650, k0)], .inn 577 863 [(663, k0)], .inn 578 665 [(703, k2)], .inn 578 864 [(665, k0)], .inn 579 542 [(439, k2)], .inn 579 439 [(542, k4)], .inn 580 594 [(487, k2)], .inn 580 487 [(594, k4)], .inn 581 424 [(431, k0)], .inn 581 431 [(424, k1)], .inn 582 311 [(317, k0)], .out 582 311 [(868, k3), (869, k3)] [], .inn 583 324 [(329, k0)], .out 583 324 [(870, k3), (871, k3)] [], .inn 584 292 [(379, k0)], .out 584 292 [(879, k3), (880, k3)] [], .inn 585 521 [(382, k3)], .inn 585 881 [(521, k0)], .inn 586 387 [(422, k0)], .out 586 387 [(888, k3), (889, k3)] [], .inn 587 263 [(558, k2)], .inn 587 891 [(263, k0)], .inn 588 748 [(783, k0)], .inn 588 899 [(748, k0)], .inn 589 741 [(784, k0)], .out 589 741 [(901, k0), (902, k0)] [], .inn 590 773 [(789, k0)], .out 590 773 [(906, k0), (907, k0)] [], .inn 591 380 [(307, k2)], .inn 591 908 [(380, k0)], .inn 592 734 [(356, k3)], .inn 593 731 [(556, k0)], .out 593 731 [(910, k0), (911, k0)] [], .inn 594 383 [(658, k2)], .out 594 383 [(913, k0), (914, k0)] [], .inn 595 315 [(523, k2)], .out 595 315 [(915, k0), (916, k0)] [], .inn 596 266 [(583, k2)], .inn 596 923 [(266, k0)], .inn 597 288 [(385, k2)], .inn 597 926 [(288, k0)], .inn 598 724 [(409, k3)], .inn 598 928 [(724, k0)], .inn 599 766 [(807, k0)], .inn 600 723 [(577, k0)], .out 600 723 [(929, k0), (930, k0)] [], .inn 601 297 [(668, k2)], .out 601 297 [(932, k0), (933, k0)] [], .inn 602 538 [(570, k2)], .out 602 538 [(935, k0), (936, k0)] [], .inn 603 764 [(816, k0)], .inn 604 761 [(817, k0)], .out 604 761 [(942, k0), (943, k0)] [], .inn 605 752 [(630, k0)], .out 605 752 [(947, k0), (948, k0)] [], .inn 606 287 [(600, k2)], .inn 607 374 [(688, k2)], .inn 608 401 [(603, k2)], .inn 609 547 [(691, k0)], .inn 610 607 [(788, k0)], .inn 611 837 [(796, k0)], .inn 460 970 [(729, k0)], .inn 612 738 [(657, k2)], .inn 612 971 [(738, k0)], .inn 613 787 [(840, k0)], .inn 614 795 [(839, k0)], .inn 615 719 [(388, k0)], .inn 615 974 [(719, k0)], .inn 616 717 [(370, k0)], .inn 616 975 [(717, k0)], .inn 617 802 [(843, k2)], .inn 617 976 [(802, k0)], .inn 618 804 [(844, k2)], .inn 618 977 [(804, k0)], .inn 619 689 [(812, k2)], .inn 620 836 [(821, k2)], .inn 621 728 [(667, k2)], .inn 621 978 [(728, k0)], .inn 622 737 [(670, k2)], .inn 622 979 [(737, k0)], .inn 623 811 [(846, k0)], .inn 623 981 [(811, k0)], .inn 624 820 [(845, k0)], .inn 624 982 [(820, k0)], .inn 625 271 [(639, k2)], .inn 625 983 [(271, k0)], .inn 626 781 [(420, k0)], .inn 627 805 [(848, k0)], .inn 628 277 [(696, k2)], .inn 628 986 [(277, k0)], .inn 629 280 [(642, k2)], .inn 629 987 [(280, k0)], .inn 630 794 [(697, k2)], .inn 630 988 [(794, k0)], .inn 631 819 [(853, k2)], .inn 631 989 [(819, k0)], .inn 632 274 [(699, k0)], .inn 632 990 [(274, k0)], .inn 633 786 [(644, k0)], .inn 633 991 [(786, k0)], .inn 634 810 [(854, k0)], .inn 634 992 [(810, k0)], .inn 635 749 [(660, k0)], .inn 635 994 [(749, k0)], .inn 636 767 [(661, k2)], .inn 636 995 [(767, k0)], .inn 637 785 [(858, k0)], .inn 638 809 [(857, k2)], .inn 639 742 [(664, k0)], .inn 639 996 [(742, k0)], .inn 640 760 [(662, k2)], .inn 640 997 [(760, k0)], .inn 641 790 [(859, k0)], .inn 641 999 [(790, k0)], .inn 642 815 [(860, k2)], .inn 642 1000 [(815, k0)], .inn 643 747 [(663, k0)], .inn 643 1002 [(747, k0)], .inn 644 765 [(665, k2)], .inn 644 1003 [(765, k0)], .inn 645 793 [(864, k0)], .inn 645 1004 [(793, k0)], .inn 646 818 [(863, k2)], .inn 646 1005 [(818, k0)], .inn 647 720 [(709, k2)], .inn 647 896 [(720, k0)], .inn 648 276 [(396, k0)], .inn 648 878 [(276, k3)], .inn 649 267 [(345, k2)], .inn 649 890 [(267, k0)], .inn 650 746 [(791, k0)], .inn 650 909 [(746, k0)], .inn 651 743 [(792, k0)], .inn 651 912 [(743, k0)], .inn 652 293 [(591, k2)], .inn 652 939 [(293, k0)], .inn 653 770 [(605, k0)], .inn 653 917 [(770, k0)], .inn 654 763 [(711, k0)], .inn 654 955 [(763, k0)], .inn 655 762 [(713, k2)], .inn 655 957 [(762, k0)], .inn 656 240 [(415, k3)], .inn 656 886 [(240, k0)], .inn 657 757 [(611, k0)], .inn 657 905 [(757, k0)], .inn 658 270 [(397, k0)], .inn 658 877 [(270, k3)], .inn 659 316 [(339, k0)], .inn 659 873 [(316, k3)]] +noncomputable def seg1_2 : List (Gate) := [.inn 660 722 [(546, k0)], .inn 660 900 [(722, k0)], .inn 661 373 [(552, k2)], .inn 661 897 [(373, k0)], .inn 662 725 [(351, k3)], .inn 662 898 [(725, k0)], .inn 663 718 [(708, k2)], .inn 663 895 [(718, k0)], .inn 664 736 [(707, k0)], .inn 664 894 [(736, k0)], .inn 483 884 [(302, k0)], .inn 665 733 [(414, k3)], .inn 666 759 [(808, k0)], .inn 666 931 [(759, k0)], .inn 667 262 [(413, k2)], .inn 667 924 [(262, k0)], .inn 668 732 [(589, k0)], .inn 668 941 [(732, k0)], .inn 669 310 [(340, k0)], .inn 669 872 [(310, k3)], .inn 670 776 [(822, k0)], .inn 670 949 [(776, k0)], .inn 671 744 [(712, k2)], .inn 671 956 [(744, k0)], .inn 672 745 [(710, k0)], .inn 672 954 [(745, k0)], .inn 673 273 [(404, k0)], .inn 673 883 [(273, k3)], .inn 674 655 [(559, k0)], .inn 674 919 [(655, k0)], .inn 675 296 [(588, k2)], .inn 675 944 [(296, k0)], .inn 676 727 [(706, k0)], .inn 676 893 [(727, k0)], .inn 677 739 [(624, k0)], .inn 677 937 [(739, k0)], .inn 678 553 [(669, k0)], .inn 678 934 [(553, k0)], .inn 679 279 [(576, k1)], .inn 679 882 [(279, k3)], .inn 680 569 [(391, k0)], .inn 680 925 [(569, k0)], .inn 681 578 [(545, k2)], .inn 681 903 [(578, k0)], .inn 682 301 [(562, k1)], .inn 682 887 [(301, k3)], .inn 683 775 [(797, k0)], .inn 683 918 [(775, k0)], .inn 684 544 [(377, k0)], .inn 684 927 [(544, k0)], .inn 685 584 [(671, k0)], .inn 685 950 [(584, k0)], .inn 686 529 [(346, k3)], .inn 686 875 [(529, k0)], .inn 687 533 [(342, k3)], .inn 687 874 [(533, k0)], .inn 688 321 [(653, k2)], .inn 688 904 [(321, k0)], .inn 689 258 [(362, k0)], .inn 689 885 [(258, k0)], .inn 690 774 [(813, k0)], .inn 690 938 [(774, k0)], .inn 502 892 [(291, k0)], .inn 691 659 [(592, k0)], .inn 691 945 [(659, k0)], .inn 692 534 [(666, k2)], .inn 692 946 [(534, k0)], .inn 693 331 [(530, k4)], .inn 693 530 [(331, k2)], .inn 693 746 [(802, k0)], .inn 693 802 [(746, k1)], .inn 694 532 [(539, k2)], .inn 694 539 [(532, k4)], .inn 694 743 [(976, k0)], .inn 694 976 [(743, k1)], .inn 695 741 [(977, k0)], .inn 695 977 [(741, k1)], .inn 696 909 [(811, k0)], .inn 696 811 [(909, k1)], .inn 697 531 [(275, k0)], .inn 697 275 [(531, k1)], .inn 697 912 [(981, k0)], .inn 697 981 [(912, k1)], .inn 698 527 [(269, k0)], .inn 698 269 [(527, k1)], .inn 698 901 [(982, k0)], .inn 698 982 [(901, k1)], .inn 699 723 [(999, k2)], .inn 699 999 [(723, k4)], .inn 700 725 [(815, k0)], .inn 700 815 [(725, k1)], .inn 701 722 [(1000, k0)], .inn 701 1000 [(722, k1)], .inn 702 929 [(1004, k2)], .inn 702 1004 [(929, k4)], .inn 703 898 [(818, k0)], .inn 703 818 [(898, k1)], .inn 704 900 [(1005, k0)], .inn 704 1005 [(900, k1)], .inn 705 971 [(995, k2)], .inn 705 995 [(971, k4)], .inn 706 974 [(749, k0)], .inn 706 749 [(974, k1)], .inn 707 979 [(994, k0)], .inn 707 994 [(979, k1)], .inn 708 729 [(997, k2)], .inn 708 997 [(729, k4)], .inn 709 717 [(742, k0)], .inn 709 742 [(717, k1)], .inn 710 728 [(996, k0)], .inn 710 996 [(728, k1)], .inn 711 970 [(1003, k2)], .inn 711 1003 [(970, k4)], .inn 712 975 [(747, k0)], .inn 712 747 [(975, k1)], .inn 713 978 [(1002, k0)], .inn 713 1002 [(978, k1)], .inn 714 326 [(526, k4)], .inn 714 526 [(326, k2)], .inn 715 899 [(820, k0)], .inn 715 820 [(899, k1)], .inn 716 406 [(573, k4)], .inn 716 573 [(406, k2)], .inn 717 575 [(579, k2)], .inn 717 579 [(575, k4)], .inn 718 399 [(381, k1)], .inn 718 381 [(399, k0)], .inn 719 574 [(378, k0)], .inn 719 378 [(574, k1)], .inn 720 928 [(793, k2)], .inn 720 793 [(928, k4)], .inn 721 519 [(338, k0)], .inn 721 338 [(519, k1)], .inn 722 248 [(684, k0)], .inn 722 684 [(248, k1)], .inn 723 253 [(686, k0)], .inn 723 686 [(253, k1)], .inn 724 251 [(503, k0)], .inn 724 503 [(251, k1)], .inn 725 245 [(497, k0)], .inn 725 497 [(245, k1)], .inn 726 337 [(680, k0)], .inn 726 680 [(337, k1)], .inn 727 395 [(682, k0)], .inn 727 682 [(395, k1)], .inn 728 368 [(483, k0)], .inn 728 483 [(368, k1)], .inn 729 283 [(463, k0)], .inn 729 463 [(283, k1)], .inn 730 321 [(949, k2)]] +noncomputable def seg1_3 : List (Gate) := [.inn 730 949 [(321, k4)], .inn 731 1021 [(276, k3), (301, k5)], .inn 731 276 [(301, k0)], .inn 732 267 [(776, k0)], .inn 732 776 [(267, k1)], .inn 733 919 [(950, k0)], .inn 733 950 [(919, k1)], .inn 734 291 [(569, k0)], .inn 734 569 [(291, k1)], .inn 735 897 [(752, k2)], .inn 735 752 [(897, k4)], .inn 736 705 [(489, k2)], .inn 736 489 [(705, k4)], .inn 737 310 [(240, k4)], .inn 737 240 [(310, k2)], .inn 738 551 [(442, k0)], .inn 738 442 [(551, k1)], .inn 738 529 [(886, k2)], .inn 738 886 [(529, k4)], .inn 739 892 [(584, k0)], .inn 739 584 [(892, k1)], .inn 740 908 [(739, k2)], .inn 740 739 [(908, k4)], .inn 741 757 [(293, k2)], .inn 741 293 [(757, k4)], .inn 742 917 [(297, k2)], .inn 742 297 [(917, k4)], .inn 743 704 [(441, k2)], .inn 743 441 [(704, k4)], .inn 744 268 [(323, k0)], .inn 744 323 [(268, k1)], .inn 744 1020 [(311, k3), (324, k5)], .inn 744 311 [(324, k0)], .inn 745 402 [(468, k1)], .inn 745 468 [(402, k0)], .inn 745 270 [(258, k4)], .inn 745 258 [(270, k2)], .inn 746 773 [(262, k0)], .inn 746 262 [(773, k1)], .inn 747 279 [(887, k4)], .inn 747 887 [(279, k2)], .inn 748 881 [(884, k0)], .inn 748 884 [(881, k1)], .inn 749 879 [(302, k0)], .inn 749 302 [(879, k1)], .inn 750 390 [(632, k2)], .inn 750 632 [(390, k4)], .inn 751 290 [(613, k2)], .inn 751 613 [(290, k4)], .inn 752 913 [(937, k2)], .inn 752 937 [(913, k4)], .inn 753 273 [(885, k4)], .inn 753 885 [(273, k2)], .inn 754 304 [(617, k2)], .inn 754 617 [(304, k4)], .inn 755 905 [(296, k2)], .inn 755 296 [(905, k4)], .inn 756 927 [(659, k2)], .inn 756 659 [(927, k4)], .inn 757 934 [(945, k2)], .inn 757 945 [(934, k4)], .inn 758 456 [(298, k4)], .inn 758 298 [(456, k2)], .inn 759 354 [(448, k1)], .inn 759 448 [(354, k0)], .inn 759 1022 [(316, k3), (387, k5)], .inn 759 316 [(387, k0)], .inn 760 479 [(392, k4)], .inn 760 392 [(479, k2)], .inn 761 533 [(888, k2)], .inn 761 888 [(533, k4)], .inn 762 906 [(534, k0)], .inn 762 534 [(906, k1)], .inn 763 918 [(538, k0)], .inn 763 538 [(918, k1)], .inn 764 655 [(925, k0)], .inn 764 925 [(655, k1)], .inn 765 315 [(938, k2)], .inn 765 938 [(315, k4)], .inn 766 903 [(947, k2)], .inn 766 947 [(903, k4)], .inn 128 438 [(454, k0)], .inn 175 440 [(452, k0)], .inn 198 486 [(494, k0)], .inn 205 488 [(492, k0)], .inn 236 419 [(434, k2)], .inn 549 257 [(455, k5)], .inn 550 421 [(495, k5)], .inn 93 127 [(450, k1)], .inn 100 148 [(462, k1)], .inn 767 450 [(462, k0)], .out 767 450 [(462, k1), (620, k0), (621, k0)] [], .inn 768 525 [(450, k0)], .inn 768 798 [(525, k0)], .inn 769 543 [(620, k0)], .out 769 543 [(620, k1), (799, k0)] [], .inn 770 554 [(621, k0)], .inn 770 800 [(554, k0)], .inn 771 389 [(543, k2)], .out 771 389 [(921, k0), (922, k0)] [], .inn 772 595 [(798, k2)], .inn 772 1007 [(595, k0)], .inn 773 922 [(948, k2)], .inn 773 948 [(922, k4)], .inn 774 375 [(554, k2)], .inn 774 920 [(375, k0)], .inn 775 578 [(921, k0)], .inn 775 921 [(578, k1)], .inn 776 373 [(389, k0)], .inn 776 389 [(373, k1)], .inn 777 383 [(920, k0)], .inn 777 920 [(383, k1)], .inn 106 120 [(474, k1)], .inn 111 121 [(482, k1)], .inn 778 474 [(482, k0)], .out 778 474 [(482, k1), (635, k0), (636, k0)] [], .inn 779 513 [(474, k0)], .inn 779 823 [(513, k0)], .inn 780 572 [(635, k0)], .out 780 572 [(635, k1), (824, k0)] [], .inn 781 585 [(636, k0)], .inn 781 825 [(585, k0)], .inn 782 866 [(823, k2)], .inn 782 1011 [(866, k0)], .inn 783 525 [(513, k0)], .inn 783 953 [(525, k0)], .inn 784 303 [(572, k2)], .inn 784 951 [(303, k0)], .inn 785 289 [(585, k2)], .inn 785 952 [(289, k0)], .inn 786 932 [(951, k2)], .inn 786 951 [(932, k4)], .inn 787 939 [(289, k2)], .inn 787 289 [(939, k4)], .inn 788 926 [(303, k2)], .inn 788 303 [(926, k4)], .inn 789 880 [(525, k2)], .inn 789 525 [(880, k4)], .inn 790 944 [(952, k2)], .inn 790 952 [(944, k4)], .inn 115 197 [(490, k1)], .inn 118 200 [(496, k1)], .inn 791 490 [(496, k0)], .out 791 490 [(496, k1), (647, k0), (648, k0)] [], .inn 792 515 [(490, k0)], .inn 792 826 [(515, k0)], .inn 793 563 [(647, k0)], .out 793 563 [(647, k1), (827, k0)] [], .inn 794 596 [(648, k0)], .inn 794 828 [(596, k0)]] +noncomputable def seg1_4 : List (Gate) := [.inn 795 824 [(827, k0)], .out 795 824 [(961, k0), (962, k0)] [], .inn 796 517 [(828, k2)], .inn 796 1015 [(517, k0)], .inn 797 772 [(515, k2)], .inn 797 959 [(772, k0)], .inn 798 799 [(826, k0)], .inn 798 960 [(799, k0)], .inn 799 754 [(563, k2)], .inn 799 958 [(754, k0)], .inn 800 986 [(517, k2)], .inn 800 517 [(986, k4)], .inn 801 987 [(1015, k2)], .inn 801 1015 [(987, k4)], .inn 802 890 [(772, k2)], .inn 802 772 [(890, k4)], .inn 803 889 [(962, k0)], .inn 803 962 [(889, k1)], .inn 804 923 [(754, k2)], .inn 804 754 [(923, k4)], .inn 750 878 [(799, k2)], .inn 750 799 [(878, k4)], .inn 754 873 [(824, k0)], .inn 754 824 [(873, k1)], .inn 760 882 [(960, k2)], .inn 760 960 [(882, k4)], .inn 805 874 [(961, k0)], .inn 805 961 [(874, k1)], .inn 806 935 [(958, k2)], .inn 806 958 [(935, k4)], .inn 807 904 [(959, k2)], .inn 807 959 [(904, k4)], .inn 120 194 [(500, k1)], .inn 121 195 [(502, k1)], .inn 808 500 [(502, k0)], .out 808 500 [(502, k1), (651, k0), (652, k0)] [], .inn 809 516 [(500, k0)], .inn 809 829 [(516, k0)], .inn 810 566 [(651, k0)], .out 810 566 [(651, k1), (830, k0)] [], .inn 811 593 [(652, k0)], .inn 811 831 [(593, k0)], .inn 812 751 [(566, k2)], .out 812 751 [(963, k0), (964, k0)] [], .inn 813 865 [(831, k2)], .inn 813 1019 [(865, k0)], .inn 814 907 [(751, k2)], .inn 814 751 [(907, k4)], .inn 815 800 [(829, k0)], .inn 815 966 [(800, k0)], .inn 816 769 [(516, k2)], .inn 816 965 [(769, k0)], .inn 817 596 [(593, k0)], .inn 818 825 [(830, k0)], .inn 818 967 [(825, k0)], .inn 819 983 [(865, k0)], .inn 819 865 [(983, k1)], .inn 820 990 [(1019, k0)], .inn 820 1019 [(990, k1)], .inn 821 946 [(964, k2)], .inn 821 964 [(946, k4)], .inn 822 891 [(769, k2)], .inn 822 769 [(891, k4)], .inn 823 924 [(963, k2)], .inn 823 963 [(924, k4)], .inn 751 872 [(825, k0)], .inn 751 825 [(872, k1)], .inn 824 877 [(800, k2)], .inn 824 800 [(877, k4)], .inn 758 875 [(967, k0)], .inn 758 967 [(875, k1)], .inn 825 883 [(966, k2)], .inn 825 966 [(883, k4)], .inn 826 915 [(965, k2)], .inn 826 965 [(915, k4)], .inn 315 211 [(300, k2)], .inn 827 300 [(451, k4)], .inn 827 833 [(300, k5)], .inn 828 716 [(300, k5)], .inn 829 832 [(833, k2)], .inn 829 1006 [(832, k0)], .inn 830 832 [(763, k0)], .inn 830 763 [(832, k1)], .inn 831 1006 [(762, k0)], .inn 831 762 [(1006, k1)], .inn 331 218 [(353, k2)], .inn 832 353 [(681, k4)], .inn 832 841 [(353, k5)], .inn 833 750 [(353, k5)], .inn 833 972 [(750, k0)], .inn 834 838 [(841, k0)], .inn 834 1008 [(838, k0)], .inn 835 838 [(955, k0)], .inn 835 955 [(838, k1)], .inn 721 1008 [(957, k0)], .inn 721 957 [(1008, k1)], .inn 334 233 [(357, k2)], .inn 836 357 [(491, k4)], .inn 836 850 [(357, k5)], .inn 837 721 [(357, k5)], .inn 838 849 [(850, k2)], .inn 838 1012 [(849, k0)], .inn 839 736 [(849, k0)], .inn 839 849 [(736, k1)], .inn 840 720 [(1012, k0)], .inn 840 1012 [(720, k1)], .inn 335 236 [(359, k2)], .inn 841 359 [(685, k4)], .inn 841 856 [(359, k5)], .inn 842 726 [(359, k5)], .inn 842 993 [(726, k0)], .inn 843 855 [(856, k0)], .inn 843 1016 [(855, k0)], .inn 844 894 [(855, k2)], .inn 844 855 [(894, k4)], .inn 845 896 [(1016, k2)], .inn 845 1016 [(896, k4)], .inn 338 238 [(361, k2)], .inn 846 361 [(501, k4)], .inn 846 861 [(361, k5)], .inn 847 730 [(361, k5)], .inn 847 998 [(730, k0)], .inn 848 851 [(861, k2)], .inn 848 1017 [(851, k0)], .inn 849 727 [(851, k0)], .inn 849 851 [(727, k1)], .inn 850 718 [(1017, k0)], .inn 850 1017 [(718, k1)], .inn 851 726 [(998, k0)], .inn 851 998 [(726, k1)], .inn 339 239 [(363, k2)], .inn 852 363 [(687, k4)], .inn 852 862 [(363, k5)], .inn 853 735 [(363, k5)], .inn 853 1001 [(735, k0)], .inn 854 852 [(862, k2)], .inn 854 1018 [(852, k0)], .inn 855 893 [(852, k0)], .inn 855 852 [(893, k1)], .inn 856 895 [(1018, k0)], .inn 856 1018 [(895, k1)], .inn 857 993 [(1001, k0)], .inn 857 1001 [(993, k1)], .inn 254 224 [(386, k2)], .inn 858 386 [(475, k4)], .inn 858 842 [(386, k5)], .inn 859 756 [(386, k5)], .inn 859 973 [(756, k0)], .inn 860 834 [(842, k2)], .inn 860 1009 [(834, k0)]] +noncomputable def seg1_5 : List (Gate) := [.inn 861 750 [(973, k2)], .inn 861 973 [(750, k4)], .inn 862 834 [(745, k2)], .inn 862 745 [(834, k4)], .inn 863 1009 [(744, k2)], .inn 863 744 [(1009, k4)], .inn 352 229 [(411, k2)], .inn 864 411 [(683, k4)], .inn 864 847 [(411, k5)], .inn 865 768 [(411, k5)], .inn 865 980 [(768, k0)], .inn 866 835 [(847, k2)], .inn 866 1010 [(835, k0)], .inn 867 972 [(980, k2)], .inn 867 980 [(972, k4)], .inn 868 835 [(954, k2)], .inn 868 954 [(835, k4)], .inn 869 1010 [(956, k2)], .inn 869 956 [(1010, k4)], .out 365 453 [(205, k2), (213, k2)] [], .out 385 493 [(231, k2), (235, k2)] [], .inn 870 493 [(421, k4)], .inn 870 435 [(493, k3)], .inn 870 867 [(435, k0)], .inn 871 753 [(435, k0)], .inn 871 1013 [(753, k0)], .inn 872 771 [(867, k2)], .inn 872 1014 [(771, k0)], .out 485 358 [(124, k4), (125, k4), (171, k1), (172, k1)] [], .inn 485 358 [(244, k0)], .inn 873 244 [(254, k0)], .inn 873 876 [(244, k0)], .inn 874 868 [(244, k2)], .inn 874 244 [(868, k4)], .inn 875 870 [(876, k2)], .inn 875 876 [(870, k4)], .inn 492 157 [(581, k1)], .out 514 447 [(182, k4), (192, k4), (222, k1), (227, k1)] [], .inn 514 447 [(305, k0)], .inn 876 305 [(587, k0)], .inn 876 940 [(305, k0)], .inn 877 544 [(305, k2)], .inn 877 305 [(544, k4)], .inn 878 553 [(940, k2)], .inn 878 940 [(553, k4)], .inn 517 164 [(616, k1)], .out 549 257 [(122, k1), (169, k4)] [], .inn 879 453 [(257, k4)], .inn 879 367 [(453, k3)], .out 551 602 [(141, k4), (144, k4), (207, k4), (208, k4)] [], .inn 551 602 [(255, k0)], .inn 880 255 [(777, k0)], .inn 881 602 [(779, k0)], .out 553 599 [(130, k4), (131, k4), (135, k4), (136, k4)] [], .inn 553 599 [(654, k0)], .inn 882 715 [(654, k0)], .inn 882 968 [(715, k0)], .inn 883 968 [(767, k2)], .inn 883 767 [(968, k4)], .out 553 599 [(131, k1), (135, k1)] [], .inn 884 778 [(599, k2)], .inn 884 599 [(778, k0)], .inn 885 599 [(761, k0)], .inn 885 761 [(599, k1)], .out 554 690 [(128, k4), (129, k4), (133, k4), (134, k4)] [], .inn 554 690 [(656, k0)], .inn 886 714 [(656, k0)], .inn 886 969 [(714, k0)], .inn 887 714 [(760, k2)], .inn 887 760 [(714, k4)], .inn 888 969 [(765, k2)], .inn 888 765 [(969, k4)], .out 554 690 [(129, k1), (133, k1)] [], .inn 889 780 [(690, k2)], .inn 889 690 [(780, k0)], .inn 890 690 [(759, k0)], .inn 890 759 [(690, k1)], .out 556 567 [(177, k1), (180, k1), (220, k1), (221, k1)] [], .inn 556 567 [(601, k2)], .inn 891 601 [(801, k0)], .inn 892 567 [(803, k2)], .out 566 637 [(175, k1), (176, k1), (185, k1), (186, k1)] [], .inn 566 637 [(249, k0)], .inn 893 758 [(249, k2)], .inn 893 985 [(758, k0)], .inn 894 715 [(758, k2)], .inn 894 758 [(715, k4)], .inn 895 738 [(985, k2)], .inn 895 985 [(738, k4)], .out 566 637 [(176, k1), (185, k1)] [], .inn 896 782 [(637, k0)], .inn 896 637 [(782, k0)], .inn 717 732 [(637, k2)], .inn 717 637 [(732, k4)], .out 567 698 [(139, k4), (140, k4), (160, k4), (161, k4)] [], .inn 567 698 [(246, k0)], .inn 897 740 [(246, k0)], .inn 897 984 [(740, k0)], .inn 898 719 [(740, k0)], .inn 898 740 [(719, k1)], .inn 899 737 [(984, k0)], .inn 899 984 [(737, k1)], .out 567 698 [(140, k1), (160, k1)] [], .inn 900 806 [(698, k2)], .inn 900 698 [(806, k0)], .inn 901 731 [(698, k0)], .inn 901 698 [(731, k1)], .out 569 425 [(146, k1), (167, k1), (209, k4), (216, k4)] [], .inn 569 425 [(640, k2)], .inn 902 447 [(640, k0)], .out 569 425 [(167, k1), (216, k4)] [], .inn 903 814 [(425, k2)], .inn 903 425 [(814, k2)], .out 879 257 [(123, k1), (170, k4)] [], .inn 879 257 [(367, k0)], .inn 904 358 [(367, k2)], .out 879 257 [(123, k4), (170, k1)] [], .inn 905 755 [(257, k2)], .inn 905 257 [(755, k0)], .inn 722 755 [(271, k0)], .inn 722 271 [(755, k1)], .inn 725 257 [(274, k0)], .inn 725 274 [(257, k1)], .out 585 550 [(198, k4), (202, k1)] [], .inn 585 550 [(521, k0)], .inn 906 292 [(521, k4)], .inn 906 521 [(292, k2)], .inn 736 550 [(953, k2)], .inn 736 953 [(550, k4)], .inn 587 203 [(558, k1)], .inn 587 558 [(263, k0)], .inn 907 263 [(774, k0)], .inn 907 774 [(263, k1)], .inn 587 203 [(558, k4)], .inn 588 204 [(783, k4)], .inn 588 783 [(748, k0)], .inn 714 748 [(804, k0)], .inn 714 804 [(748, k1)], .inn 588 204 [(783, k1)], .inn 591 126 [(307, k1)], .inn 591 307 [(380, k0)], .inn 908 380 [(375, k0)], .inn 908 375 [(380, k1)], .inn 591 126 [(307, k4)], .inn 592 142 [(616, k4)], .inn 592 616 [(734, k0)], .inn 592 237 [(541, k4)], .inn 592 541 [(734, k0)], .inn 909 734 [(806, k0)], .inn 909 806 [(734, k1)]] +noncomputable def seg1_6 : List (Gate) := [.inn 592 237 [(541, k1)], .inn 596 196 [(583, k1)], .inn 596 583 [(266, k0)], .inn 910 775 [(266, k0)], .inn 910 266 [(775, k1)], .inn 596 196 [(583, k4)], .inn 597 173 [(385, k1)], .inn 597 385 [(288, k0)], .inn 911 770 [(288, k2)], .inn 911 288 [(770, k4)], .inn 597 173 [(385, k4)], .inn 598 230 [(625, k4)], .inn 598 625 [(724, k0)], .inn 912 724 [(790, k2)], .inn 912 790 [(724, k4)], .inn 598 230 [(625, k1)], .out 599 807 [(149, k4), (155, k1)] [], .inn 599 807 [(766, k0)], .inn 913 780 [(766, k0)], .inn 913 766 [(780, k1)], .inn 603 151 [(581, k4)], .inn 603 581 [(764, k0)], .inn 603 219 [(816, k4)], .inn 603 816 [(764, k0)], .inn 914 778 [(764, k0)], .inn 914 764 [(778, k1)], .inn 603 219 [(816, k1)], .out 606 600 [(138, k4), (145, k4)] [], .inn 606 600 [(287, k0)], .inn 915 287 [(866, k2)], .inn 915 866 [(287, k4)], .inn 726 600 [(771, k0)], .inn 726 771 [(600, k1)], .out 607 688 [(174, k4), (181, k4)] [], .inn 607 688 [(374, k0)], .inn 916 374 [(595, k0)], .inn 916 595 [(374, k1)], .inn 727 688 [(753, k0)], .inn 727 753 [(688, k1)], .out 608 603 [(184, k4), (191, k4)] [], .inn 608 603 [(401, k0)], .inn 917 401 [(1007, k0)], .inn 917 1007 [(401, k1)], .inn 728 603 [(1013, k0)], .inn 728 1013 [(603, k1)], .out 609 691 [(159, k4), (166, k4)] [], .inn 609 691 [(547, k0)], .inn 918 547 [(1011, k2)], .inn 918 1011 [(547, k4)], .inn 729 691 [(1014, k2)], .inn 729 1014 [(691, k4)], .out 610 788 [(168, k4), (217, k4)] [], .inn 610 788 [(607, k0)], .inn 919 607 [(425, k0)], .inn 919 425 [(607, k1)], .inn 920 788 [(989, k2)], .inn 920 989 [(788, k4)], .out 611 796 [(165, k4), (215, k4)] [], .inn 611 796 [(837, k0)], .inn 921 796 [(992, k0)], .inn 921 992 [(796, k1)], .out 613 840 [(152, k1), (156, k1)] [], .inn 613 840 [(787, k0)], .inn 922 787 [(581, k2)], .inn 922 581 [(787, k4)], .inn 923 840 [(942, k2)], .inn 923 942 [(840, k4)], .out 614 839 [(150, k1), (154, k1)] [], .inn 614 839 [(795, k0)], .inn 924 795 [(807, k2)], .inn 924 807 [(795, k4)], .inn 925 839 [(931, k2)], .inn 925 931 [(839, k4)], .out 619 812 [(193, k1), (228, k1)] [], .inn 619 812 [(689, k0)], .inn 926 812 [(988, k0)], .inn 926 988 [(812, k1)], .out 620 821 [(190, k1), (226, k1)] [], .inn 620 821 [(836, k0)], .inn 927 821 [(991, k2)], .inn 927 991 [(821, k4)], .out 626 420 [(187, k4), (225, k1)] [], .inn 626 420 [(781, k0)], .inn 928 836 [(420, k2)], .inn 928 420 [(836, k4)], .out 627 848 [(162, k4), (214, k1)] [], .inn 627 848 [(805, k0)], .inn 929 837 [(848, k0)], .inn 929 848 [(837, k1)], .out 637 858 [(179, k1), (188, k1)] [], .inn 637 858 [(785, k0)], .inn 719 941 [(858, k2)], .inn 719 858 [(941, k4)], .out 638 857 [(143, k1), (163, k1)] [], .inn 638 857 [(809, k0)], .inn 930 616 [(809, k0)], .inn 930 809 [(616, k1)], .inn 931 910 [(857, k0)], .inn 931 857 [(910, k1)], .out 880 777 [(147, k4), (210, k4)] [], .inn 880 777 [(255, k0)], .inn 932 255 [(814, k2)], .inn 932 814 [(255, k4)], .inn 933 777 [(819, k2)], .inn 933 819 [(777, k4)], .out 881 779 [(144, k4), (208, k4)] [], .inn 881 779 [(602, k0)], .inn 934 602 [(805, k0)], .inn 934 805 [(602, k1)], .inn 935 779 [(810, k0)], .inn 935 810 [(779, k1)], .out 828 451 [(153, k1), (206, k4)] [], .inn 828 451 [(716, k0)], .inn 936 716 [(756, k2)], .inn 936 756 [(716, k4)], .inn 937 451 [(768, k2)], .inn 937 768 [(451, k4)], .out 891 801 [(183, k4), (223, k4)] [], .inn 891 801 [(601, k0)], .inn 938 801 [(794, k2)], .inn 938 794 [(801, k4)], .out 892 803 [(180, k4), (221, k4)] [], .inn 892 803 [(567, k2)], .inn 939 567 [(781, k2)], .inn 939 781 [(567, k4)], .inn 940 803 [(786, k0)], .inn 940 786 [(803, k1)], .out 837 491 [(201, k1), (232, k4)] [], .inn 837 491 [(721, k0)], .inn 941 721 [(730, k0)], .inn 941 730 [(721, k1)], .inn 942 491 [(735, k0)], .inn 942 735 [(491, k1)], .out 902 640 [(192, k4), (227, k1)] [], .inn 902 640 [(447, k0)], .inn 943 601 [(447, k2)], .inn 943 447 [(601, k4)], .inn 944 689 [(640, k0)], .inn 944 640 [(689, k1)], .out 904 367 [(125, k4), (172, k1)] [], .inn 904 367 [(358, k0)], .inn 723 358 [(277, k2)], .inn 723 277 [(358, k4)], .inn 724 367 [(280, k2)], .inn 724 280 [(367, k4)], .out 665 631 [(178, k4), (189, k1)] [], .inn 665 631 [(733, k0)], .inn 716 733 [(782, k2)], .inn 716 782 [(733, k4)], .inn 718 631 [(785, k2)]] +noncomputable def seg1_7 : List (Gate) := [.inn 718 785 [(631, k4)], .out 817 593 [(132, k1), (158, k1)] [], .inn 817 593 [(596, k0)], .inn 743 871 [(593, k0)], .inn 743 593 [(871, k1)], .inn 945 869 [(596, k0)], .inn 945 596 [(869, k1)], .inn 923 152 [(840, k4)], .inn 923 156 [(942, k0)], .inn 716 175 [(573, k2), (733, k1)], .inn 716 186 [(406, k2), (782, k0)], .inn 717 176 [(579, k2), (732, k1)], .inn 717 185 [(575, k1), (637, k0)], .inn 718 178 [(399, k0), (631, k1)], .inn 718 189 [(381, k2), (785, k0)], .inn 719 179 [(574, k1), (941, k1)], .inn 719 188 [(378, k2), (858, k0)], .inn 937 206 [(451, k1)], .inn 938 183 [(794, k2)], .inn 933 147 [(819, k2)], .inn 933 210 [(777, k1)], .inn 920 168 [(989, k2)], .inn 920 217 [(788, k1)], .inn 935 144 [(779, k1)], .inn 935 208 [(810, k0)], .inn 921 215 [(992, k0)], .inn 927 226 [(991, k0)], .inn 942 232 [(735, k0)], .inn 722 122 [(248, k1), (755, k1)], .inn 722 169 [(271, k2), (684, k2)], .inn 723 124 [(253, k1), (277, k2)], .inn 723 171 [(358, k4), (686, k2)], .inn 724 125 [(251, k1), (280, k2)], .inn 724 172 [(367, k4), (503, k2)], .inn 725 123 [(245, k1), (257, k1)], .inn 725 170 [(274, k2), (497, k2)], .inn 726 138 [(337, k1), (600, k1)], .inn 726 145 [(680, k2), (771, k0)], .inn 727 174 [(395, k1), (753, k0)], .inn 727 181 [(682, k2), (688, k1)], .inn 728 184 [(368, k1), (1013, k0)], .inn 728 191 [(483, k2), (603, k1)], .inn 729 159 [(283, k1), (1014, k2)], .inn 729 166 [(463, k2), (691, k1)], .inn 736 198 [(489, k2), (550, k1)], .inn 736 202 [(705, k1), (953, k0)], .inn 743 132 [(441, k2), (593, k0)], .inn 743 158 [(704, k1), (871, k4)], .inn 875 212 [(455, k2), (870, k4)], .inn 748 234 [(495, k2), (881, k4)], .inn 122 120 [(401, k4), (465, k2), (586, k4), (773, k1), (775, k1)], .inn 123 121 [(374, k4), (464, k0), (571, k4), (906, k1), (918, k1)], .inn 124 122 [(288, k2), (578, k4)], .inn 125 123 [(297, k2), (373, k4)], .inn 126 124 [(293, k2), (383, k4)], .inn 127 125 [(296, k2), (380, k4)], .inn 128 126 [(334, k2), (438, k2), (751, k2), (914, k4), (962, k0)], .inn 129 127 [(263, k1), (267, k1), (437, k2), (555, k4), (1011, k0)], .inn 130 128 [(526, k2), (766, k2), (804, k0), (849, k0)], .inn 131 129 [(535, k2), (759, k2), (855, k2), (977, k0)], .inn 132 130 [(530, k2), (764, k2), (802, k0), (851, k0)], .inn 133 131 [(539, k2), (761, k2), (852, k0), (976, k0)], .inn 134 132 [(291, k1), (980, k0)], .inn 135 133 [(313, k0), (690, k4), (820, k0), (1012, k0)], .inn 136 134 [(527, k1), (780, k4), (982, k0), (1016, k2)], .inn 137 135 [(319, k0), (599, k4), (811, k0), (1017, k0)], .inn 138 136 [(531, k1), (778, k4), (981, k0), (1018, k0)], .inn 139 137 [(439, k2), (596, k0), (892, k1), (973, k0)], .inn 140 138 [(774, k0), (959, k0)], .inn 141 139 [(518, k2), (763, k2), (806, k0), (815, k0)], .inn 142 140 [(548, k2), (698, k0), (762, k2), (818, k0)], .inn 143 141 [(298, k2), (602, k1), (967, k0), (995, k0)], .inn 144 142 [(520, k1), (809, k0), (1000, k0), (1006, k4)], .inn 145 143 [(348, k2), (832, k4), (857, k0), (1005, k0)], .inn 146 144 [(613, k2), (825, k0), (985, k0)], .inn 147 145 [(776, k0), (965, k0)], .inn 148 146 [(306, k2), (814, k2), (961, k0), (1003, k0)], .inn 149 147 [(617, k2), (824, k0), (997, k0)], .inn 150 148 [(436, k0), (522, k4), (866, k0), (938, k2), (949, k2)], .inn 151 149 [(528, k1), (720, k4), (741, k4), (795, k4)], .inn 152 150 [(326, k2), (748, k4), (839, k4), (896, k4)], .inn 153 151 [(532, k1), (718, k4), (743, k4), (787, k4)], .inn 154 152 [(331, k2), (746, k4), (895, k4)], .inn 155 153 [(542, k1), (655, k1), (768, k0), (869, k4)], .inn 156 154 [(269, k2), (736, k4), (901, k4), (931, k0)], .inn 157 155 [(272, k2), (807, k0), (894, k4), (899, k4)], .inn 158 156 [(275, k2), (727, k4), (912, k4)], .inn 159 157 [(278, k2), (581, k0), (893, k4), (909, k4)], .inn 160 158 [(756, k0), (919, k1)], .inn 161 159 [(315, k1), (772, k0)], .inn 162 160 [(295, k0), (722, k4), (731, k4), (838, k1)], .inn 163 161 [(519, k1), (734, k4), (900, k4), (1008, k1)], .inn 164 162 [(290, k1), (767, k0), (837, k1), (872, k4)], .inn 165 163 [(338, k2), (725, k4), (910, k4), (957, k0)], .inn 166 164 [(341, k2), (616, k4), (898, k4), (955, k0)], .inn 167 165 [(456, k2), (758, k0), (796, k1), (875, k4)], .inn 168 166 [(321, k1), (769, k0)], .inn 169 167 [(304, k1), (425, k0), (765, k0), (873, k4)], .inn 170 168 [(459, k2), (760, k0), (874, k4)], .inn 171 169 [(752, k2), (951, k0)], .inn 172 170 [(303, k0), (947, k2)], .inn 173 171 [(739, k2), (952, k0)], .inn 174 172 [(289, k0), (937, k2)], .inn 175 173 [(250, k4), (282, k2), (440, k0), (514, k4), (647, k0), (651, k0), (933, k4), (948, k2)], .inn 176 174 [(262, k2), (958, k0)], .inn 177 175 [(724, k1), (834, k4)], .inn 178 176 [(928, k1), (1009, k4)], .inn 179 177 [(384, k2), (567, k4), (883, k1), (979, k4)], .inn 180 178 [(723, k1), (744, k0)], .inn 181 179 [(745, k0), (929, k1)], .inn 182 180 [(626, k2), (737, k4), (803, k1), (877, k1)], .inn 183 181 [(266, k2), (964, k0)], .inn 184 182 [(392, k2), (447, k2), (882, k1), (978, k4)], .inn 185 183 [(632, k2), (728, k4), (878, k1)], .inn 186 184 [(534, k2), (754, k0)], .inn 187 185 [(835, k4), (999, k0)], .inn 188 186 [(1004, k0), (1010, k4)], .inn 189 187 [(376, k1), (800, k0), (836, k4), (974, k4)], .inn 190 188 [(790, k0), (956, k0)], .inn 191 189 [(793, k0), (954, k0)], .inn 192 190 [(476, k2), (719, k4), (821, k4), (966, k0)], .inn 193 191 [(538, k2), (963, k0)], .inn 194 192 [(390, k1), (640, k2), (799, k0), (975, k4)], .inn 195 193 [(479, k2), (717, k4), (960, k0), (988, k2)], .inn 196 194 [(499, k2), (565, k4), (757, k4), (908, k1), (1015, k0)], .inn 197 195 [(498, k0), (517, k0), (564, k4), (905, k4), (913, k1)], .inn 198 196 [(432, k2), (486, k2), (512, k4), (524, k4), (620, k0), (635, k0), (907, k4), (936, k4)], .inn 199 197 [(485, k2), (561, k4), (770, k4), (897, k1), (990, k4)], .inn 200 198 [(305, k2), (993, k4)], .inn 201 199 [(487, k2), (659, k2), (726, k4), (880, k1)], .inn 202 200 [(484, k0), (560, k4), (903, k1), (917, k4), (983, k4)], .inn 203 201 [(491, k4), (525, k0), (594, k1), (940, k2)], .inn 204 202 [(721, k4), (945, k2)], .inn 205 203 [(427, k2), (488, k0), (889, k4), (916, k4), (922, k1)], .inn 206 204 [(308, k0), (311, k0), (323, k0), (336, k0), (352, k0), (355, k0), (462, k0), (619, k0), (902, k1)], .inn 207 205 [(244, k2), (322, k0), (569, k0), (716, k1)], .inn 208 206 [(256, k1), (455, k2), (584, k0), (876, k2)], .inn 209 207 [(240, k2), (344, k0), (715, k1), (805, k0)], .inn 210 208 [(551, k1), (886, k2), (968, k1)], .inn 211 209 [(255, k1), (316, k0), (354, k0), (714, k1)], .inn 212 210 [(557, k1), (888, k2), (969, k1)], .inn 213 211 [(259, k2), (287, k1), (890, k1), (891, k1)], .inn 214 212 [(568, k0), (750, k1), (925, k0)], .inn 215 213 [(281, k0), (868, k4), (950, k0), (972, k1)], .inn 216 214 [(442, k2), (529, k4), (738, k1), (848, k0)], .inn 217 215 [(310, k2), (444, k2), (971, k1)], .inn 218 216 [(446, k2), (533, k4), (607, k1), (729, k1)], .inn 219 217 [(448, k2), (970, k1), (1022, k4)], .inn 220 218 [(309, k2), (547, k1), (904, k1), (915, k1)], .inn 221 219 [(242, k0), (268, k1), (394, k0), (403, k0), (410, k0), (482, k0), (628, k0), (943, k1), (1020, k4)]] +noncomputable def seg1_8 : List (Gate) := [.inn 222 220 [(258, k2), (402, k0), (740, k0), (781, k0)], .inn 223 221 [(582, k1), (749, k0), (786, k0), (885, k2)], .inn 224 222 [(276, k0), (412, k0), (601, k1), (742, k0)], .inn 225 223 [(590, k1), (747, k0), (801, k1), (887, k2)], .inn 226 224 [(241, k2), (595, k0), (923, k1), (924, k1)], .inn 227 225 [(273, k2), (420, k0), (466, k2), (984, k0)], .inn 228 226 [(270, k2), (468, k2), (994, k0)], .inn 229 227 [(279, k2), (470, k2), (689, k4), (996, k0)], .inn 230 228 [(472, k2), (812, k4), (1002, k0), (1021, k4)], .inn 231 229 [(243, k2), (935, k1), (946, k1), (1007, k0)], .inn 232 230 [(247, k0), (299, k0), (360, k0), (428, k0), (431, k0), (496, k0), (521, k2), (615, k2), (930, k4)], .inn 233 231 [(302, k0), (430, k0), (544, k1), (730, k0)], .inn 234 232 [(495, k2), (598, k0), (884, k0), (927, k1)], .inn 235 233 [(389, k0), (423, k2), (865, k0), (926, k1)], .inn 236 234 [(419, k1), (553, k1), (998, k0)], .inn 237 235 [(426, k0), (879, k4), (934, k1), (1001, k0)], .inn 238 236 [(429, k2), (921, k0), (932, k1), (1019, k0)], .inn 239 237 [(252, k0), (292, k2), (364, k0), (393, k0), (417, k0), (424, k1), (502, k0), (634, k2), (911, k4)], .inn 240 238 [(375, k0), (416, k2), (939, k1), (986, k1)], .inn 241 239 [(418, k2), (920, k0), (944, k1), (987, k1)]] +noncomputable def seg1 : List (Gate) := seg1_0 ++ (seg1_1 ++ (seg1_2 ++ (seg1_3 ++ (seg1_4 ++ (seg1_5 ++ (seg1_6 ++ (seg1_7 ++ (seg1_8)))))))) +noncomputable def rs1_0 : List (Nat) := [1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 2, 2, 2, 2, 4, 4, 1, 2, 2, 1, 4, 2, 1, 2, 1, 1, 2, 4, 2, 1, 4, 1, 2, 4, 2, 1, 4, 1, 2, 4, 2, 1, 4, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 1, 2, 4, 2, 1, 4, 2, 1, 2, 1, 1, 2, 4, 2, 1, 4, 1, 2, 4, 2, 1, 4, 1, 2, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 1, 1, 1, 1, 1, 1, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 5, 2, 2, 5, 5, 2, 2, 5, 2] +noncomputable def rs1_1 : List (Nat) := [2, 5, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 2, 2, 2, 2, 5, 5, 2, 2, 5, 5, 3, 2, 3, 2, 3, 2, 3, 2, 2, 3, 2, 3, 6, 3, 2, 6, 3, 2, 3, 2, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 2, 3, 2, 3, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 3, 2, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 3, 2, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 2, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 6, 3, 3, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3] +noncomputable def rs1_2 : List (Nat) := [6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 6, 3, 3, 6, 3, 3, 6, 5, 5, 1, 1, 5, 5, 1, 1, 2, 1, 1, 1, 5, 5, 1, 1, 5, 5, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 2, 1, 5, 5, 5, 5, 5, 5, 5, 5, 2, 1, 5, 5, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 1, 1, 5, 5, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 4, 5, 4, 4, 7, 2, 2, 5, 5, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 5, 5, 5, 5, 2, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 7, 1, 2, 5, 5, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 3, 1, 1, 3] +noncomputable def rs1_3 : List (Nat) := [1, 1, 3, 2, 2, 5, 5, 2, 3, 6, 1, 1, 3, 3, 6, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 3, 1, 1, 3, 1, 1, 3, 2, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 3, 1, 1, 3, 1, 1, 3, 2, 2, 5, 5, 2, 3, 6, 3, 3, 6, 3, 3, 6, 3, 3, 6, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 3, 1, 1, 3, 1, 1, 3, 2, 2, 5, 5, 2, 3, 6, 1, 1, 3, 3, 6, 3, 3, 6, 3, 3, 3, 3, 6, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 4, 3, 2, 2, 2, 6, 1, 1, 1, 1, 2, 2, 1, 4, 3, 2, 6, 2, 2, 6, 1, 1, 1, 1, 2, 2, 1, 4, 3, 2, 2, 2, 6, 1, 1, 1, 1, 2, 2, 1, 4, 3, 2, 6, 2, 2, 6, 1, 1, 1, 1, 2, 2, 1, 4, 3, 2, 6, 2, 2, 6, 1, 1, 1, 1, 1, 1, 2, 2, 1, 4, 3, 2, 6, 2, 2, 6, 1, 1, 1, 1] +noncomputable def rs1_4 : List (Nat) := [1, 1, 2, 2, 1, 4, 3, 2, 6, 2, 2, 6, 1, 1, 1, 1, 1, 1, 2, 2, 1, 4, 3, 2, 6, 2, 2, 6, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 3, 4, 3, 2, 6, 3, 2, 6, 3, 3, 3, 3, 3, 3, 6, 2, 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 6, 1, 1, 1, 1, 3, 3, 3, 2, 1, 3, 4, 4, 4, 4, 2, 3, 2, 3, 4, 4, 4, 4, 3, 2, 6, 1, 1, 3, 2, 1, 2, 4, 4, 4, 4, 3, 2, 6, 1, 1, 1, 1, 3, 2, 1, 1, 4, 4, 4, 4, 2, 3, 2, 3, 4, 4, 4, 4, 3, 2, 6, 1, 1, 1, 1, 3, 2, 1, 1, 4, 4, 4, 4, 3, 2, 6, 1, 1, 1, 1, 3, 2, 2, 1, 4, 4, 4, 4, 3, 2, 3, 2, 4, 4, 3, 2, 3, 2, 1, 1, 1, 1, 2, 5, 5, 2, 2, 2, 1, 5, 2, 1, 5, 2, 1, 5, 2, 1, 5, 2, 5, 2, 2, 1, 5, 1, 2, 5, 1, 2, 5, 2, 2, 1, 5, 5, 1, 2, 5, 2, 5, 1, 2, 6, 6, 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, 6, 6, 1, 1, 6, 6, 1, 2, 1, 2] +noncomputable def rs1_5 : List (Nat) := [6, 6, 1, 2, 1, 1, 6, 6, 1, 1, 6, 6, 1, 1, 6, 6, 1, 1, 6, 6, 1, 1, 6, 6, 1, 1, 6, 6, 2, 1, 2, 1, 6, 6, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 6, 6, 1, 1, 1, 1, 6, 6, 1, 1, 2, 2, 1, 1, 1, 1, 2, 6, 6, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 3, 6, 6, 1, 1, 1, 1, 6, 6, 2, 1, 2, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 7, 4, 7, 4, 7, 1, 6, 6, 1, 1, 7, 1, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 2, 3, 1, 7, 1, 1, 5, 6, 1, 4, 1, 1, 1, 1, 4, 5, 1, 1, 1, 4, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 4, 1, 1, 1, 1, 4, 5, 1, 1, 1, 4, 1, 1, 1, 1, 8, 4, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 4, 5, 1, 1, 1, 4, 1, 1, 1, 1, 3, 5, 1, 1, 1, 2, 5, 1, 1, 1, 1] +noncomputable def rs1_6 : List (Nat) := [1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, 7, 6, 6, 1, 1, 1, 3, 5, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, 1, 2, 1, 1, 1, 1, 3, 5, 1, 1, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 4, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 5, 5, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 5, 5, 5, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 7, 6, 6, 1, 1, 1, 7, 6, 1, 6, 1, 1, 3, 5, 5, 5, 5, 5, 2, 3, 7, 6, 6, 1, 1, 1, 1, 1, 1, 8, 4, 1, 1, 1, 7, 6, 6, 1, 1, 1, 2, 1, 1] +noncomputable def rs1_7 : List (Nat) := [4, 1, 1, 1, 1, 3, 5, 1, 3, 2, 3, 6, 1, 1, 6, 6, 5, 6, 5, 3, 6, 1, 5, 1, 1, 1, 5, 1, 1, 1, 4, 1, 5, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 5, 1, 1, 6, 5, 1, 1, 1, 1, 5, 1, 1, 6, 5, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 5, 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, 6, 5, 1, 1, 1, 3, 6, 1, 6, 5, 6, 6, 5, 3, 1, 4, 1, 1, 1, 1, 2, 5, 1, 1, 1, 5, 1, 5, 1, 1, 2, 5, 1, 1, 1, 6, 5, 1, 1, 1, 2, 1, 1, 5, 1, 1, 1, 1, 1, 2, 1, 5, 1, 1, 2, 5, 1, 1, 1, 6, 5, 1, 1, 1, 3, 6, 5, 6, 6, 4, 6, 1, 5, 3, 6, 1, 5, 1, 1, 1, 1, 5, 1, 1, 6, 1, 5, 1, 1, 1, 1, 1, 6, 5, 1, 1, 1, 6, 5, 1, 1, 1, 3, 6, 1, 6, 5, 6, 4, 6, 5, 3, 6, 1, 5, 1, 1, 6, 5, 1, 1, 1] +noncomputable def rs1 : List (Nat) := rs1_0 ++ (rs1_1 ++ (rs1_2 ++ (rs1_3 ++ (rs1_4 ++ (rs1_5 ++ (rs1_6 ++ (rs1_7))))))) +noncomputable def gA : List (List Gate) := [seg0] +noncomputable def gB : List (List Gate) := [seg1] +noncomputable def fins_0 : List (Gate) := [.out 1 240 [] [241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271], .out 1 272 [] [273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303], .out 1 304 [] [305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335], .out 1 336 [] [337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367], .out 1 368 [] [369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399], .out 1 400 [] [401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431], .out 1 432 [] [433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463], .out 1 464 [] [465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495], .out 1 496 [] [497, 498, 499, 500, 501, 502, 503, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535], .out 1 536 [] [537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567], .out 1 568 [] [569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599], .out 1 600 [] [601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631], .out 1 632 [] [633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663], .out 1 664 [] [665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695], .out 1 696 [] [697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727], .out 1 728 [] [729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759], .out 1 760 [] [761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791], .out 1 792 [] [793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823], .out 1 824 [] [825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855], .out 1 856 [] [857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887], .out 1 888 [] [889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919], .out 1 920 [] [921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951], .out 1 952 [] [953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983], .out 1 984 [] [985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015], .out 1 1016 [] [1017, 1018, 1019, 1020, 1021, 1022]] +noncomputable def fins : List (Gate) := fins_0 +noncomputable def rF_0 : List (Nat) := [1, 1, 1, 1, 1, 2, 3, 1, 2, 3, 1, 2, 1, 2, 3, 1, 1, 2, 1, 1, 6, 6, 1, 1, 6, 6, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 6, 1, 6, 1, 1, 4, 6, 1, 6, 1, 1, 1, 2, 6, 1, 6, 6, 4, 6, 1, 6, 6, 1, 5, 1, 2, 1, 3, 3, 1, 3, 6, 1, 3, 3, 6, 1, 6, 6, 3, 1, 3, 1, 1, 4, 3, 2, 3, 1, 3, 3, 3, 1, 6, 6, 2, 2, 6, 3, 6, 6, 1, 1, 1, 1, 3, 2, 4, 1, 2, 4, 1, 1, 4, 3, 2, 3, 1, 1, 3, 1, 1, 1, 2, 3, 3, 6, 2, 6, 1, 1, 1, 3, 6, 2, 6, 6, 4, 1, 3, 1, 3, 3, 3, 1, 1, 1, 1, 1, 5, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 3, 1, 1, 1, 1, 1, 2, 1, 6, 1, 6, 1, 1, 1, 6, 6, 2, 1, 5, 1, 1, 1, 6, 6, 1, 6, 6, 1, 2, 1, 1, 1, 6, 1, 6, 1, 6, 1, 6, 6, 5, 1, 6, 6, 1, 6, 6, 1, 2, 1, 1, 1, 1, 1, 2] +noncomputable def rF_1 : List (Nat) := [6, 1, 1, 5, 1, 1, 1, 2, 1, 1, 6, 5, 1, 2, 1, 3, 1, 3, 3, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 1, 1, 6, 4, 1, 4, 1, 3, 3, 1, 1, 6, 2, 1, 3, 1, 3, 1, 4, 1, 4, 3, 1, 1, 3, 3, 1, 1, 4, 1, 1, 1, 4, 1, 3, 2, 2, 2, 3, 4, 1, 2, 6, 1, 1, 4, 1, 3, 1, 3, 3, 3, 1, 3, 3, 2, 1, 1, 1, 5, 1, 1, 2, 1, 1, 2, 6, 3, 5, 1, 5, 5, 6, 3, 6, 1, 6, 1, 1, 1, 6, 1, 1, 6, 5, 6, 3, 4, 1, 6, 1, 6, 4, 2, 1, 6, 1, 1, 6, 2, 5, 3, 1, 5, 3, 5, 3, 5, 5, 1, 6, 5, 5, 1, 6, 3, 3, 1, 3, 3, 4, 1, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 2, 5, 2, 5, 2, 5, 2, 5, 2, 1, 1, 2, 5, 5, 5, 5, 3, 3, 1, 3, 5, 5, 5, 5, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def rF_2 : List (Nat) := [1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 4, 4, 2, 1, 1, 2, 4, 1, 3, 3, 1, 2, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 3, 1, 1, 4, 4, 1, 2, 1, 1, 3, 3, 1, 1, 3, 4, 3, 3, 3, 3, 1, 3, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 1, 1, 3, 1, 1, 3, 3, 1, 3, 1, 2, 3, 3, 3, 3, 3, 3, 1, 1, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1] +noncomputable def rF_3 : List (Nat) := [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1] +noncomputable def rF : List (Nat) := rF_0 ++ (rF_1 ++ (rF_2 ++ (rF_3))) +noncomputable def pairs : List (List (Nat × Nat)) := [] +noncomputable def cuts : List (Nat × List Nat) := [] +noncomputable def tab_0 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 0) (.leaf 169848033248118254784858923011)) (.node (.leaf 198509397473908406202974210) (.leaf 290142196707739700549421571))) (.node (.node (.leaf 159230188816527698340427726344) (.leaf 160471755651754765604683380742)) (.node (.leaf 256872558442252626202493788162) (.leaf 158702946043556213707671581446)))) (.node (.node (.node (.leaf 200546286364231604533658189825) (.leaf 166053373313460167993853075460)) (.node (.leaf 160952416835646117818449922) (.leaf 159309826887761133004218542084))) (.node (.node (.leaf 163562978990919876712438429448) (.leaf 158614845578973552507237825543)) (.node (.leaf 170821744972395460611) (.leaf 0))))) (.node (.node (.node (.node (.leaf 175244068700240748545) (.leaf 200546286599427802579687516163)) (.node (.leaf 241785403730598793165447170) (.leaf 158630561683641721003081592327))) (.node (.node (.leaf 159849158836170423662048181512) (.leaf 158645106627749033229928358662)) (.node (.leaf 238303457562435702918282805762) (.leaf 164183160265355678413358233095)))) (.node (.node (.node (.leaf 305152219683846237762634186753) (.leaf 158640289758596274142547404294)) (.node (.leaf 241785422177342866874998786) (.leaf 160555020509634088706829820932))) (.node (.node (.leaf 159231397746968023779470605832) (.leaf 188360502997175598113490194183)) (.node (.leaf 176697008050462399475539971) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 189079126755522912257) (.leaf 171129494395549043931765377027)) (.node (.leaf 168978815583815336408245149698) (.leaf 158612430175977539678752598534))) (.node (.node (.leaf 158611221162679935656161050120) (.leaf 160471762804299618848799321094)) (.node (.leaf 160787134008956786669816323) (.leaf 158611247168013281490293224199)))) (.node (.node (.node (.leaf 207973926599943886183052935169) (.leaf 161094364323767653095086090245)) (.node (.leaf 203166386389937827842) (.leaf 158611225880434855515108014086))) (.node (.node (.leaf 159851581419417487109754453256) (.leaf 158625725943649759822518416135)) (.node (.leaf 165785758930863199895994883) (.leaf 0))))) (.node (.node (.node (.node (.leaf 234531609005238059893030913) (.leaf 159309826883149464577977198596)) (.node (.leaf 159308617961941535967229880324) (.leaf 158614852676376419496802514950))) (.node (.node (.leaf 158611218815367780936200747784) (.leaf 158618486523522908035748067334)) (.node (.leaf 159984407264521812754521229315) (.leaf 164183176793575318062333294087)))) (.node (.node (.node (.leaf 286583119094565533639147323393) (.leaf 158611218884362980141379480582)) (.node (.leaf 295248699604759182503237984258) (.leaf 160548975779241228629639805958))) (.node (.node (.leaf 158612427727325333676380782088) (.leaf 158635397386920232124472879879)) (.node (.leaf 170835725642743617926826371075) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 160313235087456745599436652545) (.leaf 198689376582004695227154113027)) (.node (.leaf 305152219683846237762835513858) (.leaf 158616063949508188708700027399))) (.node (.node (.leaf 158611218801496711813524487688) (.leaf 166044924916965088254404719110)) (.node (.leaf 189268277939872477186) (.leaf 158694483562711036018691258886)))) (.node (.node (.node (.leaf 183215125814236280685070450689) (.leaf 175523278618698909799730693)) (.node (.leaf 196039599803367581756211202) (.leaf 158611218796912047461446581255))) (.node (.node (.leaf 168514776889955798171190030088) (.leaf 163562997848113013261349287431)) (.node (.leaf 175433430990822848515) (.leaf 0))))) (.node (.node (.node (.node (.leaf 164646025224955576561583587329) (.leaf 158746467225236362317036358660)) (.node (.leaf 159369064022337966504595785731) (.leaf 231204701818056394839998466))) (.node (.node (.leaf 158613641370890720330771594504) (.leaf 160476607897178046594744973318)) (.node (.leaf 198616093441630742274050) (.leaf 159868539501858981792767536391)))) (.node (.node (.node (.leaf 274203718701711730890156081153) (.leaf 163649870501931883254700422662)) (.node (.leaf 159988034041980639049859303427) (.leaf 158634233323582134525488131078))) (.node (.node (.leaf 159231400103530572030970822152) (.leaf 161712125353216275529928407559)) (.node (.leaf 183964785407831004588072963) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 229034774419177792880641) (.leaf 171071466177568259509661573123)) (.node (.leaf 203085321596645158914) (.leaf 246621028781531782438760451))) (.node (.node (.leaf 158611218806108380308351221000) (.leaf 158611218884362962583553174534)) (.node (.leaf 175487860869918885786206210) (.leaf 160470549073256260152525454343)))) (.node (.node (.node (.leaf 310722949860630448999680245761) (.leaf 159321916086230312339560837637)) (.node (.leaf 239807884064456714242) (.leaf 158614845574343869751206476807))) (.node (.node (.leaf 159231400108142258049331101192) (.leaf 158640289758596274108120688391)) (.node (.leaf 191477203485105347125763) (.leaf 0))))) (.node (.node (.node (.node (.leaf 239807672958224179201) (.leaf 158630410567914374555550984196)) (.node (.leaf 175523278618540408125308930) (.leaf 166038859051115950645126099719))) (.node (.node (.leaf 161087108320188734354560908040) (.leaf 158613639009707531672506989575)) (.node (.leaf 160313235087456921693095791619) (.leaf 0)))) (.node (.node (.node (.leaf 230904831546394172368912385) (.leaf 158630599411845090362301475334)) (.node (.leaf 232360378233210185895225950210) (.leaf 159849163577019714449355045127))) (.node (.node (.leaf 168978815362454407523931849218) (.leaf 166048539883887031750066696967)) (.node (.leaf 199540460359013394165945966595) (.leaf 0))))))) +noncomputable def tab_1 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 171136785840082945) (.leaf 199544087136472238053470085123)) (.node (.leaf 213035396775215434880303106) (.leaf 158630599462573654157188786694))) (.node (.node (.leaf 158611221158068249672093400584) (.leaf 160468135957845646021627082758)) (.node (.leaf 197682605550087588718911275011) (.leaf 158692065711098758126599519238)))) (.node (.node (.node (.leaf 183756724581423634555371521) (.leaf 188341197962993750011585611780)) (.node (.leaf 167004129483443568159801346) (.leaf 178534165040859837189238921220))) (.node (.node (.leaf 158611256649459732266835242760) (.leaf 159231397760830156071569062407)) (.node (.leaf 189362290783427075) (.leaf 0))))) (.node (.node (.node (.node (.leaf 234187180623269889) (.leaf 232345871123375021451362011139)) (.node (.leaf 234821751201945570894927724546) (.leaf 158612430120853269270944151047))) (.node (.node (.leaf 159849158836188402876185574664) (.leaf 158692065711071771747567123462)) (.node (.leaf 163643825978749466248204100612) (.leaf 160470549077876970996753366023)))) (.node (.node (.node (.leaf 305858232362501181200695297) (.leaf 159235034042793739952844827142)) (.node (.leaf 188360314102516142452619968514) (.leaf 158640270906023830776958936839))) (.node (.node (.leaf 159231400103539561638039518728) (.leaf 158611266094192768237430893319)) (.node (.leaf 198921490062669542923054449155) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 225972614902942015489) (.leaf 173561853421314627830684950531)) (.node (.leaf 175294479040108170129219586) (.leaf 158612430102334678571990252039))) (.node (.node (.leaf 159230191177710939775183224328) (.leaf 158692065715701436945772166150)) (.node (.leaf 162921643922885550557186) (.leaf 158630599462573583925883563527)))) (.node (.node (.node (.leaf 257491528171359097179017904129) (.leaf 173472555776966572053589254661)) (.node (.leaf 169429064672397130977034242) (.leaf 188325519706270622789476141060))) (.node (.node (.leaf 159849163567778293035777129736) (.leaf 158617263425983151580156918279)) (.node (.leaf 162161342655471853225691139) (.leaf 0))))) (.node (.node (.node (.node (.leaf 202914184810805075969) (.leaf 167933319131431908756682825732)) (.node (.leaf 161580147430798667778) (.leaf 158630599388786607665405095431))) (.node (.node (.leaf 158611228260064717878472211208) (.leaf 158616063986482530543179264518)) (.node (.leaf 178534165040688700403398838275) (.leaf 0)))) (.node (.node (.node (.leaf 256872558151716407041568342017) (.leaf 158630573489557980781954066950)) (.node (.leaf 161230809784544442657085163523) (.leaf 158689647859432595094111369734))) (.node (.node (.leaf 175433219884590313474) (.leaf 169153054309575404498135936519)) (.node (.leaf 235740696405000119866404867) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 162921643659002759888897) (.leaf 236059691241230951170028175875)) (.node (.leaf 294010759551638744173056696322) (.leaf 235740774632736753524451331))) (.node (.node (.leaf 158611218801505701420593184264) (.leaf 158616094713921502449728875014)) (.node (.leaf 175244332583031416834) (.leaf 158612427741187465934186609159)))) (.node (.node (.node (.leaf 264452523040700131983361) (.leaf 169154301097337335797281581061)) (.node (.leaf 199544086859771076947826802690) (.leaf 158611218810720101476790828039))) (.node (.node (.leaf 178456944904104808145211350792) (.leaf 158620899648282836491728843527)) (.node (.leaf 159308617897558040510103403014) (.leaf 0))))) (.node (.node (.node (.node (.leaf 169597785382097097661180084225) (.leaf 161847361952547868352014551556)) (.node (.leaf 160313235087456904135269485571) (.leaf 169148244648487733539423511045))) (.node (.node (.leaf 158611218815331822507925961480) (.leaf 169231481010939662131022376454)) (.node (.leaf 295248699590924124447955820546) (.leaf 161707280200557083681934670343)))) (.node (.node (.node (.leaf 291534879251707054738743820289) (.leaf 164183160375819970073501754886)) (.node (.leaf 164939794199121931451037220866) (.leaf 188323104215814529584833089030))) (.node (.node (.leaf 159231397742356337795402956296) (.leaf 159249571848011201550942858759)) (.node (.leaf 183955285334633044168990723) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 198689376305303534121309503489) (.leaf 203268787545199736374893322243)) (.node (.leaf 200778400121597613335201808386) (.leaf 158707781820369605441615932934))) (.node (.node (.leaf 158611218796903057785658539272) (.leaf 158616073518612350651154555654)) (.node (.leaf 175294465205050115048382979) (.leaf 158611218824591258526037571847)))) (.node (.node (.node (.leaf 236446547503507632505732792321) (.leaf 168538972008417880101009614853)) (.node (.leaf 173311605776654399591520739330) (.leaf 158693274728980956201177295622))) (.node (.node (.leaf 158612430088508575111136280072) (.leaf 158617275231899358754202843655)) (.node (.leaf 194828312800511517960225283) (.leaf 0))))) (.node (.node (.node (.node (.leaf 236118324143482260701185) (.leaf 158630599241212760456844920836)) (.node (.leaf 228698619906562) (.leaf 159868539501859052024072759558))) (.node (.node (.leaf 158620890203513842092858406664) (.leaf 158611225889667111743354174471)) (.node (.leaf 161844944100908744646580078595) (.leaf 0)))) (.node (.node (.node (.leaf 158611218796894015402232905224) (.leaf 160472974003851594700184221702)) (.node (.leaf 168629436091121998853165916163) (.leaf 161707280278802623607869663750))) (.node (.node (.leaf 161551175126742284204010178562) (.leaf 160469340147436645557710486535)) (.node (.leaf 169848033261953312840141086723) (.leaf 0))))))) +noncomputable def tab_n00 : SSC.Trie := .node tab_0 tab_1 +noncomputable def tab_2 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 240518169601) (.leaf 198994025611846420673536819715)) (.node (.leaf 200546286364231815639890724866) (.leaf 233322959886784536562934275))) (.node (.node (.leaf 158611218796894015436525534728) (.leaf 158611225967912651669289167878)) (.node (.leaf 217508724539244466483960578050) (.leaf 163564190277922732776502720007)))) (.node (.node (.node (.leaf 258254417031933730817) (.leaf 160482643178181130922653507588)) (.node (.leaf 160952416835857224050984963) (.leaf 158690856868118355043277843718))) (.node (.node (.leaf 163562997843492320043600181000) (.leaf 163564190241101302223121544711)) (.node (.leaf 175442490966635722755) (.leaf 0))))) (.node (.node (.node (.node (.leaf 161996059828360309410660353) (.leaf 200778400356793600274998599683)) (.node (.leaf 295867669610566814585405382658) (.leaf 158616063954137889125435701511))) (.node (.node (.leaf 158611223519269505470931664136) (.leaf 160469340147436750904668321798)) (.node (.leaf 179157139627108600117248002) (.leaf 158613639023542536951231020039)))) (.node (.node (.node (.leaf 275441658740997111165055205377) (.leaf 160548975774620517785411894278)) (.node (.leaf 203268787310003749435096530946) (.leaf 158698110450706018191536269062))) (.node (.node (.leaf 158612430088508575076843650568) (.leaf 160471762721451400103691680775)) (.node (.leaf 233322683185852129338231299) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 165622837287204196934778881) (.leaf 173547346311479252280588476419)) (.node (.leaf 160787134009009563026622466) (.leaf 158612430083923963295299664391))) (.node (.node (.leaf 159230188821139384358788005384) (.leaf 166040070342739499926872519174)) (.node (.leaf 175478255880864018434) (.leaf 158617272870716134911566281223)))) (.node (.node (.node (.leaf 270799383593676935134216193) (.leaf 198868297547967639230114540037)) (.node (.leaf 158199277440015905343490) (.leaf 158611225880434750168150178823))) (.node (.node (.leaf 159851581410194150257271766280) (.leaf 158611218796930114430557092359)) (.node (.leaf 160950055652668565786511363) (.leaf 0))))) (.node (.node (.node (.node (.leaf 238922427582078393055531040769) (.leaf 161169154802940083508971939844)) (.node (.leaf 180739245735665731241504737282) (.leaf 160468128943290997777170033670))) (.node (.node (.leaf 158616054500199495379190020872) (.leaf 158611218829229930957856962566)) (.node (.leaf 160603377284164450115412658179) (.leaf 0)))) (.node (.node (.node (.leaf 227161997208867280443989360641) (.leaf 166040070324328784650181931526)) (.node (.leaf 236063318018689795057350967298) (.leaf 159854004067048116108587690246))) (.node (.node (.leaf 194828312800511517758898178) (.leaf 160469342503999176113945443335)) (.node (.leaf 200778400121597824441434343427) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 189151184349564929) (.leaf 198921490339370704028496404483)) (.node (.leaf 236059691241230951169826848770) (.leaf 298604677445024512384993282))) (.node (.node (.leaf 158612427722704640424271805960) (.leaf 158613639009707601903812212742)) (.node (.leaf 165785758930863199694667778) (.leaf 159250780769219130161690177031)))) (.node (.node (.node (.leaf 203022166442802365083456438273) (.leaf 235740696405193874431065093)) (.node (.leaf 233322683185623430919651842) (.leaf 168611302060865671345970720262))) (.node (.node (.leaf 158649979833402449661148782344) (.leaf 158611218806117387541965569031)) (.node (.leaf 189304306737092768259) (.leaf 0))))) (.node (.node (.node (.node (.leaf 193617025797655453777921) (.leaf 159928796902792137123240716292)) (.node (.leaf 167915184953601470158136786947) (.leaf 169429299868384070773825539))) (.node (.node (.leaf 159851576687809617736025505032) (.leaf 159308617883695978449310169606)) (.node (.leaf 203307321820503965740089346) (.leaf 161710906964180869514176625159)))) (.node (.node (.node (.leaf 303440380723271922851282945) (.leaf 158611218884362927467900562438)) (.node (.leaf 161844944100908480763789410306) (.leaf 160471762730683761678895676423))) (.node (.node (.leaf 159230191182322643420223503880) (.leaf 158611218819988474153949854215)) (.node (.leaf 179157139627319706349783043) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 178882335676737449722923515905) (.leaf 291534879473068194729490982915)) (.node (.leaf 169407814023224217573572610) (.leaf 251456791841035635644213251))) (.node (.node (.leaf 158613636648524237529845857544) (.leaf 158611218815394925679132932102)) (.node (.leaf 176694425506292080138305538) (.leaf 158618481796535767132792944903)))) (.node (.node (.node (.leaf 295867669389205885700890755073) (.leaf 171001520846407235759780258309)) (.node (.leaf 179119360695456749188073475) (.leaf 160550184787909079389949765636))) (.node (.node (.leaf 159231397746968023813763235336) (.leaf 158618486518902214818066069767)) (.node (.leaf 176694660702279019935096835) (.leaf 0))))) (.node (.node (.node (.node (.leaf 178921021302965117856546817) (.leaf 167933283644507996957932904452)) (.node (.leaf 175523278618540408326636035) (.leaf 158612430102370707368942107143))) (.node (.node (.leaf 158611218833850413206879860488) (.leaf 158611218801514761396271840263)) (.node (.leaf 188360502997175457238428532739) (.leaf 0)))) (.node (.node (.node (.leaf 158611218796885008237337902600) (.leaf 160472974036142404028430678022)) (.node (.leaf 177895852498468131477288755203) (.leaf 158611218815376876096385579527))) (.node (.node (.leaf 178882335676737449723124843010) (.leaf 158611218838471106424628966919)) (.node (.leaf 169844406484494468952616968195) (.leaf 0))))))) +noncomputable def tab_3 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 158199277176133114675201) (.leaf 199544087150307296108752248835)) (.node (.leaf 257491754844950274921988177922) (.leaf 158689647877915350372720949766))) (.node (.node (.leaf 159230188816527698374720355848) (.leaf 158614845661821771252345465862)) (.node (.leaf 197664507080541990803629785091) (.leaf 166040098658419595476996321798)))) (.node (.node (.node (.leaf 245563057109221551128577) (.leaf 162161518097751713628878853)) (.node (.leaf 169283464668997294075957838339) (.leaf 158611218796912152808404416518))) (.node (.node (.leaf 168514739184810911508866526984) (.leaf 161091934583354920349718411783)) (.node (.leaf 175433483767380981763) (.leaf 0))))) (.node (.node (.node (.node (.leaf 174727559866176872923137) (.leaf 188359367268036327088754638851)) (.node (.leaf 164948256679859234061418595331) (.leaf 158612430102370637000265038343))) (.node (.node (.leaf 158613636657747609497981156616) (.leaf 179154343986304022176237460998)) (.node (.leaf 183757001282584740198653954) (.leaf 160470551439051205232321231879)))) (.node (.node (.node (.leaf 303914279644560857487735062529) (.leaf 158611218879751346762071402758)) (.node (.leaf 167952664015192765097375285251) (.leaf 158648768767616266418528575492))) (.node (.node (.leaf 159230191182331633027292200456) (.leaf 158651191120405305725213072903)) (.node (.leaf 179119582056174527470166019) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 175294243844121230332428289) (.leaf 171071465956207541731379480579)) (.node (.leaf 198689376305303534121510830594) (.leaf 158611228246238737391255943687))) (.node (.node (.leaf 158611218796885043455868534024) (.leaf 158692065720304115764944813062)) (.node (.leaf 166997045933719263691980802) (.leaf 158630599462573583960176193031)))) (.node (.node (.node (.leaf 314436769978486589824377618433) (.leaf 159321916104641027616251425285)) (.node (.leaf 161847361952547868351813224451) (.leaf 158614845574343975098164312070))) (.node (.node (.leaf 159231400108151265214226103816) (.leaf 158631810749576422397627723271)) (.node (.leaf 175485499686677451164926467) (.leaf 0))))) (.node (.node (.node (.node (.leaf 169249614746048084458897409) (.leaf 160559856116319342175168081924)) (.node (.leaf 160313235087456921521297098754) (.leaf 158613641389373563432805333255))) (.node (.node (.leaf 161087098893902512688980032264) (.leaf 158612432445071105804675972103)) (.node (.leaf 188379656915630240402205935619) (.leaf 0)))) (.node (.node (.node (.leaf 269590457774062305959510017) (.leaf 166054577434056073809221513734)) (.node (.leaf 291534879528408215844387102722) (.leaf 159928796843020345276593584390))) (.node (.node (.leaf 189313313936146182146) (.leaf 160468128865045457851235040263)) (.node (.leaf 160470551439060300186347763718) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 161551175126742125874335776769) (.leaf 200778400412133832496127254531)) (.node (.leaf 271727838623141181446590367746) (.leaf 158630599462573619213133540358))) (.node (.node (.leaf 158612427722713630031340502536) (.leaf 158634226253867468276302474246)) (.node (.leaf 165282827164320373164034) (.leaf 158617275231899288385525774855)))) (.node (.node (.node (.leaf 188166885971377801784666947585) (.leaf 176561349440165742420850500101)) (.node (.leaf 171400668630751234) (.leaf 188379815114907416535320610820))) (.node (.node (.leaf 161091944041950036110732425992) (.leaf 158620899703514982321800606471)) (.node (.leaf 160959500385370422487597571) (.leaf 0))))) (.node (.node (.node (.node (.leaf 195845982777569926302433281) (.leaf 160607004061623258990363380740)) (.node (.leaf 236949700452351382699157507) (.leaf 169133709204453671877688289798))) (.node (.node (.leaf 158616054500163536950915234568) (.leaf 160472974031539725209258031110)) (.node (.leaf 291534879251707265844976355330) (.leaf 178418334835740883552556932615)))) (.node (.node (.node (.leaf 232113757366008801543585857537) (.leaf 161088310254548229859806669318)) (.node (.leaf 164331704511855772976160014338) (.leaf 179038513781212195518435941895))) (.node (.node (.leaf 158612430083896889092776001032) (.leaf 166043713625341538972658299655)) (.node (.leaf 198499952741153773145081859) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 246290604623873) (.leaf 203268787600539968596021977091)) (.node (.leaf 170835725421382689042311743490) (.leaf 166130586279160408966009434886))) (.node (.node (.leaf 158611223519251526256794270984) (.leaf 158619697805905070882063251462)) (.node (.leaf 194868452915615909743214594) (.leaf 164191622746029930422797989383)))) (.node (.node (.node (.leaf 312579859919558519412028932097) (.leaf 158631810749576457650585070598)) (.node (.leaf 170835725698083639041722490882) (.leaf 158635435184298768786599963399))) (.node (.node (.leaf 159231400108142258015038471688) (.leaf 160470551439060212397216234503)) (.node (.leaf 175485734882664390760390659) (.leaf 0))))) (.node (.node (.node (.node (.leaf 180739245735665520135272202241) (.leaf 160559856157743451547721904132)) (.node (.leaf 170821533866364252675) (.leaf 158631808393004866981232504327))) (.node (.node (.leaf 158611237723244287091422787336) (.leaf 158625725925239044545827828487)) (.node (.leaf 208224174535140333583142592515) (.leaf 0)))) (.node (.node (.node (.leaf 158611221158068249637800771080) (.leaf 158692065724906794584117459974)) (.node (.leaf 207973926890480105343978381314) (.leaf 159854003993405255001825343751))) (.node (.node (.leaf 236949700452140276466622466) (.leaf 158654824981413944148443257607)) (.node (.leaf 179186984983280336275150832131) (.leaf 0))))))) +noncomputable def tab_n01 : SSC.Trie := .node tab_2 tab_3 +noncomputable def tab_n0 : SSC.Trie := .node tab_n00 tab_n01 +noncomputable def tab_4 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 158611218796885008202911186697) (.leaf 295248699590924124448157147651)) (.node (.leaf 173311605721314167370392084482) (.leaf 246621093173999254783435267))) (.node (.node (.leaf 158611218796885025829456838152) (.leaf 158611247260066857873746158342)) (.node (.leaf 227452139405574791445918875650) (.leaf 166040070374940237262571565574)))) (.node (.node (.node (.leaf 240160367621363773330430164993) (.leaf 166042514231732809244684181508)) (.node (.leaf 160950055652404683197170179) (.leaf 159249569482216344294571239942))) (.node (.node (.leaf 158620909092907715977401333512) (.leaf 159235033964548200026909833735)) (.node (.leaf 160950055652615789228378115) (.leaf 0))))) (.node (.node (.node (.node (.leaf 165282826900437582495745) (.leaf 232407526340175367539272026115)) (.node (.leaf 208148011917968392784210657282) (.leaf 158611256649459749893448003079))) (.node (.node (.leaf 158611218806126394638141226248) (.leaf 166040070361150215203563106822)) (.node (.leaf 158527481646956437791885315) (.leaf 160469340147445652722605489159)))) (.node (.node (.node (.leaf 295248699369563195563441192961) (.leaf 158633022036579296088036600838)) (.node (.leaf 200840055338398170529344358403) (.leaf 160487509521501636848924093446))) (.node (.node (.leaf 159230191182331650585118506504) (.leaf 160471762726054078922864327687)) (.node (.leaf 168978815583815336408446476803) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 172366376624742050316289) (.leaf 180974986270490583930572474371)) (.node (.leaf 170632646564604028930) (.leaf 158693274641512114607198681606))) (.node (.node (.leaf 158612427727316308850513149448) (.leaf 158708990746189202444244856326)) (.node (.leaf 189415067140233218) (.leaf 158611218819979554915558226439)))) (.node (.node (.node (.leaf 247588007857076054979824910337) (.leaf 161093157759131279900733990917)) (.node (.leaf 246621070367770741577920515) (.leaf 158611225880434767725976484871))) (.node (.node (.leaf 159851581419399507895617060104) (.leaf 158630604194163421239996312839)) (.node (.leaf 162158981472230418403084291) (.leaf 0))))) (.node (.node (.node (.node (.leaf 199308346324946224258759065601) (.leaf 163649870584789109301940691972)) (.node (.leaf 169597785603458026545694711810) (.leaf 160468128855813201622988879878))) (.node (.node (.leaf 158611228241654002601781623560) (.leaf 159231400181785189353106041350)) (.node (.leaf 159365437244879105024885622787) (.leaf 160468128855813096276031044615)))) (.node (.node (.node (.leaf 266776078465999449240761335809) (.leaf 158649979833447555888794688006)) (.node (.leaf 236682288038332485194800529410) (.leaf 160470551517296745158256225286))) (.node (.node (.leaf 158611221162688960482028682760) (.leaf 159231400122022422297899563527)) (.node (.leaf 235740534825046443632397315) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 228698418579457) (.leaf 236132226790407828920510546435)) (.node (.leaf 295248699369563195563642520066) (.leaf 158611221176551092739834509831))) (.node (.node (.leaf 158611221158068267229919706632) (.leaf 158617275241140745189432883206)) (.node (.leaf 160959500385370422286270466) (.leaf 158611218893586369633182673414)))) (.node (.node (.node (.leaf 241785163922925834941267969) (.leaf 194828312800670019433319941)) (.node (.leaf 168978815597650394463527313410) (.leaf 168611302074700834782369130500))) (.node (.node (.leaf 168534081924137769280823619336) (.leaf 161087108324809427572310014471)) (.node (.leaf 170821797748953593859) (.leaf 0))))) (.node (.node (.node (.node (.leaf 230584300921369403393) (.leaf 159927587981584208512493398020)) (.node (.leaf 163711525566393468450053915651) (.leaf 158527758347853660644499459))) (.node (.node (.leaf 159849163558536871347321306376) (.leaf 158654824981422951347764976134)) (.node (.leaf 184002287638532856106500098) (.leaf 159868539501858946677114924295)))) (.node (.node (.node (.leaf 234589637444579562093384105985) (.leaf 158692065711071736631914511366)) (.node (.leaf 162474794452927702563811328002) (.leaf 160471762730683849468027205638))) (.node (.node (.leaf 159231397746959016614575603208) (.leaf 159231400126625101117072210439)) (.node (.leaf 198560753420515846154243) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 194637056957955297127727105) (.leaf 173561853365974395609556295683)) (.node (.leaf 158548732295865468404678658) (.leaf 235740737991239079005564931))) (.node (.node (.leaf 158611223519251491141141658888) (.leaf 158620899777157843428562952966)) (.node (.leaf 193852221784595250569218) (.leaf 160469340152048331541778136071)))) (.node (.node (.node (.leaf 305771189703488927900083748865) (.leaf 171030591513115063517433678341)) (.node (.leaf 179128805428211382245965826) (.leaf 168514776889955815797802790407))) (.node (.node (.leaf 159231400103539579230158454280) (.leaf 158633022036579278461490949383)) (.node (.leaf 175488082230847770300833795) (.leaf 0))))) (.node (.node (.node (.node (.leaf 198339392280525098991617) (.leaf 167915185174962399042651414532)) (.node (.leaf 175485721047606335478226947) (.leaf 166038859069526665921816687367))) (.node (.node (.leaf 161091934578734227131969305352) (.leaf 158612432445071158478154890247)) (.node (.leaf 158456325028528833688762387972) (.leaf 0)))) (.node (.node (.node (.leaf 299870271662222471086081) (.leaf 166040070379560930480253694470)) (.node (.leaf 177895852207931912316363309058) (.leaf 158611218875139643151592057350))) (.node (.node (.leaf 176734565621396472122621954) (.leaf 160469342517861308646629178375)) (.node (.leaf 179128956543938834074764935683) (.leaf 0))))))) +noncomputable def tab_5 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 161409010644958584833) (.leaf 198925117130664605971302686723)) (.node (.leaf 251456791840771752853544962) (.leaf 200778400342958753326083320582))) (.node (.node (.leaf 158612427722704622866445499912) (.leaf 158625726035703336205971350278)) (.node (.leaf 197664207210270328581158699010) (.leaf 158612432445098127299360979975)))) (.node (.node (.node (.leaf 173311605499953238485877456897) (.leaf 208206040578671087751901849604)) (.node (.leaf 225972614903143342594) (.leaf 178534165040832710210358451718))) (.node (.node (.leaf 158630561683641703376468832008) (.leaf 163572650365203998816166082055)) (.node (.leaf 170857562663383216643) (.leaf 0))))) (.node (.node (.node (.node (.leaf 193690812773950300161) (.leaf 160610630839082208259205072899)) (.node (.leaf 301438399565990308044169349122) (.leaf 160470549068635549308297542663))) (.node (.node (.leaf 158611223528474863109276957960) (.leaf 158712617523648116563007220486)) (.node (.leaf 208060826407370032701442) (.leaf 160469342513240597802401266695)))) (.node (.node (.node (.leaf 308866039801702378587331559425) (.leaf 158690856785252227315338033414)) (.node (.leaf 167933094819023972448535158787) (.leaf 158630618388932845222142142215))) (.node (.node (.leaf 159231397746968006221644299784) (.leaf 158611259010642973701724827143)) (.node (.leaf 161580411313589336067) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 191255842556220631171073) (.leaf 171071466232908491730790227971)) (.node (.leaf 234531834977852962835046402) (.leaf 188341197962993627003856604935))) (.node (.node (.leaf 159231397742347312969535323656) (.leaf 158635444541409770544581175814)) (.node (.leaf 162170787388226486283583490) (.leaf 158630599462573566368057257479)))) (.node (.node (.node (.leaf 277298568799925181577403891713) (.leaf 180914731235352408692669663749)) (.node (.leaf 169429341373558236620316675) (.leaf 188321892928811673520835776006))) (.node (.node (.leaf 158613641380132142019227417864) (.leaf 158611218819943508526420326919)) (.node (.leaf 225972843601561922051) (.leaf 0))))) (.node (.node (.node (.node (.leaf 179449926349046518136833) (.leaf 158649979833258457480801929220)) (.node (.leaf 158527481646692555001217026) (.leaf 158616063949517125539210590727))) (.node (.node (.leaf 158616054518610210655880608520) (.leaf 158613639009707478999028071431)) (.node (.leaf 168611301913291824137410545667) (.leaf 0)))) (.node (.node (.node (.leaf 217258476894584238244796366849) (.leaf 158617301278557875644080974342)) (.node (.leaf 294010759606978976394185351170) (.leaf 158616066306079761717214181895))) (.node (.node (.leaf 162158981472019312170549250) (.leaf 179075917284939764543351021063)) (.node (.leaf 169229063228475564647409360899) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 160787134008745680235954177) (.leaf 173547346256139020059459821571)) (.node (.leaf 291534879473067983623258447874) (.leaf 236949695840665364271769603))) (.node (.node (.leaf 158611221158077256836988403208) (.leaf 158670571712306887561094221318)) (.node (.leaf 170632593788247222787) (.leaf 158613639009734500493713079303)))) (.node (.node (.node (.leaf 212770944252174734748319745) (.leaf 169774482403982881998728456197)) (.node (.leaf 198925116840128386810377240578) (.leaf 158611218810720083918964521991))) (.node (.node (.leaf 198302520190745061438217502472) (.leaf 158616073389737343714320446215)) (.node (.leaf 162921643870109193751043) (.leaf 0))))) (.node (.node (.node (.node (.leaf 231395957660612615487489) (.leaf 164328077734396929260635915780)) (.node (.leaf 188341197962993486128794943491) (.leaf 158669360425304049123642691078))) (.node (.node (.leaf 158611228241618044173506837256) (.leaf 160472974022307398749706647558)) (.node (.leaf 235827577483864942368484557314) (.leaf 178456944904104825771824111111)))) (.node (.node (.node (.leaf 271727838623140970340357832705) (.leaf 161169154720082804788252752390)) (.node (.leaf 310722949860630712882470914050) (.leaf 169134955840029806582854446599))) (.node (.node (.leaf 159230191177719964601050856968) (.leaf 159250778412647574745294958087)) (.node (.leaf 179119637396406748598820867) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 238303457562435702918081478657) (.leaf 200792907521969208046223728643)) (.node (.leaf 236949718898884350176174082) (.leaf 158616063958758582343117699078))) (.node (.node (.leaf 158611218806108415424003833096) (.leaf 160472974026937046390085384198)) (.node (.leaf 191491038543160427962370) (.leaf 158611218815385900887692278023)))) (.node (.node (.node (.leaf 307067158182115810375401473) (.leaf 230488961064446951039147674373)) (.node (.leaf 203335656019401183611371522) (.leaf 159249569482216274063266016775))) (.node (.node (.leaf 159231400108151247622107168264) (.leaf 160469340147436663115536792583)) (.node (.leaf 176694646867220964652933123) (.leaf 0))))) (.node (.node (.node (.node (.leaf 198263834416799184651845633) (.leaf 166119705960727021749641785348)) (.node (.leaf 170830541065417666562) (.leaf 158689647937687054395809836550))) (.node (.node (.leaf 163562978954098446159057254152) (.leaf 158611225885064432924181527559)) (.node (.leaf 162463914120551434784029640707) (.leaf 0)))) (.node (.node (.node (.leaf 158611218801496694221405552136) (.leaf 158702946098788359537743344390)) (.node (.leaf 218127694558887156621410140162) (.leaf 160472974017659631157702162438))) (.node (.node (.leaf 170835725642743406820593836034) (.leaf 158611218824609237740174964999)) (.node (.leaf 169225436229655791875571941891) (.leaf 0))))))) +noncomputable def tab_n10 : SSC.Trie := .node tab_4 tab_5 +noncomputable def tab_6 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 193514046490625) (.leaf 238303457839136864023926088195)) (.node (.leaf 240160367621363984436662700034) (.leaf 200778400347570439344577686021))) (.node (.node (.leaf 158611218801496694255698181640) (.leaf 166038887371416739412999008774)) (.node (.leaf 197451700718541194546542362626) (.leaf 161088310180905368753044322823)))) (.node (.node (.node (.leaf 207784125246264389419009) (.leaf 160603377284164415137199000580)) (.node (.leaf 193915992755318829058) (.leaf 158633017323436167628700511495))) (.node (.node (.leaf 163572650360583305598416975624) (.leaf 161088310162494653476353735175)) (.node (.leaf 162161342655524629783824387) (.leaf 0))))) (.node (.node (.node (.node (.leaf 162170145146384816011785338881) (.leaf 203254280490704593045925502979)) (.node (.leaf 275441658740997111165256532482) (.leaf 198921490210387751575734042119))) (.node (.node (.leaf 158613636648542251859635862792) (.leaf 158631780054194353976306166278)) (.node (.leaf 198462173809079709750837250) (.leaf 158612432458906163756878920711)))) (.node (.node (.node (.leaf 235827577483864942368283230209) (.leaf 160469340230293871467713129478)) (.node (.leaf 200792907231432988885298282498) (.leaf 159249569482216256505439710727))) (.node (.node (.leaf 159231400108142240457212165640) (.leaf 160470551439060194839389928455)) (.node (.leaf 159308617957329762159872290310) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 164027055205312886424134025217) (.leaf 171085973342743867280886702083)) (.node (.leaf 233322913769924352087728130) (.leaf 158616054504784230168664340999))) (.node (.node (.leaf 158612430083887864266908368392) (.leaf 160474187670493443471968434182)) (.node (.leaf 193888971157554606082) (.leaf 158630599462573601586587888903)))) (.node (.node (.node (.leaf 217877446914226928382245928961) (.leaf 198921490238111981112930711557)) (.node (.leaf 158369282369780304677210114) (.leaf 168534081924137786907436379655))) (.node (.node (.leaf 159851576697051039424481328392) (.leaf 158611230602801285608396421639)) (.node (.leaf 165795203663828939186422275) (.leaf 0))))) (.node (.node (.node (.node (.leaf 252201579132751873) (.leaf 161167945881732154898224621572)) (.node (.leaf 193754564660226) (.leaf 158649979833402467287761542663))) (.node (.node (.leaf 161087098875491797412289444616) (.leaf 188381019318360442913733856774)) (.node (.leaf 160603377284164256841884337155) (.leaf 0)))) (.node (.node (.node (.leaf 288933270887896372754808833) (.leaf 160472974022334367570912737286)) (.node (.leaf 308866039801702572101378050050) (.leaf 159854003984199897363480049927))) (.node (.node (.leaf 198921490062669542922853122050) (.leaf 158631770609461318005710515719)) (.node (.leaf 158527716842679494798008323) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 170632382681813360641) (.leaf 199540460372848452221228130307)) (.node (.leaf 308866039801702378827849729026) (.leaf 290142196707704756494175235))) (.node (.node (.leaf 159230188816527715932546661896) (.leaf 158612432445071228709460113414)) (.node (.leaf 198422266394974210) (.leaf 158611218819988544522626923015)))) (.node (.node (.node (.leaf 242636247699934533880228413441) (.leaf 199540460253133978032698144773)) (.node (.leaf 234531839589538981262434306) (.leaf 158611218810720189265922357254))) (.node (.node (.leaf 178418334835740865925944172296) (.leaf 158611218806117440215444487175)) (.node (.leaf 175442438190077589507) (.leaf 0))))) (.node (.node (.node (.node (.leaf 176503169663735859507134465) (.leaf 158746467225236344518893210116)) (.node (.leaf 167741064508364561195565408259) (.leaf 213035396775479317670971395))) (.node (.node (.leaf 158611218796921107231235373832) (.leaf 158626965527921996160015921670)) (.node (.leaf 203254280200168373885000056834) (.leaf 161707280186749047224416729607)))) (.node (.node (.node (.leaf 301438399565990096937936814081) (.leaf 164270049447394188055684429318)) (.node (.leaf 158746467225236186361017501188) (.leaf 160471762730683744121069370375))) (.node (.node (.leaf 158612430088499567911948647944) (.leaf 159235036330343145072412981767)) (.node (.leaf 198462173809290815983372291) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 233322683185623430718324737) (.leaf 240160367856559971376459491331)) (.node (.leaf 164646025224955576767742018562) (.leaf 235740682543061341747330053))) (.node (.node (.leaf 159849158836170388546395569416) (.leaf 158620909116011181928440001030)) (.node (.leaf 176503404859722799303925762) (.leaf 158616068667263020744088746247)))) (.node (.node (.node (.leaf 276060628760639801302504767489) (.leaf 168542591702326999684065912837)) (.node (.leaf 179129026789140266760593411) (.leaf 160487509521501689522403011590))) (.node (.node (.leaf 159230191182331650619411136008) (.leaf 159236242894979518266765081095)) (.node (.leaf 175488096065905825582997507) (.leaf 0))))) (.node (.node (.node (.node (.leaf 170835725421382477936079208449) (.leaf 167915149826389067796723130372)) (.node (.leaf 233322909158238333660340226) (.leaf 159927587976972540086252054532))) (.node (.node (.leaf 158611237686422856538041612040) (.leaf 158611247149602566213602636551)) (.node (.leaf 158630599462573425458568880132) (.leaf 0)))) (.node (.node (.node (.leaf 158611218796885025795164208648) (.leaf 166040070319708091432499802630)) (.node (.leaf 187818715335328788582351601666) (.leaf 161789333665545127147063065094))) (.node (.node (.leaf 199540460082312233060302684162) (.leaf 158622120379910572041465624071)) (.node (.leaf 169229063242310622702691524611) (.leaf 0))))))) +noncomputable def tab_7 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.leaf 158369282369516421886541825) (.leaf 198925117116829547916020523011)) (.node (.leaf 236678661260873641307276410882) (.leaf 158616063944905509889527380487))) (.node (.node (.leaf 158611218796894032994351840776) (.leaf 158611218884362945025726868486)) (.node (.leaf 170857562663181889538) (.leaf 160472981105857070277616334854)))) (.node (.node (.node (.leaf 203099537695257701350670337) (.leaf 160950226474202431949436933)) (.node (.leaf 169597785617293084600976875522) (.leaf 158611218796912065019272887303))) (.node (.node (.leaf 158630599388786590038792335112) (.leaf 159230191196193782877216963079)) (.node (.leaf 189268277940073804291) (.leaf 0))))) (.node (.node (.node (.node (.leaf 166831763106818826109485057) (.leaf 160607004061623276616909163524)) (.node (.leaf 160607004061623100660688978947) (.leaf 158616063949517195907887659527))) (.node (.node (.leaf 159849158845393760514530868488) (.leaf 166049751175510581031813116422)) (.node (.leaf 178921242664105108603709443) (.leaf 160470551434448526413148584967)))) (.node (.node (.node (.leaf 294010759330277815288542068737) (.leaf 163564190351565593883265066502)) (.node (.leaf 307628099762417227010851014658) (.leaf 158645134906607698226670985990))) (.node (.node (.leaf 158612430088508557519017344520) (.leaf 160468128855813113833857350663)) (.node (.leaf 235196180694361451523) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 168978815362454407523730522113) (.leaf 181033014709832086130958370819)) (.node (.leaf 161661212224091336706) (.leaf 269590679134991190474137602))) (.node (.node (.leaf 158611218796903022670005927176) (.leaf 158692065711071754189740817414)) (.node (.leaf 233322909158238333861667331) (.leaf 160469342508619886958173355015)))) (.node (.node (.node (.leaf 313198829939201209549478494209) (.leaf 171014845017273974401622206469)) (.node (.leaf 171085973287403635059758047235) (.leaf 158614845574343887309032782855))) (.node (.node (.leaf 159231400108151247656399797768) (.leaf 158635444610584990452180839175)) (.node (.leaf 176697021885520454757703683) (.leaf 0))))) (.node (.node (.node (.node (.leaf 165883965264240956836482711553) (.leaf 166119706002151131122195607556)) (.node (.leaf 160607004061623276410750732291) (.leaf 158620909097528409195150439943))) (.node (.node (.leaf 158616063944896432321461484296) (.leaf 158611218801514708722792922119)) (.node (.leaf 188167150423901106367589599235) (.leaf 0)))) (.node (.node (.node (.leaf 197451436266018153846410379265) (.leaf 160476600799766189860672632838)) (.node (.leaf 234836258311780946445024198658) (.leaf 159851576706292460838059243783))) (.node (.node (.leaf 165797564847070373807702018) (.leaf 160470549082497681840981277703)) (.node (.leaf 169844406470659410897334804483) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 225179981368528897) (.leaf 203254280435364360824796848131)) (.node (.leaf 232113757366009012649818392578) (.leaf 188457028168085453661658124038))) (.node (.node (.leaf 159230188816536705539615358472) (.leaf 158630606559958348693246176262)) (.node (.leaf 161996059828624192201328642) (.leaf 158631810675789446102856625671)))) (.node (.node (.node (.leaf 251456570479842868338917377) (.leaf 238303656123189123434128960005)) (.node (.leaf 161409274527749253122) (.leaf 188379808031357586849736543750))) (.node (.node (.leaf 159851581419417522225407065352) (.leaf 158616073444969489544392209159)) (.node (.leaf 162158981472283194961217539) (.leaf 0))))) (.node (.node (.node (.node (.leaf 179501305696380139860373078017) (.leaf 158746467225236344690490575876)) (.node (.leaf 198921490353205762083778568195) (.leaf 166038859161580242305269621510))) (.node (.node (.leaf 161087098875455838984014658312) (.leaf 160475394235129816666320533510)) (.node (.leaf 232345871123374810345129476098) (.leaf 161707287270271749931120327175)))) (.node (.node (.node (.leaf 298604677444813406152458241) (.leaf 158692065711071789305393429510)) (.node (.leaf 295867669624401872640687546370) (.leaf 158752511854334470441324874244))) (.node (.node (.leaf 159230188821148409184655638024) (.leaf 160468128860442779032062393351)) (.node (.leaf 183964730067598783459418115) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 198158383604305921) (.leaf 200792907466628975825095073795)) (.node (.leaf 178921298004126223499829250) (.leaf 158612430139336042004233712134))) (.node (.node (.leaf 158613636648524272645498469640) (.leaf 158630627852112554897703166726)) (.node (.leaf 196075017551989104095313922) (.leaf 164183160297574430147566761479)))) (.node (.node (.node (.leaf 310103979840987758862230683649) (.leaf 158635444610585008044433861126)) (.node (.leaf 236949460644678424474978306) (.leaf 158630608925753276009191566087))) (.node (.node (.leaf 159231400103539579195865824776) (.leaf 158635444536798084526086810375)) (.node (.leaf 194866091732374475121934851) (.leaf 0))))) (.node (.node (.node (.node (.leaf 236949460644467318242443265) (.leaf 160471784096453772173484613636)) (.node (.leaf 170830752171650201603) (.leaf 158630601828368493786880404999))) (.node (.node (.leaf 158620890240335272646239581960) (.leaf 158614845583576231326410472455)) (.node (.leaf 217508724829780685644886024195) (.leaf 0)))) (.node (.node (.node (.leaf 158612427722704622832152870408) (.leaf 166053366147053217745224200710)) (.node (.leaf 158456514144549182740201826308) (.leaf 159235033969150878846082480647))) (.node (.node (.leaf 183955063973704159654363138) (.leaf 305858232362501181402022402)) (.node (.leaf 169225436451016720759885242371) (.leaf 0))))))) +noncomputable def tab_n11 : SSC.Trie := .node tab_6 tab_7 +noncomputable def tab_n1 : SSC.Trie := .node tab_n10 tab_n11 +noncomputable def tab : SSC.Trie := .node tab_n0 tab_n1 +noncomputable def st0_0 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 2) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 66) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 34) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 98) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 18) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 82) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 50) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 114) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 10) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 74) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 42) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 106) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 26) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 90) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 58) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 6) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 70) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 38) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 102) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 22) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 86) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 54) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 118) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 14) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 78) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 46) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 110) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 30) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 94) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 62) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) +noncomputable def st0_1 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 4) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 68) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 36) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 100) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 20) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 84) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 52) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 116) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 12) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 76) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 44) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 108) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 28) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 92) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 60) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 8) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 72) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 40) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 104) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 24) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 88) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 56) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 120) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 16) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 80) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 48) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 112) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 32) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 96) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 64) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) +noncomputable def st0_n0 : SSC.Trie := .node st0_0 st0_1 +noncomputable def st0_2 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 3) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 67) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 35) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 99) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 19) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 83) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 51) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 115) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 11) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 75) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 43) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 107) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 27) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 91) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 59) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 7) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 71) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 39) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 103) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 23) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 87) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 55) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 119) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 15) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 79) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 47) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 111) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 31) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 95) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 63) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) +noncomputable def st0_3 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 5) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 69) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 37) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 101) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 21) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 85) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 53) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 117) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 13) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 77) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 45) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 109) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 29) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 93) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 61) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 9) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 73) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 41) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 105) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 25) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 89) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 57) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 121) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 17) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 81) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 49) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 113) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 33) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 97) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))))) (.node (.node (.node (.node (.leaf 65) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 0) (.leaf 0)))))))) +noncomputable def st0_n1 : SSC.Trie := .node st0_2 st0_3 +noncomputable def st0 : SSC.Trie := .node st0_n0 st0_n1 +noncomputable def st1_0 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 497)) (.node (.leaf 300) (.leaf 495))) (.node (.node (.leaf 0) (.leaf 381)) (.node (.leaf 348) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 492)) (.node (.leaf 451) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 440)) (.node (.leaf 369) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 326)) (.node (.leaf 470) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 290)) (.node (.leaf 439) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 366)) (.node (.leaf 330) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 466)) (.node (.leaf 431) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 454)) (.node (.leaf 454) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 277)) (.node (.leaf 488) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 259)) (.node (.leaf 325) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 451)) (.node (.leaf 267) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 334)) (.node (.leaf 333) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 311)) (.node (.leaf 446) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 268)) (.node (.leaf 254) (.leaf 0))) (.node (.node (.leaf 487) (.leaf 482)) (.node (.leaf 118) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 474)) (.node (.leaf 449) (.leaf 337))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 354) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 257)) (.node (.leaf 455) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 447)) (.node (.leaf 367) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 250)) (.node (.leaf 412) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 432)) (.node (.leaf 446) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 369)) (.node (.leaf 336) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 314)) (.node (.leaf 382) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 458)) (.node (.leaf 400) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 282)) (.node (.leaf 491) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 361)) (.node (.leaf 327) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 458)) (.node (.leaf 375) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 300)) (.node (.leaf 459) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 357)) (.node (.leaf 362) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 376)) (.node (.leaf 350) (.leaf 0))) (.node (.node (.leaf 335) (.leaf 489)) (.node (.leaf 1) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 309)) (.node (.leaf 448) (.leaf 498))) (.node (.node (.leaf 0) (.leaf 384)) (.node (.leaf 420) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 494)) (.node (.leaf 457) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 445)) (.node (.leaf 364) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 474)) (.node (.leaf 314) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 292)) (.node (.leaf 357) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 367)) (.node (.leaf 333) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 470)) (.node (.leaf 377) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 245)) (.node (.leaf 462) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 279)) (.node (.leaf 493) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 261)) (.node (.leaf 471) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 455)) (.node (.leaf 373) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 338)) (.node (.leaf 316) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 295)) (.node (.leaf 359) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 269)) (.node (.leaf 489) (.leaf 0))) (.node (.node (.leaf 485) (.leaf 486)) (.node (.leaf 120) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 482)) (.node (.leaf 444) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 347) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 258)) (.node (.leaf 466) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 313)) (.node (.leaf 266) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 332)) (.node (.leaf 315) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 436)) (.node (.leaf 261) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 0)) (.node (.leaf 340) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 478)) (.node (.leaf 384) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 467)) (.node (.leaf 469) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 286)) (.node (.leaf 354) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 263)) (.node (.leaf 475) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 462)) (.node (.leaf 373) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 344)) (.node (.leaf 322) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 299)) (.node (.leaf 367) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 489) (.leaf 0))) (.node (.node (.leaf 309) (.leaf 492)) (.node (.leaf 1) (.leaf 0)))))))) +noncomputable def st1_1 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 500)) (.node (.leaf 469) (.leaf 497))) (.node (.node (.leaf 0) (.leaf 383)) (.node (.leaf 254) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 494)) (.node (.leaf 440) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 444)) (.node (.leaf 93) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 327)) (.node (.leaf 329) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 291)) (.node (.leaf 438) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 264)) (.node (.leaf 332) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 468)) (.node (.leaf 111) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 320)) (.node (.leaf 397) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 278)) (.node (.leaf 348) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 301)) (.node (.leaf 328) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 319)) (.node (.leaf 374) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 337)) (.node (.leaf 332) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 360)) (.node (.leaf 262) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 374)) (.node (.leaf 288) (.leaf 0))) (.node (.node (.leaf 307) (.leaf 484)) (.node (.leaf 387) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 315)) (.node (.leaf 321) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 390)) (.node (.leaf 344) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 352)) (.node (.leaf 462) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 448)) (.node (.leaf 368) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 330)) (.node (.leaf 327) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 434)) (.node (.leaf 442) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 266)) (.node (.leaf 341) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 477)) (.node (.leaf 115) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 467)) (.node (.leaf 445) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 284)) (.node (.leaf 351) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 362)) (.node (.leaf 478) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 461)) (.node (.leaf 106) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 253)) (.node (.leaf 450) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 378)) (.node (.leaf 368) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 271)) (.node (.leaf 349) (.leaf 0))) (.node (.node (.leaf 499) (.leaf 490)) (.node (.leaf 1) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 475)) (.node (.leaf 318) (.leaf 341))) (.node (.node (.leaf 0) (.leaf 386)) (.node (.leaf 355) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 350)) (.node (.leaf 323) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 446)) (.node (.leaf 366) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 476)) (.node (.leaf 479) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 430)) (.node (.leaf 500) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 265)) (.node (.leaf 485) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 472)) (.node (.leaf 381) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 458)) (.node (.leaf 463) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 281)) (.node (.leaf 349) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 301)) (.node (.leaf 477) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 397)) (.node (.leaf 376) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 340)) (.node (.leaf 319) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 297)) (.node (.leaf 361) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 270)) (.node (.leaf 486) (.leaf 0))) (.node (.node (.leaf 280) (.leaf 346)) (.node (.leaf 121) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 317)) (.node (.leaf 453) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 275)) (.node (.leaf 495) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 355)) (.node (.leaf 444) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 450)) (.node (.leaf 100) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 251)) (.node (.leaf 483) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 438)) (.node (.leaf 442) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 372)) (.node (.leaf 440) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 480)) (.node (.leaf 386) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 300)) (.node (.leaf 472) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 288)) (.node (.leaf 355) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 364)) (.node (.leaf 477) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 465)) (.node (.leaf 374) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 345)) (.node (.leaf 468) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 388)) (.node (.leaf 370) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 380)) (.node (.leaf 491) (.leaf 0))) (.node (.node (.leaf 417) (.leaf 493)) (.node (.leaf 1) (.leaf 0)))))))) +noncomputable def st1_n0 : SSC.Trie := .node st1_0 st1_1 +noncomputable def st1_2 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 307)) (.node (.leaf 8) (.leaf 496))) (.node (.node (.leaf 0) (.leaf 382)) (.node (.leaf 306) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 348)) (.node (.leaf 468) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 442)) (.node (.leaf 429) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 248)) (.node (.leaf 481) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 428)) (.node (.leaf 260) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 366)) (.node (.leaf 331) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 467)) (.node (.leaf 376) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 456)) (.node (.leaf 455) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 277)) (.node (.leaf 495) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 260)) (.node (.leaf 331) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 452)) (.node (.leaf 371) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 335)) (.node (.leaf 278) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 294)) (.node (.leaf 442) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 373)) (.node (.leaf 487) (.leaf 0))) (.node (.node (.leaf 435) (.leaf 407)) (.node (.leaf 437) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 476)) (.node (.leaf 461) (.leaf 501))) (.node (.node (.leaf 0) (.leaf 388)) (.node (.leaf 498) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 351)) (.node (.leaf 466) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 447)) (.node (.leaf 428) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 250)) (.node (.leaf 479) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 433)) (.node (.leaf 298) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 370)) (.node (.leaf 338) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 476)) (.node (.leaf 385) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 456)) (.node (.leaf 440) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 282)) (.node (.leaf 350) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 361)) (.node (.leaf 305) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 460)) (.node (.leaf 271) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 343)) (.node (.leaf 454) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 358)) (.node (.leaf 365) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 271)) (.node (.leaf 286) (.leaf 0))) (.node (.node (.leaf 279) (.leaf 347)) (.node (.leaf 1) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 441)) (.node (.leaf 452) (.leaf 499))) (.node (.node (.leaf 0) (.leaf 386)) (.node (.leaf 498) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 492)) (.node (.leaf 453) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 445)) (.node (.leaf 365) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 480)) (.node (.leaf 472) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 293)) (.node (.leaf 78) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 368)) (.node (.leaf 334) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 471)) (.node (.leaf 379) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 465)) (.node (.leaf 461) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 280)) (.node (.leaf 490) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 358)) (.node (.leaf 474) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 456)) (.node (.leaf 430) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 339)) (.node (.leaf 432) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 296)) (.node (.leaf 432) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 270)) (.node (.leaf 346) (.leaf 0))) (.node (.node (.leaf 334) (.leaf 487)) (.node (.leaf 438) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 316)) (.node (.leaf 323) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 272)) (.node (.leaf 488) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 354)) (.node (.leaf 464) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 318)) (.node (.leaf 370) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 333)) (.node (.leaf 482) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 437)) (.node (.leaf 436) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 0)) (.node (.leaf 300) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 479)) (.node (.leaf 385) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 465)) (.node (.leaf 470) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 306)) (.node (.leaf 427) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 263)) (.node (.leaf 478) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 464)) (.node (.leaf 269) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 345)) (.node (.leaf 451) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 380)) (.node (.leaf 265) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 378)) (.node (.leaf 256) (.leaf 0))) (.node (.node (.leaf 339) (.leaf 423)) (.node (.leaf 1) (.leaf 0)))))))) +noncomputable def st1_3 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 308)) (.node (.leaf 433) (.leaf 302))) (.node (.node (.leaf 0) (.leaf 384)) (.node (.leaf 497) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 256)) (.node (.leaf 445) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 444)) (.node (.leaf 432) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 480)) (.node (.leaf 502) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 429)) (.node (.leaf 301) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 264)) (.node (.leaf 484) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 469)) (.node (.leaf 435) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 320)) (.node (.leaf 324) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 416)) (.node (.leaf 496) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 443)) (.node (.leaf 473) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 453)) (.node (.leaf 293) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 336)) (.node (.leaf 416) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 342)) (.node (.leaf 85) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 269)) (.node (.leaf 486) (.leaf 0))) (.node (.node (.leaf 434) (.leaf 417)) (.node (.leaf 389) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 243)) (.node (.leaf 449) (.leaf 303))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 352) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 353)) (.node (.leaf 324) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 449)) (.node (.leaf 369) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 331)) (.node (.leaf 481) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 435)) (.node (.leaf 447) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 266)) (.node (.leaf 339) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 412)) (.node (.leaf 436) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 247)) (.node (.leaf 315) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 285)) (.node (.leaf 352) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 363)) (.node (.leaf 473) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 322)) (.node (.leaf 434) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 254)) (.node (.leaf 459) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 298)) (.node (.leaf 501) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 490) (.leaf 0))) (.node (.node (.leaf 338) (.leaf 491)) (.node (.leaf 1) (.leaf 0)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 312)) (.node (.leaf 448) (.leaf 500))) (.node (.node (.leaf 0) (.leaf 0)) (.node (.leaf 284) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 257)) (.node (.leaf 457) (.leaf 304))) (.node (.node (.leaf 0) (.leaf 446)) (.node (.leaf 95) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 329)) (.node (.leaf 474) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 431)) (.node (.leaf 437) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 265)) (.node (.leaf 335) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 473)) (.node (.leaf 113) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 454)) (.node (.leaf 464) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 281)) (.node (.leaf 493) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 360)) (.node (.leaf 471) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 457)) (.node (.leaf 292) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 342)) (.node (.leaf 450) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 372)) (.node (.leaf 87) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 375)) (.node (.leaf 496) (.leaf 0))) (.node (.node (.leaf 308) (.leaf 488)) (.node (.leaf 439) (.leaf 0))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 317)) (.node (.leaf 452) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 305)) (.node (.leaf 255) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 259)) (.node (.leaf 294) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 321)) (.node (.leaf 433) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 251)) (.node (.leaf 484) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 439)) (.node (.leaf 447) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 268)) (.node (.leaf 55) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 481)) (.node (.leaf 117) (.leaf 0)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 325)) (.node (.leaf 313) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 427)) (.node (.leaf 499) (.leaf 0)))) (.node (.node (.node (.leaf 1) (.leaf 364)) (.node (.leaf 329) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 400)) (.node (.leaf 375) (.leaf 0))))) (.node (.node (.node (.node (.leaf 1) (.leaf 255)) (.node (.leaf 463) (.leaf 0))) (.node (.node (.leaf 0) (.leaf 390)) (.node (.leaf 291) (.leaf 0)))) (.node (.node (.node (.leaf 0) (.leaf 381)) (.node (.leaf 423) (.leaf 0))) (.node (.node (.leaf 311) (.leaf 494)) (.node (.leaf 1) (.leaf 0)))))))) +noncomputable def st1_n1 : SSC.Trie := .node st1_2 st1_3 +noncomputable def st1 : SSC.Trie := .node st1_n0 st1_n1 +noncomputable def st2_0 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 198)) (.node (.leaf 208) (.leaf 155))) (.node (.node (.leaf 130) (.leaf 194)) (.node (.leaf 179) (.leaf 152)))) (.node (.node (.node (.leaf 1) (.leaf 679)) (.node (.leaf 451) (.leaf 145))) (.node (.node (.leaf 194) (.leaf 743)) (.node (.leaf 219) (.leaf 195))))) (.node (.node (.node (.node (.leaf 1) (.leaf 233)) (.node (.leaf 124) (.leaf 189))) (.node (.node (.leaf 162) (.leaf 503)) (.node (.leaf 240) (.leaf 178)))) (.node (.node (.node (.leaf 1) (.leaf 557)) (.node (.leaf 206) (.leaf 645))) (.node (.node (.leaf 226) (.leaf 156)) (.node (.leaf 546) (.leaf 921)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 151)) (.node (.leaf 157) (.leaf 589))) (.node (.node (.leaf 146) (.leaf 886)) (.node (.leaf 488) (.leaf 158)))) (.node (.node (.node (.leaf 1) (.leaf 691)) (.node (.leaf 206) (.leaf 216))) (.node (.node (.leaf 210) (.leaf 151)) (.node (.leaf 123) (.leaf 133))))) (.node (.node (.node (.node (.leaf 1) (.leaf 202)) (.node (.leaf 169) (.leaf 603))) (.node (.node (.leaf 178) (.leaf 727)) (.node (.leaf 198) (.leaf 241)))) (.node (.node (.node (.leaf 1) (.leaf 677)) (.node (.leaf 728) (.leaf 201))) (.node (.node (.leaf 209) (.leaf 171)) (.node (.leaf 232) (.leaf 163))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 144)) (.node (.leaf 449) (.leaf 147))) (.node (.node (.leaf 138) (.leaf 794)) (.node (.leaf 184) (.leaf 220)))) (.node (.node (.node (.leaf 1) (.leaf 208)) (.node (.leaf 455) (.leaf 923))) (.node (.node (.leaf 202) (.leaf 671)) (.node (.leaf 167) (.leaf 210))))) (.node (.node (.node (.node (.leaf 1) (.leaf 661)) (.node (.leaf 127) (.leaf 666))) (.node (.node (.leaf 170) (.leaf 726)) (.node (.leaf 239) (.leaf 198)))) (.node (.node (.node (.leaf 1) (.leaf 166)) (.node (.leaf 232) (.leaf 164))) (.node (.node (.leaf 234) (.leaf 180)) (.node (.leaf 205) (.leaf 144)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 458)) (.node (.leaf 724) (.leaf 651))) (.node (.node (.leaf 154) (.leaf 639)) (.node (.leaf 491) (.leaf 241)))) (.node (.node (.node (.leaf 1) (.leaf 726)) (.node (.leaf 209) (.leaf 843))) (.node (.node (.leaf 218) (.leaf 185)) (.node (.leaf 230) (.leaf 227))))) (.node (.node (.node (.node (.leaf 1) (.leaf 214)) (.node (.leaf 459) (.leaf 149))) (.node (.node (.leaf 186) (.leaf 628)) (.node (.leaf 175) (.leaf 173)))) (.node (.node (.node (.leaf 122) (.leaf 185)) (.node (.leaf 189) (.leaf 212))) (.node (.node (.leaf 722) (.leaf 170)) (.node (.leaf 1) (.leaf 136)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 816)) (.node (.leaf 448) (.leaf 161))) (.node (.node (.leaf 134) (.leaf 633)) (.node (.leaf 615) (.leaf 163)))) (.node (.node (.node (.leaf 1) (.leaf 494)) (.node (.leaf 744) (.leaf 189))) (.node (.node (.leaf 198) (.leaf 663)) (.node (.leaf 175) (.leaf 183))))) (.node (.node (.node (.node (.leaf 1) (.leaf 142)) (.node (.leaf 239) (.leaf 130))) (.node (.node (.leaf 166) (.leaf 527)) (.node (.leaf 227) (.leaf 238)))) (.node (.node (.node (.leaf 1) (.leaf 507)) (.node (.leaf 592) (.leaf 215))) (.node (.node (.leaf 230) (.leaf 222)) (.node (.leaf 202) (.leaf 229)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 153)) (.node (.leaf 224) (.leaf 920))) (.node (.node (.leaf 150) (.leaf 635)) (.node (.leaf 673) (.leaf 205)))) (.node (.node (.node (.leaf 1) (.leaf 139)) (.node (.leaf 669) (.leaf 133))) (.node (.node (.leaf 214) (.leaf 177)) (.node (.leaf 228) (.leaf 134))))) (.node (.node (.node (.node (.leaf 1) (.leaf 197)) (.node (.leaf 206) (.leaf 135))) (.node (.node (.leaf 182) (.leaf 558)) (.node (.leaf 150) (.leaf 175)))) (.node (.node (.node (.leaf 1) (.leaf 221)) (.node (.leaf 489) (.leaf 234))) (.node (.node (.leaf 207) (.leaf 160)) (.node (.leaf 809) (.leaf 135))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 198)) (.node (.leaf 221) (.leaf 136))) (.node (.node (.leaf 142) (.leaf 811)) (.node (.leaf 648) (.leaf 196)))) (.node (.node (.node (.leaf 1) (.leaf 675)) (.node (.leaf 466) (.leaf 618))) (.node (.node (.leaf 206) (.leaf 207)) (.node (.leaf 522) (.leaf 215))))) (.node (.node (.node (.node (.leaf 1) (.leaf 593)) (.node (.leaf 828) (.leaf 230))) (.node (.node (.leaf 174) (.leaf 722)) (.node (.leaf 232) (.leaf 203)))) (.node (.node (.node (.leaf 1) (.leaf 198)) (.node (.leaf 239) (.leaf 208))) (.node (.node (.leaf 238) (.leaf 152)) (.node (.leaf 205) (.leaf 188)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 467)) (.node (.leaf 469) (.leaf 167))) (.node (.node (.leaf 158) (.leaf 601)) (.node (.leaf 224) (.leaf 226)))) (.node (.node (.node (.leaf 1) (.leaf 504)) (.node (.leaf 145) (.leaf 642))) (.node (.node (.leaf 222) (.leaf 717)) (.node (.leaf 192) (.leaf 195))))) (.node (.node (.node (.node (.leaf 1) (.leaf 784)) (.node (.leaf 211) (.leaf 796))) (.node (.node (.leaf 190) (.leaf 571)) (.node (.leaf 217) (.leaf 190)))) (.node (.node (.node (.leaf 126) (.leaf 781)) (.node (.leaf 127) (.leaf 139))) (.node (.node (.leaf 239) (.leaf 132)) (.node (.leaf 1) (.leaf 221)))))))) +noncomputable def st2_1 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 175)) (.node (.leaf 222) (.leaf 199))) (.node (.node (.leaf 132) (.leaf 629)) (.node (.leaf 859) (.leaf 166)))) (.node (.node (.node (.leaf 1) (.leaf 124)) (.node (.leaf 207) (.leaf 177))) (.node (.node (.leaf 196) (.leaf 676)) (.node (.leaf 768) (.leaf 128))))) (.node (.node (.node (.node (.leaf 1) (.leaf 660)) (.node (.leaf 164) (.leaf 132))) (.node (.node (.leaf 164) (.leaf 515)) (.node (.leaf 241) (.leaf 232)))) (.node (.node (.node (.leaf 1) (.leaf 505)) (.node (.leaf 211) (.leaf 150))) (.node (.node (.leaf 228) (.leaf 216)) (.node (.leaf 221) (.leaf 228)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 132)) (.node (.leaf 725) (.leaf 223))) (.node (.node (.leaf 148) (.leaf 594)) (.node (.leaf 222) (.leaf 128)))) (.node (.node (.node (.leaf 1) (.leaf 203)) (.node (.leaf 165) (.leaf 838))) (.node (.node (.leaf 212) (.leaf 162)) (.node (.leaf 227) (.leaf 184))))) (.node (.node (.node (.node (.leaf 1) (.leaf 682)) (.node (.leaf 148) (.leaf 142))) (.node (.node (.leaf 180) (.leaf 135)) (.node (.leaf 236) (.leaf 231)))) (.node (.node (.node (.leaf 1) (.leaf 182)) (.node (.leaf 616) (.leaf 184))) (.node (.node (.leaf 221) (.leaf 186)) (.node (.leaf 197) (.leaf 188))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 150)) (.node (.leaf 183) (.leaf 138))) (.node (.node (.leaf 140) (.leaf 577)) (.node (.leaf 221) (.leaf 123)))) (.node (.node (.node (.leaf 1) (.leaf 122)) (.node (.leaf 462) (.leaf 860))) (.node (.node (.leaf 204) (.leaf 211)) (.node (.leaf 508) (.leaf 219))))) (.node (.node (.node (.node (.leaf 1) (.leaf 774)) (.node (.leaf 143) (.leaf 935))) (.node (.node (.leaf 172) (.leaf 727)) (.node (.leaf 237) (.leaf 150)))) (.node (.node (.node (.leaf 1) (.leaf 523)) (.node (.leaf 689) (.leaf 170))) (.node (.node (.leaf 236) (.leaf 154)) (.node (.leaf 792) (.leaf 230)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 193)) (.node (.leaf 175) (.leaf 938))) (.node (.node (.leaf 156) (.leaf 692)) (.node (.leaf 221) (.leaf 205)))) (.node (.node (.node (.leaf 1) (.leaf 143)) (.node (.leaf 686) (.leaf 719))) (.node (.node (.leaf 220) (.leaf 233)) (.node (.leaf 779) (.leaf 240))))) (.node (.node (.node (.node (.leaf 1) (.leaf 602)) (.node (.leaf 450) (.leaf 798))) (.node (.node (.leaf 188) (.leaf 142)) (.node (.leaf 216) (.leaf 191)))) (.node (.node (.node (.leaf 124) (.leaf 239)) (.node (.leaf 719) (.leaf 213))) (.node (.node (.leaf 175) (.leaf 142)) (.node (.leaf 1) (.leaf 138)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 141)) (.node (.leaf 176) (.leaf 140))) (.node (.node (.leaf 136) (.leaf 572)) (.node (.leaf 194) (.leaf 206)))) (.node (.node (.node (.leaf 1) (.leaf 223)) (.node (.leaf 152) (.leaf 162))) (.node (.node (.leaf 200) (.leaf 672)) (.node (.leaf 128) (.leaf 192))))) (.node (.node (.node (.node (.leaf 1) (.leaf 736)) (.node (.leaf 479) (.leaf 141))) (.node (.node (.leaf 168) (.leaf 535)) (.node (.leaf 586) (.leaf 237)))) (.node (.node (.node (.leaf 1) (.leaf 510)) (.node (.leaf 723) (.leaf 875))) (.node (.node (.leaf 232) (.leaf 224)) (.node (.leaf 198) (.leaf 236)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 186)) (.node (.leaf 159) (.leaf 190))) (.node (.node (.leaf 152) (.leaf 640)) (.node (.leaf 716) (.leaf 123)))) (.node (.node (.node (.leaf 1) (.leaf 234)) (.node (.leaf 687) (.leaf 634))) (.node (.node (.leaf 216) (.leaf 201)) (.node (.leaf 229) (.leaf 136))))) (.node (.node (.node (.node (.leaf 1) (.leaf 812)) (.node (.leaf 217) (.leaf 670))) (.node (.node (.leaf 184) (.leaf 561)) (.node (.leaf 128) (.leaf 215)))) (.node (.node (.node (.leaf 1) (.leaf 605)) (.node (.leaf 123) (.leaf 210))) (.node (.node (.leaf 897) (.leaf 167)) (.node (.leaf 239) (.leaf 729))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 130)) (.node (.leaf 228) (.leaf 716))) (.node (.node (.leaf 144) (.leaf 882)) (.node (.leaf 495) (.leaf 165)))) (.node (.node (.node (.leaf 1) (.leaf 225)) (.node (.leaf 128) (.leaf 623))) (.node (.node (.leaf 208) (.leaf 153)) (.node (.leaf 206) (.leaf 189))))) (.node (.node (.node (.node (.leaf 1) (.leaf 587)) (.node (.leaf 233) (.leaf 148))) (.node (.node (.leaf 176) (.leaf 723)) (.node (.leaf 233) (.leaf 923)))) (.node (.node (.node (.leaf 1) (.leaf 562)) (.node (.leaf 440) (.leaf 185))) (.node (.node (.leaf 240) (.leaf 214)) (.node (.leaf 198) (.leaf 144)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 155)) (.node (.leaf 472) (.leaf 772))) (.node (.node (.leaf 160) (.leaf 622)) (.node (.leaf 665) (.leaf 235)))) (.node (.node (.node (.leaf 1) (.leaf 555)) (.node (.leaf 477) (.leaf 854))) (.node (.node (.leaf 224) (.leaf 163)) (.node (.leaf 532) (.leaf 199))))) (.node (.node (.node (.node (.leaf 1) (.leaf 719)) (.node (.leaf 468) (.leaf 818))) (.node (.node (.leaf 192) (.leaf 576)) (.node (.leaf 218) (.leaf 176)))) (.node (.node (.node (.leaf 128) (.leaf 573)) (.node (.leaf 585) (.leaf 157))) (.node (.node (.leaf 873) (.leaf 130)) (.node (.leaf 1) (.leaf 219)))))))) +noncomputable def st2_n0 : SSC.Trie := .node st2_0 st2_1 +noncomputable def st2_2 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 783)) (.node (.leaf 725) (.leaf 168))) (.node (.node (.leaf 131) (.leaf 564)) (.node (.leaf 597) (.leaf 199)))) (.node (.node (.node (.leaf 1) (.leaf 600)) (.node (.leaf 168) (.leaf 829))) (.node (.node (.leaf 195) (.leaf 736)) (.node (.leaf 520) (.leaf 148))))) (.node (.node (.node (.node (.leaf 1) (.leaf 681)) (.node (.leaf 174) (.leaf 225))) (.node (.node (.leaf 163) (.leaf 512)) (.node (.leaf 239) (.leaf 181)))) (.node (.node (.node (.leaf 1) (.leaf 559)) (.node (.leaf 833) (.leaf 235))) (.node (.node (.leaf 227) (.leaf 182)) (.node (.leaf 542) (.leaf 200)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 216)) (.node (.leaf 227) (.leaf 718))) (.node (.node (.leaf 147) (.leaf 612)) (.node (.leaf 122) (.leaf 197)))) (.node (.node (.node (.leaf 1) (.leaf 743)) (.node (.leaf 726) (.leaf 130))) (.node (.node (.leaf 211) (.leaf 204)) (.node (.leaf 122) (.leaf 131))))) (.node (.node (.node (.node (.leaf 1) (.leaf 199)) (.node (.leaf 200) (.leaf 604))) (.node (.node (.leaf 179) (.leaf 229)) (.node (.leaf 442) (.leaf 204)))) (.node (.node (.node (.leaf 1) (.leaf 598)) (.node (.leaf 487) (.leaf 748))) (.node (.node (.leaf 226) (.leaf 727)) (.node (.leaf 725) (.leaf 178))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 232)) (.node (.leaf 461) (.leaf 933))) (.node (.node (.leaf 139) (.leaf 575)) (.node (.leaf 239) (.leaf 197)))) (.node (.node (.node (.leaf 1) (.leaf 785)) (.node (.leaf 583) (.leaf 834))) (.node (.node (.leaf 203) (.leaf 655)) (.node (.leaf 511) (.leaf 212))))) (.node (.node (.node (.node (.leaf 1) (.leaf 236)) (.node (.leaf 125) (.leaf 144))) (.node (.node (.leaf 171) (.leaf 832)) (.node (.leaf 169) (.leaf 174)))) (.node (.node (.node (.leaf 1) (.leaf 149)) (.node (.leaf 847) (.leaf 169))) (.node (.node (.leaf 235) (.leaf 181)) (.node (.leaf 736) (.leaf 237)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 456)) (.node (.leaf 215) (.leaf 191))) (.node (.node (.leaf 155) (.leaf 644)) (.node (.leaf 598) (.leaf 238)))) (.node (.node (.node (.leaf 1) (.leaf 224)) (.node (.leaf 649) (.leaf 145))) (.node (.node (.leaf 219) (.leaf 218)) (.node (.leaf 544) (.leaf 146))))) (.node (.node (.node (.node (.leaf 1) (.leaf 207)) (.node (.leaf 135) (.leaf 146))) (.node (.node (.leaf 187) (.leaf 630)) (.node (.leaf 743) (.leaf 736)))) (.node (.node (.node (.leaf 123) (.leaf 545)) (.node (.leaf 684) (.leaf 205))) (.node (.node (.leaf 893) (.leaf 133)) (.node (.leaf 1) (.leaf 137)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 197)) (.node (.leaf 452) (.leaf 122))) (.node (.node (.leaf 135) (.leaf 570)) (.node (.leaf 235) (.leaf 156)))) (.node (.node (.node (.leaf 1) (.leaf 159)) (.node (.leaf 453) (.leaf 164))) (.node (.node (.leaf 199) (.leaf 647)) (.node (.leaf 879) (.leaf 147))))) (.node (.node (.node (.node (.leaf 1) (.leaf 480)) (.node (.leaf 126) (.leaf 209))) (.node (.node (.leaf 167) (.leaf 529)) (.node (.leaf 870) (.leaf 175)))) (.node (.node (.node (.leaf 1) (.leaf 146)) (.node (.leaf 837) (.leaf 155))) (.node (.node (.leaf 231) (.leaf 151)) (.node (.leaf 199) (.leaf 149)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 218)) (.node (.leaf 723) (.leaf 590))) (.node (.node (.leaf 151) (.leaf 636)) (.node (.leaf 490) (.leaf 202)))) (.node (.node (.node (.leaf 1) (.leaf 565)) (.node (.leaf 166) (.leaf 631))) (.node (.node (.leaf 215) (.leaf 165)) (.node (.leaf 534) (.leaf 138))))) (.node (.node (.node (.node (.leaf 1) (.leaf 196)) (.node (.leaf 220) (.leaf 192))) (.node (.node (.leaf 183) (.leaf 560)) (.node (.leaf 129) (.leaf 150)))) (.node (.node (.node (.leaf 1) (.leaf 539)) (.node (.leaf 125) (.leaf 223))) (.node (.node (.leaf 725) (.leaf 196)) (.node (.leaf 846) (.leaf 728))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 203)) (.node (.leaf 156) (.leaf 222))) (.node (.node (.leaf 143) (.leaf 688)) (.node (.leaf 658) (.leaf 159)))) (.node (.node (.node (.leaf 1) (.leaf 668)) (.node (.leaf 464) (.leaf 624))) (.node (.node (.leaf 207) (.leaf 195)) (.node (.leaf 518) (.leaf 139))))) (.node (.node (.node (.node (.leaf 1) (.leaf 212)) (.node (.leaf 731) (.leaf 690))) (.node (.node (.leaf 175) (.leaf 841)) (.node (.leaf 238) (.leaf 719)))) (.node (.node (.node (.leaf 1) (.leaf 770)) (.node (.leaf 300) (.leaf 182))) (.node (.node (.leaf 239) (.leaf 223)) (.node (.leaf 870) (.leaf 145)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 592)) (.node (.leaf 470) (.leaf 683))) (.node (.node (.leaf 159) (.leaf 678)) (.node (.leaf 667) (.leaf 214)))) (.node (.node (.node (.leaf 1) (.leaf 653)) (.node (.leaf 478) (.leaf 848))) (.node (.node (.leaf 223) (.leaf 716)) (.node (.leaf 536) (.leaf 920))))) (.node (.node (.node (.node (.leaf 1) (.leaf 716)) (.node (.leaf 582) (.leaf 815))) (.node (.node (.leaf 191) (.leaf 574)) (.node (.leaf 509) (.leaf 165)))) (.node (.node (.node (.leaf 127) (.leaf 717)) (.node (.leaf 718) (.leaf 159))) (.node (.node (.leaf 723) (.leaf 169)) (.node (.leaf 1) (.leaf 230)))))))) +noncomputable def st2_3 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 797)) (.node (.leaf 213) (.leaf 726))) (.node (.node (.leaf 133) (.leaf 568)) (.node (.leaf 759) (.leaf 157)))) (.node (.node (.node (.leaf 1) (.leaf 717)) (.node (.leaf 206) (.leaf 187))) (.node (.node (.leaf 197) (.leaf 664)) (.node (.leaf 937) (.leaf 193))))) (.node (.node (.node (.node (.leaf 1) (.leaf 220)) (.node (.leaf 134) (.leaf 182))) (.node (.node (.leaf 165) (.leaf 521)) (.node (.leaf 236) (.leaf 156)))) (.node (.node (.node (.leaf 1) (.leaf 657)) (.node (.leaf 206) (.leaf 872))) (.node (.node (.leaf 229) (.leaf 173)) (.node (.leaf 728) (.leaf 143)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 138)) (.node (.leaf 158) (.leaf 153))) (.node (.node (.leaf 149) (.leaf 201)) (.node (.leaf 221) (.leaf 220)))) (.node (.node (.node (.leaf 1) (.leaf 226)) (.node (.leaf 659) (.leaf 132))) (.node (.node (.leaf 213) (.leaf 180)) (.node (.leaf 528) (.leaf 179))))) (.node (.node (.node (.node (.leaf 1) (.leaf 799)) (.node (.leaf 591) (.leaf 933))) (.node (.node (.leaf 181) (.leaf 729)) (.node (.leaf 871) (.leaf 172)))) (.node (.node (.node (.leaf 1) (.leaf 537)) (.node (.leaf 486) (.leaf 179))) (.node (.node (.leaf 231) (.leaf 722)) (.node (.leaf 196) (.leaf 129))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 595)) (.node (.leaf 129) (.leaf 935))) (.node (.node (.leaf 141) (.leaf 175)) (.node (.leaf 727) (.leaf 198)))) (.node (.node (.node (.leaf 1) (.leaf 876)) (.node (.leaf 154) (.leaf 617))) (.node (.node (.leaf 205) (.leaf 209)) (.node (.leaf 170) (.leaf 217))))) (.node (.node (.node (.node (.leaf 1) (.leaf 129)) (.node (.leaf 232) (.leaf 137))) (.node (.node (.leaf 173) (.leaf 864)) (.node (.leaf 205) (.leaf 240)))) (.node (.node (.node (.leaf 1) (.leaf 206)) (.node (.leaf 853) (.leaf 167))) (.node (.node (.leaf 237) (.leaf 225)) (.node (.leaf 203) (.leaf 148)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 133)) (.node (.leaf 729) (.leaf 151))) (.node (.node (.leaf 157) (.leaf 621)) (.node (.leaf 865) (.leaf 226)))) (.node (.node (.node (.leaf 1) (.leaf 728)) (.node (.leaf 473) (.leaf 641))) (.node (.node (.leaf 221) (.leaf 162)) (.node (.leaf 858) (.leaf 241))))) (.node (.node (.node (.node (.leaf 1) (.leaf 123)) (.node (.leaf 161) (.leaf 795))) (.node (.node (.leaf 189) (.leaf 632)) (.node (.leaf 501) (.leaf 166)))) (.node (.node (.node (.leaf 125) (.leaf 198)) (.node (.leaf 584) (.leaf 213))) (.node (.node (.leaf 724) (.leaf 141)) (.node (.leaf 1) (.leaf 238)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 163)) (.node (.leaf 129) (.leaf 122))) (.node (.node (.leaf 137) (.leaf 175)) (.node (.leaf 680) (.leaf 202)))) (.node (.node (.node (.leaf 1) (.leaf 596)) (.node (.leaf 457) (.leaf 152))) (.node (.node (.leaf 201) (.leaf 654)) (.node (.leaf 208) (.leaf 143))))) (.node (.node (.node (.node (.leaf 1) (.leaf 210)) (.node (.leaf 162) (.leaf 157))) (.node (.node (.leaf 169) (.leaf 547)) (.node (.leaf 235) (.leaf 231)))) (.node (.node (.node (.leaf 1) (.leaf 232)) (.node (.leaf 842) (.leaf 743))) (.node (.node (.leaf 233) (.leaf 153)) (.node (.leaf 201) (.leaf 187)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 131)) (.node (.leaf 229) (.leaf 650))) (.node (.node (.leaf 153) (.leaf 643)) (.node (.leaf 493) (.leaf 160)))) (.node (.node (.node (.leaf 1) (.leaf 137)) (.node (.leaf 471) (.leaf 131))) (.node (.node (.leaf 217) (.leaf 158)) (.node (.leaf 526) (.leaf 202))))) (.node (.node (.node (.node (.leaf 1) (.leaf 179)) (.node (.leaf 206) (.leaf 782))) (.node (.node (.leaf 185) (.leaf 563)) (.node (.leaf 139) (.leaf 171)))) (.node (.node (.node (.leaf 1) (.leaf 718)) (.node (.leaf 240) (.leaf 225))) (.node (.node (.leaf 232) (.leaf 131)) (.node (.leaf 724) (.leaf 196))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 136)) (.node (.leaf 722) (.leaf 588))) (.node (.node (.leaf 145) (.leaf 155)) (.node (.leaf 718) (.leaf 239)))) (.node (.node (.node (.leaf 1) (.leaf 652)) (.node (.leaf 552) (.leaf 866))) (.node (.node (.leaf 209) (.leaf 192)) (.node (.leaf 729) (.leaf 194))))) (.node (.node (.node (.node (.leaf 1) (.leaf 674)) (.node (.leaf 172) (.leaf 141))) (.node (.node (.leaf 177) (.leaf 852)) (.node (.leaf 232) (.leaf 221)))) (.node (.node (.node (.leaf 1) (.leaf 525)) (.node (.leaf 724) (.leaf 237))) (.node (.node (.leaf 241) (.leaf 128)) (.node (.leaf 234) (.leaf 231)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 771)) (.node (.leaf 213) (.leaf 194))) (.node (.node (.leaf 161) (.leaf 685)) (.node (.leaf 656) (.leaf 234)))) (.node (.node (.node (.leaf 1) (.leaf 218)) (.node (.leaf 662) (.leaf 646))) (.node (.node (.leaf 225) (.leaf 942)) (.node (.leaf 195) (.leaf 927))))) (.node (.node (.node (.node (.leaf 1) (.leaf 717)) (.node (.leaf 137) (.leaf 813))) (.node (.node (.leaf 193) (.leaf 578)) (.node (.leaf 184) (.leaf 140)))) (.node (.node (.node (.leaf 129) (.leaf 625)) (.node (.leaf 126) (.leaf 154))) (.node (.node (.leaf 211) (.leaf 164)) (.node (.leaf 1) (.leaf 0)))))))) +noncomputable def st2_n1 : SSC.Trie := .node st2_2 st2_3 +noncomputable def st2 : SSC.Trie := .node st2_n0 st2_n1 +noncomputable def st3_0 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 130) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 194) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 162) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 226) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 146) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 210) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 178) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 138) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 202) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 170) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 234) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 154) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 218) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 186) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 122) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 134) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 198) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 166) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 230) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 150) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 214) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 182) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 142) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 206) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 174) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 238) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 158) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 222) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 190) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 126) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) +noncomputable def st3_1 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 132) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 196) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 164) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 228) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 148) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 212) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 180) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 140) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 204) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 172) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 236) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 156) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 220) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 188) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 124) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 136) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 200) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 168) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 232) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 152) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 216) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 184) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 144) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 208) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 176) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 240) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 160) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 224) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 192) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 128) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) +noncomputable def st3_n0 : SSC.Trie := .node st3_0 st3_1 +noncomputable def st3_2 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 131) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 195) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 163) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 227) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 147) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 211) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 179) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 139) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 203) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 171) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 235) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 155) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 219) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 187) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 123) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 135) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 199) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 167) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 231) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 151) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 215) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 183) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 143) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 207) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 175) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 239) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 159) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 223) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 191) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 127) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) +noncomputable def st3_3 : SSC.Trie := .node (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 133) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 197) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 165) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 229) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 149) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 213) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 181) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 141) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 205) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 173) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 237) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 157) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 221) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 189) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 125) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))))) (.node (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 137) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 201) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 169) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 233) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 153) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 217) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 185) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))))) (.node (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 145) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 209) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 177) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 241) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))))) (.node (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 161) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 225) (.leaf 1)) (.node (.leaf 1) (.leaf 1))))) (.node (.node (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 193) (.leaf 1)) (.node (.leaf 1) (.leaf 1)))) (.node (.node (.node (.leaf 129) (.leaf 1)) (.node (.leaf 1) (.leaf 1))) (.node (.node (.leaf 1) (.leaf 1)) (.node (.leaf 1) (.leaf 0)))))))) +noncomputable def st3_n1 : SSC.Trie := .node st3_2 st3_3 +noncomputable def st3 : SSC.Trie := .node st3_n0 st3_n1 +end GXD.E8 diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8End.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8End.lean new file mode 100644 index 0000000000..dfec705e0e --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8End.lean @@ -0,0 +1,10 @@ +import Work.GCert.Labels.EndDef +import Work.GCert.Data.Gen.E8Par +/-! Kernel check (E1 E2: frames at the start, at the scatter, at the end) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem end_ok : GLab.endK par 120 ports (raw.ret.map Prod.fst) st0 st1 st3 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.end_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Hist.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Hist.lean new file mode 100644 index 0000000000..4c0a89ebc5 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Hist.lean @@ -0,0 +1,46 @@ +import Work.GCert.Data.Count +import Work.GCert.Data.Gen.E8 +/-! Kernel count of the BLOCK RANKS of the gcert/1 certificate `GXD.E8.raw` (h = 9) on the explicit rank lists +`rA`, `rB`, `rF` (phase A, phase B, final climbs): `wsumK (SSC.wEq r) l 0` blocks of rank `r`, none above 8 +(`GXD.sum_of_wsumK` turns a count into `(l.map wt).sum` = `SSC.wsum wt l`). +The 8 scratch copies (ranks [9]) are not in these lists. Whole invocation, by rank: {1: 2091, 2: 604, 3: 518, 4: 140, 5: 215, 6: 331, 7: 43, 8: 24, 9: 8}. +Source: gcert1-e8-r783.json.gz. Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +/-- block ranks of phase A / phase B, in order (the lists of the replay segments) -/ +noncomputable def rA : List Nat := rs0 +noncomputable def rB : List Nat := rs1 +theorem rankBoundA : wsumK (SSC.wGt 8) rA 0 = 0 := by decide +kernel +theorem rankA0_ok : wsumK (SSC.wEq 0) rA 0 = 0 := by decide +kernel +theorem rankA1_ok : wsumK (SSC.wEq 1) rA 0 = 770 := by decide +kernel +theorem rankA2_ok : wsumK (SSC.wEq 2) rA 0 = 229 := by decide +kernel +theorem rankA3_ok : wsumK (SSC.wEq 3) rA 0 = 120 := by decide +kernel +theorem rankA4_ok : wsumK (SSC.wEq 4) rA 0 = 3 := by decide +kernel +theorem rankA5_ok : wsumK (SSC.wEq 5) rA 0 = 15 := by decide +kernel +theorem rankA6_ok : wsumK (SSC.wEq 6) rA 0 = 50 := by decide +kernel +theorem rankA7_ok : wsumK (SSC.wEq 7) rA 0 = 30 := by decide +kernel +theorem rankA8_ok : wsumK (SSC.wEq 8) rA 0 = 22 := by decide +kernel +theorem rankBoundB : wsumK (SSC.wGt 8) rB 0 = 0 := by decide +kernel +theorem rankB0_ok : wsumK (SSC.wEq 0) rB 0 = 0 := by decide +kernel +theorem rankB1_ok : wsumK (SSC.wEq 1) rB 0 = 867 := by decide +kernel +theorem rankB2_ok : wsumK (SSC.wEq 2) rB 0 = 301 := by decide +kernel +theorem rankB3_ok : wsumK (SSC.wEq 3) rB 0 = 287 := by decide +kernel +theorem rankB4_ok : wsumK (SSC.wEq 4) rB 0 = 109 := by decide +kernel +theorem rankB5_ok : wsumK (SSC.wEq 5) rB 0 = 170 := by decide +kernel +theorem rankB6_ok : wsumK (SSC.wEq 6) rB 0 = 203 := by decide +kernel +theorem rankB7_ok : wsumK (SSC.wEq 7) rB 0 = 13 := by decide +kernel +theorem rankB8_ok : wsumK (SSC.wEq 8) rB 0 = 2 := by decide +kernel +theorem rankBoundF : wsumK (SSC.wGt 8) rF 0 = 0 := by decide +kernel +theorem rankF0_ok : wsumK (SSC.wEq 0) rF 0 = 0 := by decide +kernel +theorem rankF1_ok : wsumK (SSC.wEq 1) rF 0 = 454 := by decide +kernel +theorem rankF2_ok : wsumK (SSC.wEq 2) rF 0 = 74 := by decide +kernel +theorem rankF3_ok : wsumK (SSC.wEq 3) rF 0 = 111 := by decide +kernel +theorem rankF4_ok : wsumK (SSC.wEq 4) rF 0 = 28 := by decide +kernel +theorem rankF5_ok : wsumK (SSC.wEq 5) rF 0 = 30 := by decide +kernel +theorem rankF6_ok : wsumK (SSC.wEq 6) rF 0 = 78 := by decide +kernel +theorem rankF7_ok : wsumK (SSC.wEq 7) rF 0 = 0 := by decide +kernel +theorem rankF8_ok : wsumK (SSC.wEq 8) rF 0 = 0 := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.rankBoundA +#print axioms GXD.E8.rankA0_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Par.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Par.lean new file mode 100644 index 0000000000..9ace01b6f3 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Par.lean @@ -0,0 +1,8 @@ +import Work.GCert.Labels.Def +import Work.GCert.Data.Gen.E8 +/-! Parameters `GLab.Par` of the label check of `GXD.E8.raw` (h, registers, trie depth, K, frame table). +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +namespace GXD.E8 +open GXD +noncomputable def par : GLab.Par := ⟨9, 1023, 10, 450, tab⟩ +end GXD.E8 diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Scal0.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Scal0.lean new file mode 100644 index 0000000000..219dd4f6db --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Scal0.lean @@ -0,0 +1,10 @@ +import Work.GCert.Scalar.Seg +import Work.GCert.Data.Gen.E8 +/-! Kernel check (scalar identity E3 E5 for the sources 0 .. 119) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem scal0_ok : GS.scalCheck raw ⟨10, 7, 2, 2, 6⟩ 0 120 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.scal0_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg0.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg0.lean new file mode 100644 index 0000000000..b69b6fdff4 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg0.lean @@ -0,0 +1,9 @@ +import Work.GCert.Data.Gen.E8Par +/-! Kernel check (E1: replay of the gates 0 .. 772 (phase A) and their block ranks) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem seg0_ok : GLab.segK par seg0 st0 st1 rs0 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.seg0_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg1.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg1.lean new file mode 100644 index 0000000000..a05e925bde --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Seg1.lean @@ -0,0 +1,9 @@ +import Work.GCert.Data.Gen.E8Par +/-! Kernel check (E1: replay of the gates 773 .. 1992 (phase B) and their block ranks) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem seg1_ok : GLab.segK par seg1 st1 st2 rs1 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.seg1_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8SegF.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8SegF.lean new file mode 100644 index 0000000000..72addebadb --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8SegF.lean @@ -0,0 +1,9 @@ +import Work.GCert.Data.Gen.E8Par +/-! Kernel check (E1: the final climbs and their block ranks) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem segF_ok : GLab.segK par fins st2 st3 rF = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.segF_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab0.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab0.lean new file mode 100644 index 0000000000..8995e049e0 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab0.lean @@ -0,0 +1,10 @@ +import Work.GCert.Labels.Def +import Work.GCert.Data.Gen.E8 +/-! Kernel check (E0: subtrie 0 of 4 of the frame table (codes of reduced echelon bases)) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem tab0_ok : GLab.tabK 9 tab_n00 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.tab0_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab1.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab1.lean new file mode 100644 index 0000000000..38ccb738ce --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab1.lean @@ -0,0 +1,10 @@ +import Work.GCert.Labels.Def +import Work.GCert.Data.Gen.E8 +/-! Kernel check (E0: subtrie 1 of 4 of the frame table (codes of reduced echelon bases)) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem tab1_ok : GLab.tabK 9 tab_n01 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.tab1_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab2.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab2.lean new file mode 100644 index 0000000000..bc10a63187 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab2.lean @@ -0,0 +1,10 @@ +import Work.GCert.Labels.Def +import Work.GCert.Data.Gen.E8 +/-! Kernel check (E0: subtrie 2 of 4 of the frame table (codes of reduced echelon bases)) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem tab2_ok : GLab.tabK 9 tab_n10 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.tab2_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab3.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab3.lean new file mode 100644 index 0000000000..07453a6580 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8Tab3.lean @@ -0,0 +1,10 @@ +import Work.GCert.Labels.Def +import Work.GCert.Data.Gen.E8 +/-! Kernel check (E0: subtrie 3 of 4 of the frame table (codes of reduced echelon bases)) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem tab3_ok : GLab.tabK 9 tab_n11 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.tab3_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8YChk.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8YChk.lean new file mode 100644 index 0000000000..e7129aa67f --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/Gen/E8YChk.lean @@ -0,0 +1,10 @@ +import Work.GCert.Scalar.Seg +import Work.GCert.Data.Gen.E8 +/-! Kernel check (the y -> y adds, E4) of the gcert/1 certificate `GXD.E8.raw`. Source: gcert1-e8-r783.json.gz. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.E8 +open GXD +theorem ychk_ok : GS.yCheck raw ⟨10, 7, 2, 2, 6⟩ 0 120 = true := by decide +kernel +end GXD.E8 +#print axioms GXD.E8.ychk_ok diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/InstB2Ge8.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/InstB2Ge8.lean new file mode 100644 index 0000000000..be583c65d3 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/InstB2Ge8.lean @@ -0,0 +1,55 @@ +import Work.BridgeGeom.B2 +import Work.FoldRate.Group +import Work.GCert.Data.RateB2Ge8 +import Work.GCert.Data.RateB2Ge8x + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `E8`, h = 9: the unit price is the price of the block list + +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. Arithmetic only (no certificate is imported). + +One unit: `W = 1263` live roles (`4 v + R`, `v = 120`, `R = 783`), label dimension `m = 45`, deficit `D = 120`. +`invPrice φ` = the price of the blocks of ONE invocation (the kernel-counted list `GXD.E8.hist`, by rank); +`unitPrice φ = 5 * invPrice φ + v * BG.bankPrice h φ = listCost φ BlockAccounting.blocksB2Ge8` (`unit_cost`). +Whole-block `1 - 87624/10^8` (fails at 87625), ten decimals `1 - 8762479/10^10` (fails at 8762483). +-/ + +namespace OAI +namespace PowerSaving +namespace BridgeRate +namespace B2Ge8 +open Finset Binary Matrix RAM CB FoldRate +noncomputable section + +/-- price of the blocks of ONE invocation of `E8` (all roles and scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := 2091 * φ 1 + 604 * φ 2 + 518 * φ 3 + 140 * φ 4 + 215 * φ 5 + 331 * φ 6 + 43 * φ 7 + 24 * φ 8 + 8 * φ 9 + +/-- price of ONE unit of the bridged word B_2 -/ +def unitPrice (φ : ℕ → ℝ) : ℝ := 5 * invPrice φ + ((120:ℕ):ℝ) * BG.bankPrice 9 φ + +/-- **The unit price is the price of the unit block list.** -/ +theorem unit_cost (φ : ℕ → ℝ) : unitPrice φ = listCost φ BlockAccounting.blocksB2Ge8 := by + unfold unitPrice invPrice + simp only [BG.bankPrice, listCost, BlockAccounting.blocksB2Ge8, List.map_cons, List.map_nil, + List.sum_cons, List.sum_nil] + norm_num [bcost] + try ring + +theorem blocks_x : BlockAccounting.blocksB2Ge8 = BlockAccounting.blocksB2Ge8x := rfl + +theorem unit_cost_x (φ : ℕ → ℝ) : unitPrice φ = listCost φ BlockAccounting.blocksB2Ge8x := by + rw [unit_cost, blocks_x] + +/-- one unit stands for `W * m - D` unit moves -/ +theorem unit_tally : unitPrice (fun r => (r:ℝ)) = ((1263:ℕ):ℝ) * ((45:ℕ):ℝ) - ((120:ℕ):ℝ) := by + rw [unit_cost] + exact BlockAccounting.blocksB2Ge8_tally + +end +end B2Ge8 +end BridgeRate +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.BridgeRate.B2Ge8.unit_cost +#print axioms OAI.PowerSaving.BridgeRate.B2Ge8.unit_tally diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8.lean new file mode 100644 index 0000000000..46c0ed04cd --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8.lean @@ -0,0 +1,207 @@ +import Work.BlockAccounting.Moment +import Work.BlockAccounting.Sharp +import Work.FoldRate.RankTools + +/-! +# (key: gx-data) Rate lemmas for one unit of the bridged word B_2 with the gcert/1 circuit `E8` (h = 9) + +GENERATED by checks/wht26/gx-data/py/gxrate.py with the text generators of checks/wht9/bridge-rate/py +(used read-only). No `sorry`. Arithmetic only. + +One unit: `W = 1263` live roles, label dimension `m = 45`, deficit `D = 120`. + +* `blocksB2Ge8` the block list (rank, count) of ONE unit; +* `fold_B2Ge8` whole-block fact at `1 - 87624/10^8`, fill parameter `s = 13` (slack 7.83e-09); +* `fold_B2Ge8_sharp` `W ≤ moment` at `1 - 87625/10^8`: fails for every table (excess 4.13e-09); +* `foldRank_B2Ge8` per-rank fact at `1 - 55517/10^8`, `s = 13` (slack 1.53e-06); +* `foldRank_B2Ge8_sharp` per-rank: fails for every table at `1 - 55524/10^8`. + +That a Lean word has `G` times this list as its block histogram is NOT proved here. +-/ + +set_option maxRecDepth 4000 + +namespace OAI.PowerSaving.BlockAccounting +open Finset + +/-- Block list `(rank, count)` of ONE unit of the bridged five-stage word B_2 with the gcert/1 circuit `E8` (h = 9, m = 45): five invocations (ALL blocks of one invocation: x roles, y roles, slots, scratch copies; the kernel-counted list `GXD.E8.hist`), and for each of the v = 120 ports the idle climbs of its two twins (2 blocks each of rank h-1, 2h-2, 2h+2, 4); R = 783 slots shared by the five stages. -/ +def blocksB2Ge8 : List (ℕ × ℕ) := [(1, 10455), (2, 3020), (3, 2590), (4, 940), (5, 1075), (6, 1655), (7, 215), (8, 360), (9, 40), (16, 240), (20, 240)] + +/-- total rank of one unit (= number of unit moves it stands for): `W * m - D` -/ +theorem blocksB2Ge8_rank : (blocksB2Ge8.map fun b => b.1 * b.2).sum = 1263 * 45 - 120 := by + norm_num [blocksB2Ge8] + +/-- the same as a price: the unit list at the price list `r ↦ r` (shape of `hPid` in `RAM.engine_program_group_perRank`) -/ +theorem blocksB2Ge8_tally : (blocksB2Ge8.map fun b => (b.2:ℝ) * ((b.1:ℕ):ℝ)).sum = ((1263:ℕ):ℝ) * ((45:ℕ):ℝ) - ((120:ℕ):ℝ) := by + norm_num [blocksB2Ge8] + +theorem blocksB2Ge8_count : (blocksB2Ge8.map fun b => b.2).sum = 20830 := by + norm_num [blocksB2Ge8] + +theorem blocksB2Ge8_proper : ∀ b ∈ blocksB2Ge8, 1 ≤ b.1 ∧ b.1 < 45 := by + decide + +/-- **whole-block fact** of `blocksB2Ge8` at exponent `1 - 87624/10^8`, fill parameter `s = 13`: the hypothesis `hnum` of `RAM.engine_program_group_list` (u = 45, W = 1263). Relative slack of the rational certificate: 7.83e-09. -/ +theorem fold_B2Ge8 : + ((2:ℝ)^13 - 1) * moment 45 (1 - 87624/(10:ℝ)^8) blocksB2Ge8 + + ((1263:ℕ):ℝ) * (T 45 (1 - 87624/(10:ℝ)^8) (45 - 1) 1 + T 45 (1 - 87624/(10:ℝ)^8) 1 1) + < (2:ℝ)^13 * ((1263:ℕ):ℝ) := by + have hsum : moment 45 (1 - 87624/(10:ℝ)^8) blocksB2Ge8 + = T 45 (1 - 87624/(10:ℝ)^8) 1 10455 + (T 45 (1 - 87624/(10:ℝ)^8) 2 3020 + (T 45 (1 - 87624/(10:ℝ)^8) 3 2590 + (T 45 (1 - 87624/(10:ℝ)^8) 4 940 + (T 45 (1 - 87624/(10:ℝ)^8) 5 1075 + (T 45 (1 - 87624/(10:ℝ)^8) 6 1655 + (T 45 (1 - 87624/(10:ℝ)^8) 7 215 + (T 45 (1 - 87624/(10:ℝ)^8) 8 360 + (T 45 (1 - 87624/(10:ℝ)^8) 9 40 + (T 45 (1 - 87624/(10:ℝ)^8) 16 240 + (T 45 (1 - 87624/(10:ℝ)^8) 20 240 + 0)))))))))) := rfl + have b0 : T 45 (1 - 87624/(10:ℝ)^8) 1 10455 ≤ ((4662191743:ℝ)/20000000) := + term_le 45 1 10455 (87624/(10:ℝ)^8) ((951665622443:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 25 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b1 : T 45 (1 - 87624/(10:ℝ)^8) 2 3020 ≤ ((6729445281:ℝ)/50000000) := + term_le 45 2 3020 (87624/(10:ℝ)^8) ((778378827303:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 23 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b2 : T 45 (1 - 87624/(10:ℝ)^8) 3 2590 ≤ ((4326921859:ℝ)/25000000) := + term_le 45 3 2590 (87624/(10:ℝ)^8) ((169253137569:ℝ)/62500000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 22 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b3 : T 45 (1 - 87624/(10:ℝ)^8) 4 940 ≤ ((4186647511:ℝ)/50000000) := + term_le 45 4 940 (87624/(10:ℝ)^8) ((605092032163:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 21 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b4 : T 45 (1 - 87624/(10:ℝ)^8) 5 1075 ≤ ((11967463193:ℝ)/100000000) := + term_le 45 5 1075 (87624/(10:ℝ)^8) ((1098612288669:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 20 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b5 : T 45 (1 - 87624/(10:ℝ)^8) 6 1655 ≤ ((22105660639:ℝ)/100000000) := + term_le 45 6 1655 (87624/(10:ℝ)^8) ((1967678731:ℝ)/976562500) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 19 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b6 : T 45 (1 - 87624/(10:ℝ)^8) 7 215 ≤ ((669980379:ℝ)/20000000) := + term_le 45 7 215 (87624/(10:ℝ)^8) ((1860752340717:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b7 : T 45 (1 - 87624/(10:ℝ)^8) 8 360 ≤ ((160242337:ℝ)/2500000) := + term_le 45 8 360 (87624/(10:ℝ)^8) ((431805237023:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b8 : T 45 (1 - 87624/(10:ℝ)^8) 9 40 ≤ ((801129:ℝ)/100000) := + term_le 45 9 40 (87624/(10:ℝ)^8) ((402359478109:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b9 : T 45 (1 - 87624/(10:ℝ)^8) 16 240 ≤ ((133454201:ℝ)/1562500) := + term_le 45 16 240 (87624/(10:ℝ)^8) ((258518441883:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 15 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b10 : T 45 (1 - 87624/(10:ℝ)^8) 20 240 ≤ ((10674248769:ℝ)/100000000) := + term_le 45 20 240 (87624/(10:ℝ)^8) ((405465108109:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 14 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b11 : T 45 (1 - 87624/(10:ℝ)^8) 44 1 ≤ ((12222463:ℝ)/12500000) := + term_le 45 44 1 (87624/(10:ℝ)^8) ((11236427927:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 6 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b12 : T 45 (1 - 87624/(10:ℝ)^8) 1 1 ≤ ((2229647:ℝ)/100000000) := + term_le 45 1 1 (87624/(10:ℝ)^8) ((951665622443:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 25 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have e1 : ((2:ℝ)^13 - 1) = 8191 := by norm_num + have e2 : (2:ℝ)^13 = 8192 := by norm_num + have e3 : ((1263:ℕ):ℝ) = 1263 := by norm_num + have e4 : T 45 (1 - 87624/(10:ℝ)^8) (45 - 1) 1 = T 45 (1 - 87624/(10:ℝ)^8) 44 1 := rfl + rw [e1, e2, e3, e4, hsum] + linarith + +/-- **sharpness**: at exponent `1 - 87625/10^8` the moment of one unit is at least its number of live roles `1263`, so the moment criterion fails for EVERY table made of copies of the unit and idle roles (`FoldRate.block_fails`). Relative excess of the rational certificate: 4.13e-09. -/ +theorem fold_B2Ge8_sharp : ((1263:ℕ):ℝ) ≤ moment 45 (1 - 87625/(10:ℝ)^8) blocksB2Ge8 := by + have hsum : moment 45 (1 - 87625/(10:ℝ)^8) blocksB2Ge8 + = T 45 (1 - 87625/(10:ℝ)^8) 1 10455 + (T 45 (1 - 87625/(10:ℝ)^8) 2 3020 + (T 45 (1 - 87625/(10:ℝ)^8) 3 2590 + (T 45 (1 - 87625/(10:ℝ)^8) 4 940 + (T 45 (1 - 87625/(10:ℝ)^8) 5 1075 + (T 45 (1 - 87625/(10:ℝ)^8) 6 1655 + (T 45 (1 - 87625/(10:ℝ)^8) 7 215 + (T 45 (1 - 87625/(10:ℝ)^8) 8 360 + (T 45 (1 - 87625/(10:ℝ)^8) 9 40 + (T 45 (1 - 87625/(10:ℝ)^8) 16 240 + (T 45 (1 - 87625/(10:ℝ)^8) 20 240 + 0)))))))))) := rfl + have c0 : ((116554797769:ℝ)/500000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 1 10455 := + term_ge 45 1 10455 (87625/(10:ℝ)^8) ((3806662489769:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 12 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c1 : ((2691778193:ℝ)/20000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 2 3020 := + term_ge 45 2 3020 (87625/(10:ℝ)^8) ((3113515309209:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c2 : ((86538439457:ℝ)/500000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 3 2590 := + term_ge 45 3 2590 (87625/(10:ℝ)^8) ((2708050201101:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c3 : ((83732952201:ℝ)/1000000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 4 940 := + term_ge 45 4 940 (87625/(10:ℝ)^8) ((2420368128649:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c4 : ((11967463451:ℝ)/100000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 5 1075 := + term_ge 45 5 1075 (87625/(10:ℝ)^8) ((439444915467:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c5 : ((13816038173:ℝ)/62500000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 6 1655 := + term_ge 45 6 1655 (87625/(10:ℝ)^8) ((2014903020541:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c6 : ((33499019563:ℝ)/1000000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 7 215 := + term_ge 45 7 215 (87625/(10:ℝ)^8) ((930376170357:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c7 : ((64096935887:ℝ)/1000000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 8 360 := + term_ge 45 8 360 (87625/(10:ℝ)^8) ((1727220948089:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c8 : ((4005645059:ℝ)/500000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 9 40 := + term_ge 45 9 40 (87625/(10:ℝ)^8) ((1609437912433:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c9 : ((85410689517:ℝ)/1000000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 16 240 := + term_ge 45 16 240 (87625/(10:ℝ)^8) ((1034073767529:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c10 : ((53371244273:ℝ)/500000000) ≤ T 45 (1 - 87625/(10:ℝ)^8) 20 240 := + term_ge 45 20 240 (87625/(10:ℝ)^8) ((162186043243:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 1 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have e3 : ((1263:ℕ):ℝ) = 1263 := by norm_num + rw [e3, hsum] + linarith + +/-- **per-rank fact** at exponent `1 - 55517/10^8`, fill parameter `s = 13`: the hypothesis `hnum` of `RAM.engine_program_group_perRank` (u = 45, W = 1263, D = 120). Relative slack: 1.53e-06. -/ +theorem foldRank_B2Ge8 : + (2:ℝ)^13 * ((1263:ℕ):ℝ) * (((45:ℕ):ℝ) - ((45:ℕ):ℝ)^(1 - 55517/(10:ℝ)^8)) < ((2:ℝ)^13 - 1) * ((120:ℕ):ℝ) := + FoldRate.rank_fact3 45 1263 120 13 (55517/(10:ℝ)^8) ((951665622443:ℝ)/250000000000) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 25 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + +/-- **per-rank sharpness**: at exponent `1 - 55524/10^8` the deficit of one unit is at most `W (m - m^z)`, so the per-rank inequality fails for EVERY table made of copies of the unit and idle roles (`FoldRate.rank_fails`). -/ +theorem foldRank_B2Ge8_sharp : + ((120:ℕ):ℝ) ≤ ((1263:ℕ):ℝ) * (((45:ℕ):ℝ) - ((45:ℕ):ℝ)^(1 - 55524/(10:ℝ)^8)) := + FoldRate.rank_fact_sharp 45 1263 120 (55524/(10:ℝ)^8) ((3806662489769:ℝ)/1000000000000) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 12 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + +end OAI.PowerSaving.BlockAccounting + +#print axioms OAI.PowerSaving.BlockAccounting.fold_B2Ge8 +#print axioms OAI.PowerSaving.BlockAccounting.fold_B2Ge8_sharp +#print axioms OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8 +#print axioms OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8_sharp diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8x.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8x.lean new file mode 100644 index 0000000000..10c148fd72 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/RateB2Ge8x.lean @@ -0,0 +1,207 @@ +import Work.BlockAccounting.Moment +import Work.BlockAccounting.Sharp +import Work.FoldRate.RankTools + +/-! +# (key: gx-data) Rate lemmas for one unit of the bridged word B_2 with the gcert/1 circuit `E8` (h = 9) + +GENERATED by checks/wht26/gx-data/py/gxrate.py with the text generators of checks/wht9/bridge-rate/py +(used read-only). No `sorry`. Arithmetic only. + +One unit: `W = 1263` live roles, label dimension `m = 45`, deficit `D = 120`. + +* `blocksB2Ge8x` the block list (rank, count) of ONE unit; +* `fold_B2Ge8x` whole-block fact at `1 - 8762479/10^10`, fill parameter `s = 40` (slack 1.86e-10); +* `fold_B2Ge8x_sharp` `W ≤ moment` at `1 - 8762483/10^10`: fails for every table (excess 3.08e-11); +* `foldRank_B2Ge8x` per-rank fact at `1 - 5552387/10^10`, `s = 40` (slack 2.91e-09); +* `foldRank_B2Ge8x_sharp` per-rank: fails for every table at `1 - 5552394/10^10`. + +That a Lean word has `G` times this list as its block histogram is NOT proved here. +-/ + +set_option maxRecDepth 4000 + +namespace OAI.PowerSaving.BlockAccounting +open Finset + +/-- Block list `(rank, count)` of ONE unit of the bridged five-stage word B_2 with the gcert/1 circuit `E8` (h = 9, m = 45): five invocations (ALL blocks of one invocation: x roles, y roles, slots, scratch copies; the kernel-counted list `GXD.E8.hist`), and for each of the v = 120 ports the idle climbs of its two twins (2 blocks each of rank h-1, 2h-2, 2h+2, 4); R = 783 slots shared by the five stages. -/ +def blocksB2Ge8x : List (ℕ × ℕ) := [(1, 10455), (2, 3020), (3, 2590), (4, 940), (5, 1075), (6, 1655), (7, 215), (8, 360), (9, 40), (16, 240), (20, 240)] + +/-- total rank of one unit (= number of unit moves it stands for): `W * m - D` -/ +theorem blocksB2Ge8x_rank : (blocksB2Ge8x.map fun b => b.1 * b.2).sum = 1263 * 45 - 120 := by + norm_num [blocksB2Ge8x] + +/-- the same as a price: the unit list at the price list `r ↦ r` (shape of `hPid` in `RAM.engine_program_group_perRank`) -/ +theorem blocksB2Ge8x_tally : (blocksB2Ge8x.map fun b => (b.2:ℝ) * ((b.1:ℕ):ℝ)).sum = ((1263:ℕ):ℝ) * ((45:ℕ):ℝ) - ((120:ℕ):ℝ) := by + norm_num [blocksB2Ge8x] + +theorem blocksB2Ge8x_count : (blocksB2Ge8x.map fun b => b.2).sum = 20830 := by + norm_num [blocksB2Ge8x] + +theorem blocksB2Ge8x_proper : ∀ b ∈ blocksB2Ge8x, 1 ≤ b.1 ∧ b.1 < 45 := by + decide + +/-- **whole-block fact** of `blocksB2Ge8x` at exponent `1 - 8762479/10^10`, fill parameter `s = 40`: the hypothesis `hnum` of `RAM.engine_program_group_list` (u = 45, W = 1263). Relative slack of the rational certificate: 1.86e-10. -/ +theorem fold_B2Ge8x : + ((2:ℝ)^40 - 1) * moment 45 (1 - 8762479/(10:ℝ)^10) blocksB2Ge8x + + ((1263:ℕ):ℝ) * (T 45 (1 - 8762479/(10:ℝ)^10) (45 - 1) 1 + T 45 (1 - 8762479/(10:ℝ)^10) 1 1) + < (2:ℝ)^40 * ((1263:ℕ):ℝ) := by + have hsum : moment 45 (1 - 8762479/(10:ℝ)^10) blocksB2Ge8x + = T 45 (1 - 8762479/(10:ℝ)^10) 1 10455 + (T 45 (1 - 8762479/(10:ℝ)^10) 2 3020 + (T 45 (1 - 8762479/(10:ℝ)^10) 3 2590 + (T 45 (1 - 8762479/(10:ℝ)^10) 4 940 + (T 45 (1 - 8762479/(10:ℝ)^10) 5 1075 + (T 45 (1 - 8762479/(10:ℝ)^10) 6 1655 + (T 45 (1 - 8762479/(10:ℝ)^10) 7 215 + (T 45 (1 - 8762479/(10:ℝ)^10) 8 360 + (T 45 (1 - 8762479/(10:ℝ)^10) 9 40 + (T 45 (1 - 8762479/(10:ℝ)^10) 16 240 + (T 45 (1 - 8762479/(10:ℝ)^10) 20 240 + 0)))))))))) := rfl + have b0 : T 45 (1 - 8762479/(10:ℝ)^10) 1 10455 ≤ ((2331095941537:ℝ)/10000000000) := + term_le 45 1 10455 (8762479/(10:ℝ)^10) ((951665622443:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 25 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b1 : T 45 (1 - 8762479/(10:ℝ)^10) 2 3020 ≤ ((67294454461:ℝ)/500000000) := + term_le 45 2 3020 (8762479/(10:ℝ)^10) ((778378827303:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 23 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b2 : T 45 (1 - 8762479/(10:ℝ)^10) 3 2590 ≤ ((1730768780589:ℝ)/10000000000) := + term_le 45 3 2590 (8762479/(10:ℝ)^10) ((169253137569:ℝ)/62500000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 22 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b3 : T 45 (1 - 8762479/(10:ℝ)^10) 4 940 ≤ ((167465903641:ℝ)/2000000000) := + term_le 45 4 940 (8762479/(10:ℝ)^10) ((605092032163:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 21 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b4 : T 45 (1 - 8762479/(10:ℝ)^10) 5 1075 ≤ ((598373170031:ℝ)/5000000000) := + term_le 45 5 1075 (8762479/(10:ℝ)^10) ((1098612288669:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 20 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b5 : T 45 (1 - 8762479/(10:ℝ)^10) 6 1655 ≤ ((221056609901:ℝ)/1000000000) := + term_le 45 6 1655 (8762479/(10:ℝ)^10) ((1967678731:ℝ)/976562500) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 19 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b6 : T 45 (1 - 8762479/(10:ℝ)^10) 7 215 ≤ ((33499019441:ℝ)/1000000000) := + term_le 45 7 215 (8762479/(10:ℝ)^10) ((1860752340717:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b7 : T 45 (1 - 8762479/(10:ℝ)^10) 8 360 ≤ ((640969356673:ℝ)/10000000000) := + term_le 45 8 360 (8762479/(10:ℝ)^10) ((431805237023:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b8 : T 45 (1 - 8762479/(10:ℝ)^10) 9 40 ≤ ((20028225233:ℝ)/2500000000) := + term_le 45 9 40 (8762479/(10:ℝ)^10) ((402359478109:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 18 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b9 : T 45 (1 - 8762479/(10:ℝ)^10) 16 240 ≤ ((854106893351:ℝ)/10000000000) := + term_le 45 16 240 (8762479/(10:ℝ)^10) ((258518441883:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 15 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b10 : T 45 (1 - 8762479/(10:ℝ)^10) 20 240 ≤ ((1067424883667:ℝ)/10000000000) := + term_le 45 20 240 (8762479/(10:ℝ)^10) ((405465108109:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 14 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b11 : T 45 (1 - 8762479/(10:ℝ)^10) 44 1 ≤ ((4888985161:ℝ)/5000000000) := + term_le 45 44 1 (8762479/(10:ℝ)^10) ((11236427927:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 6 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have b12 : T 45 (1 - 8762479/(10:ℝ)^10) 1 1 ≤ ((222964701:ℝ)/10000000000) := + term_le 45 1 1 (8762479/(10:ℝ)^10) ((951665622443:ℝ)/250000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 25 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + have e1 : ((2:ℝ)^40 - 1) = 1099511627775 := by norm_num + have e2 : (2:ℝ)^40 = 1099511627776 := by norm_num + have e3 : ((1263:ℕ):ℝ) = 1263 := by norm_num + have e4 : T 45 (1 - 8762479/(10:ℝ)^10) (45 - 1) 1 = T 45 (1 - 8762479/(10:ℝ)^10) 44 1 := rfl + rw [e1, e2, e3, e4, hsum] + linarith + +/-- **sharpness**: at exponent `1 - 8762483/10^10` the moment of one unit is at least its number of live roles `1263`, so the moment criterion fails for EVERY table made of copies of the unit and idle roles (`FoldRate.block_fails`). Relative excess of the rational certificate: 3.08e-11. -/ +theorem fold_B2Ge8x_sharp : ((1263:ℕ):ℝ) ≤ moment 45 (1 - 8762483/(10:ℝ)^10) blocksB2Ge8x := by + have hsum : moment 45 (1 - 8762483/(10:ℝ)^10) blocksB2Ge8x + = T 45 (1 - 8762483/(10:ℝ)^10) 1 10455 + (T 45 (1 - 8762483/(10:ℝ)^10) 2 3020 + (T 45 (1 - 8762483/(10:ℝ)^10) 3 2590 + (T 45 (1 - 8762483/(10:ℝ)^10) 4 940 + (T 45 (1 - 8762483/(10:ℝ)^10) 5 1075 + (T 45 (1 - 8762483/(10:ℝ)^10) 6 1655 + (T 45 (1 - 8762483/(10:ℝ)^10) 7 215 + (T 45 (1 - 8762483/(10:ℝ)^10) 8 360 + (T 45 (1 - 8762483/(10:ℝ)^10) 9 40 + (T 45 (1 - 8762483/(10:ℝ)^10) 16 240 + (T 45 (1 - 8762483/(10:ℝ)^10) 20 240 + 0)))))))))) := rfl + have c0 : ((23310959402953:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 1 10455 := + term_ge 45 1 10455 (8762483/(10:ℝ)^10) ((3806662489769:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 12 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c1 : ((13458890893811:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 2 3020 := + term_ge 45 2 3020 (8762483/(10:ℝ)^10) ((3113515309209:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c2 : ((8653843905907:ℝ)/50000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 3 2590 := + term_ge 45 3 2590 (8762483/(10:ℝ)^10) ((2708050201101:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c3 : ((8373295185727:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 4 940 := + term_ge 45 4 940 (8762483/(10:ℝ)^10) ((2420368128649:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c4 : ((11967463406397:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 5 1075 := + term_ge 45 5 1075 (8762483/(10:ℝ)^10) ((439444915467:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c5 : ((22105661001167:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 6 1655 := + term_ge 45 6 1655 (8762483/(10:ℝ)^10) ((2014903020541:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c6 : ((418737743223:ℝ)/12500000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 7 215 := + term_ge 45 7 215 (8762483/(10:ℝ)^10) ((930376170357:ℝ)/500000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c7 : ((3204846784959:ℝ)/50000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 8 360 := + term_ge 45 8 360 (8762483/(10:ℝ)^10) ((1727220948089:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c8 : ((801129009703:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 9 40 := + term_ge 45 9 40 (8762483/(10:ℝ)^10) ((1609437912433:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c9 : ((8541068936689:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 16 240 := + term_ge 45 16 240 (8762483/(10:ℝ)^10) ((1034073767529:ℝ)/1000000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 2 10 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have c10 : ((10674248839919:ℝ)/100000000000) ≤ T 45 (1 - 8762483/(10:ℝ)^10) 20 240 := + term_ge 45 20 240 (8762483/(10:ℝ)^10) ((162186043243:ℝ)/200000000000) _ (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 1 11 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) + have e3 : ((1263:ℕ):ℝ) = 1263 := by norm_num + rw [e3, hsum] + linarith + +/-- **per-rank fact** at exponent `1 - 5552387/10^10`, fill parameter `s = 40`: the hypothesis `hnum` of `RAM.engine_program_group_perRank` (u = 45, W = 1263, D = 120). Relative slack: 2.91e-09. -/ +theorem foldRank_B2Ge8x : + (2:ℝ)^40 * ((1263:ℕ):ℝ) * (((45:ℕ):ℝ) - ((45:ℕ):ℝ)^(1 - 5552387/(10:ℝ)^10)) < ((2:ℝ)^40 - 1) * ((120:ℕ):ℝ) := + FoldRate.rank_fact3 45 1263 120 40 (5552387/(10:ℝ)^10) ((951665622443:ℝ)/250000000000) (by norm_num) (by norm_num) (by norm_num) + (log_le_of_le_expsum _ _ 25 (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + +/-- **per-rank sharpness**: at exponent `1 - 5552394/10^10` the deficit of one unit is at most `W (m - m^z)`, so the per-rank inequality fails for EVERY table made of copies of the unit and idle roles (`FoldRate.rank_fails`). -/ +theorem foldRank_B2Ge8x_sharp : + ((120:ℕ):ℝ) ≤ ((1263:ℕ):ℝ) * (((45:ℕ):ℝ) - ((45:ℕ):ℝ)^(1 - 5552394/(10:ℝ)^10)) := + FoldRate.rank_fact_sharp 45 1263 120 (5552394/(10:ℝ)^10) ((3806662489769:ℝ)/1000000000000) (by norm_num) (by norm_num) (by norm_num) + (le_log_of_expbound _ _ 3 12 (by norm_num) (by norm_num) (by norm_num) + (by norm_num [Finset.sum_range_succ, Nat.factorial])) + (by norm_num) (by norm_num) + +end OAI.PowerSaving.BlockAccounting + +#print axioms OAI.PowerSaving.BlockAccounting.fold_B2Ge8x +#print axioms OAI.PowerSaving.BlockAccounting.fold_B2Ge8x_sharp +#print axioms OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8x +#print axioms OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8x_sharp diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/SolutionB2Ge8x.lean b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/SolutionB2Ge8x.lean new file mode 100644 index 0000000000..bfa1d03088 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/Work/GCert/Data/SolutionB2Ge8x.lean @@ -0,0 +1,38 @@ +import Work.GCert.Data.B2Ge8Main + +/-! +Comparator solution `Work.GCert.Data.SolutionB2Ge8x` (not part of github.com/openai/math). + +The whole proof is in `Work.GCert.Data.B2Ge8Main` (and its imports), which ends with + + theorem wht_main_B2Ge8x : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 8762479/(10:ℝ)^10) W + +This module adds nothing mathematical: it defines `WHT.WHTTimeBoundsAt` with the text of the +challenge (the same definition as `BlockWHT.WHTTimeBoundsAt` of `Work.Block.WHT`) and restates +the theorem under the name the challenge uses. Its proof is that single term. +`WHTProgram`, `wht`, `whtInKind`, `whtOutKind` come from `WHTCheck.Solution`. +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open Filter Asymptotics + +/-- `W = O(2^k (k+1)^β)` and `W = o(2^k k)` (`WHTTimeBounds` is the case `β = 1 - 2/10^11`). -/ +def WHTTimeBoundsAt (β : ℝ) (W : ℕ → ℕ) : Prop := + let W' := fun k : ℕ => (W k : ℝ) + W' =O[atTop] (fun k : ℕ => (2:ℝ)^k * ((k:ℝ)+1)^β) ∧ + W' =o[atTop] (fun k : ℕ => (2:ℝ)^k * (k:ℝ)) + +/-- **Walsh-Hadamard transform with the improved exponent**: the statement `WHTGoal` of +`WHTCheck/Challenge.lean` with `1 - 2/10^11` replaced by `1 - 8762479/10^10`. -/ +theorem wht_main_block_B2Ge8x : + ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 8762479/(10:ℝ)^10) W := + wht_main_B2Ge8x + +end WHT +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.WHT.wht_main_block_B2Ge8x diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/comparator/B2Ge8x.json b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/comparator/B2Ge8x.json new file mode 100644 index 0000000000..7fda546848 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/comparator/B2Ge8x.json @@ -0,0 +1,14 @@ +{ + "challenge_module": "Work.GCert.Data.ChallengeB2Ge8x", + "solution_module": "Work.GCert.Data.SolutionB2Ge8x", + "theorem_names": [ + "OAI.PowerSaving.WHT.wht_main_block_B2Ge8x" + ], + "definition_names": [], + "permitted_axioms": [ + "propext", + "Quot.sound", + "Classical.choice" + ], + "enable_nanoda": false +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/certificate/gcert1-e8-r783.json.gz b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/certificate/gcert1-e8-r783.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..56708f99a48c3f86bfcabfc526c2ff224bdba66a GIT binary patch literal 22008 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 [e8] [json] [seed=] [noparts] [norandom] + +replay.py: a STAND-ALONE replay of a certificate of format gcert/1. +Python 3.9 standard library only. It imports nothing of the published tools and nothing of the E8 harness, and it +reads only the certificate file. Every rule below cites the line of the published code it was read from +(REL = this repository at its third revision; gx = REL/tools/gx/gx.py, core = REL/tools/gx/gxcore.py, unit = REL/tools/gx/gxunit.py, +rate = REL/tools/gx/gxrate.py, fold = REL/tools/gen/foldlib.py, logs = REL/tools/gen/gen_rates.py, +gsm = REL/tools/gx/gsmirror.py, Lean = REL/Work/GCert). + + e8 also require h = 9, v = 120 and ports = exactly the 120 bit vectors of length 9 of weight 3 or 7 + json print one last line `JSON {...}` with the key numbers + seed= seed of the two random-value runs (default: fresh values from the system) + noparts skip section 9 (the replay with separate positive and negative parts, the slowest part) + norandom skip the two random-value runs + +Exit code: 0 accepted on every count; 1 REFUSED by a rule of the two published checkers (or the file is malformed, +or the program could not decide); 3 accepted by those rules but a Lean-facing extra test failed; 2 usage. +What is NOT checked: see README.md of this folder. + +Control: figure 7474547 on tools/certificate/gcert1-p11-pr193.json.gz (about 40 s, 550 MB). +""" +import sys +import json +import gzip +import hashlib +import os +import random +import time +from collections import Counter +from fractions import Fraction as Q +from math import gcd + + +class Refuse(Exception): + def __init__(self, rule, msg): + Exception.__init__(self, "%s: %s" % (rule, msg)) + self.rule = rule + + +def need(cond, rule, msg): + if not cond: + raise Refuse(rule, msg) + + +def isint(x): + return type(x) is int + + +def islist(x): + return type(x) is list + + +def wt(x): + return bin(x).count("1") + + +# ===================================================================================================================== +# 0. the file +# ===================================================================================================================== +def load(path): + raw = open(path, "rb").read() + sha = hashlib.sha256(raw).hexdigest() + if raw[:2] == b"\x1f\x8b": + raw = gzip.decompress(raw) + + def nodup(pairs): + d = {} + for k, val in pairs: + need(k not in d, "F0", "the key %r occurs twice in one JSON object" % (k,)) + d[k] = val + return d + + def noconst(s): + raise Refuse("F0", "a number that is not finite (%s)" % s) + try: + c = json.loads(raw.decode("utf-8"), object_pairs_hook=nodup, parse_constant=noconst) + except ValueError as e: + raise Refuse("F0", "not JSON: %s" % e) + return c, sha + + +# ===================================================================================================================== +# 1. subspaces of F_2^h (own code: elimination by leading bit; for h <= 12 also the full list of elements) +# ===================================================================================================================== +def canon(vectors): + """the subspace spanned by the bit vectors, as its unique reduced basis, leading bits descending""" + piv = {} + for u in vectors: + while u: + p = u.bit_length() - 1 + if p in piv: + u ^= piv[p] + else: + piv[p] = u + break + order = sorted(piv, reverse=True) + for p in sorted(piv): # clear every leading bit from the vectors above it + for q in order: + if q > p and piv[q] >> p & 1: + piv[q] ^= piv[p] + return tuple(piv[p] for p in order) + + +def in_span(u, piv): + while u: + p = u.bit_length() - 1 + if p not in piv: + return False + u ^= piv[p] + return True + + +def elements(basis): + """bit set (one Python integer, bit e set if e is in the span)""" + els = [0] + for b in basis: + els += [e ^ b for e in els] + m = 0 + for e in els: + m |= 1 << e + return m + + +# ===================================================================================================================== +# 2. outward-rounded fixed-point arithmetic for the figure (own code; an integer n stands for n / 2^P) +# ===================================================================================================================== +def cdiv(a, b): + return -((-a) // b) + + +class Undecided(Exception): + pass + + +class Fix: + def __init__(self, P): + self.P, self.S = P, 1 << P + lo, hi = self.atanh(1, 3) + self.ln2 = (2 * lo, 2 * hi) # ln 2 = 2 atanh(1/3) + self.cache = {} + + def atanh(self, a, b): + """bounds of atanh(a/b) = sum_k (a/b)^(2k+1) / (2k+1) for integers 0 <= a, 0 < b, 3a <= b""" + assert 0 <= a and 0 < b and 3 * a <= b + if a == 0: + return 0, 0 + lo = hi = 0 + pl, ph = (a * self.S) // b, cdiv(a * self.S, b) + a2, b2 = a * a, b * b + K = self.P // 3 + 4 # (1/9)^K < 2^-P + for k in range(K): + lo += pl // (2 * k + 1) + hi += cdiv(ph, 2 * k + 1) + pl, ph = (pl * a2) // b2, cdiv(ph * a2, b2) + hi += cdiv(ph * 9, 8) # the tail: at most y^(2K+1) / (1 - y^2), and 1 / (1 - y^2) <= 9/8 + return lo, hi + + def ln(self, n): + """bounds of ln n for an integer n >= 1: n = 2^k q, 1 <= q < 2, ln q = 2 atanh((q-1)/(q+1))""" + if n not in self.cache: + k = n.bit_length() - 1 + lo, hi = self.atanh(n - (1 << k), n + (1 << k)) + self.cache[n] = (k * self.ln2[0] + 2 * lo, k * self.ln2[1] + 2 * hi) + return self.cache[n] + + def ln_ratio(self, m, r): + (a, b), (c, d) = self.ln(m), self.ln(r) + return a - d, b - c + + def exp_lo(self, x): + """a lower bound of e^x for x >= 0 (x a lower bound of the argument)""" + assert x >= 0 + tot, term, k = 0, self.S, 0 + while term > 0: + tot += term + k += 1 + term = (term * x) // (self.S * k) + return tot + + def exp_up(self, x): + """an upper bound of e^x for x >= 0 (x an upper bound of the argument)""" + assert x >= 0 + tot, term, k = 0, self.S, 0 + while True: + tot += term + k += 1 + term = cdiv(term * x, self.S * k) # an upper bound of x^k / k! + if term <= 1 and (k + 1) * self.S >= 2 * x: + break + return tot + 2 * term + 1 # the tail from k on is at most twice its first term + + +def block_holds(F, U, A, B, sbits): + """the whole-block inequality of fold:8, (t-1) M(z) + W ((m-1)/m)^z + W (1/m)^z < t W, z = 1 - A/10^B, t = 2^sbits, + M(z) = sum over the block list of count * (rank/m)^z. True = proved, False = proved false, None = undecided.""" + t, m, W, den = 1 << sbits, U["m"], U["W"], 10 ** B + + def term(r, n): # bounds of n (r/m)^z = n (r/m) exp((A/10^B) ln(m/r)) + l, u = F.ln_ratio(m, r) + return (n * r * F.exp_lo((A * l) // den)) // m, cdiv(n * r * F.exp_up(cdiv(A * u, den)), m) + lo = hi = 0 + for r, n in U["H"].items(): + a, b = term(r, n) + lo, hi = lo + a, hi + b + (a1, b1), (a2, b2) = term(m - 1, 1), term(1, 1) + L, Hh, rhs = (t - 1) * lo + W * (a1 + a2), (t - 1) * hi + W * (b1 + b2), t * W * F.S + return True if Hh < rhs else False if L >= rhs else None + + +def rank_holds(F, U, A, B, sbits): + """the per-rank inequality of fold:10, t W (m - m^z) < (t-1) D""" + t, m, W, D, den = 1 << sbits, U["m"], U["W"], U["D"], 10 ** B + l, u = F.ln_ratio(m, 1) + e_lo, e_up = F.exp_lo((A * l) // den), F.exp_up(cdiv(A * u, den)) + one_minus_lo, one_minus_up = F.S - cdiv(F.S * F.S, e_lo), F.S - (F.S * F.S) // e_up # 1 - e^-x + L, Hh, rhs = t * W * m * one_minus_lo, t * W * m * one_minus_up, (t - 1) * D * F.S + return True if Hh < rhs else False if L >= rhs else None + + +def last_true(f, top): + """the largest A in [0, top) with f(A), for a monotone f (bisection as in fold:59-67)""" + r0 = f(0) + if r0 is None: + raise Undecided() + if not r0: + return None + lo, hi = 0, top + while hi - lo > 1: + mid = (lo + hi) // 2 + r = f(mid) + if r is None: + raise Undecided() + if r: + lo = mid + else: + hi = mid + return lo + + +def log_upper(F, m, r, Dd=12): + """the rational bound of the tools (logs:13-15): (ceiling of ln(m/r) 10^Dd, plus one) / 10^Dd""" + l, u = F.ln_ratio(m, r) + a, b = cdiv(l * 10 ** Dd, F.S), cdiv(u * 10 ** Dd, F.S) + if a != b: + raise Undecided() + return Q(a + 1, 10 ** Dd) + + +def block_cert(U, Ls, A, B, sbits): + """the exact rational certificate of the tools (fold:86-111): every (r/m)^z is bounded by + (r/m)(1 + x + x^2/2 + (2/9) x^3), x = (A/10^B) L_r <= 1. Returns the margin (a fraction; > 0 = certificate) or + None when some x > 1 (the tool stops there).""" + eps, t, m, W, H = Q(A, 10 ** B), 1 << sbits, U["m"], U["W"], U["H"] + vals = [] + for r, n in [(r, H[r]) for r in sorted(H)] + [(m - 1, 1), (1, 1)]: + x = eps * Ls[r] + if x > 1: + return None + vals.append(n * Q(r, m) * (1 + x + x * x / 2 + x ** 3 * Q(2, 9))) + nH = len(H) + margin = t * W - ((t - 1) * sum(vals[:nH]) + W * (vals[nH] + vals[nH + 1])) + if margin > 0: # the rounding step of fold:104-110, repeated as a test + G = 0 + while Q((t - 1) * nH + 2 * W, 10 ** G) > margin / 50: + G += 1 + up = [Q(cdiv((x * 10 ** G).numerator, (x * 10 ** G).denominator), 10 ** G) for x in vals] + if not (t - 1) * sum(up[:nH]) + W * (up[nH] + up[nH + 1]) < t * W: + return Q(0) + return margin + + +def rank_cert(U, L1, A, B, sbits): + """fold:136-146: t W m (x - x^2/2 + x^3/4) < (t-1) D with x = (A/10^B) L, L >= ln m, x <= 1""" + t, m, W, D = 1 << sbits, U["m"], U["W"], U["D"] + x = Q(A, 10 ** B) * L1 + return x <= 1 and t * W * m * (x - x * x / 2 + x ** 3 / 4) < (t - 1) * D + + +def figures(U, B, sbits): + """(largest A with the tools' rational certificate, largest A for which the inequality is true), whole-block + and per-rank. unit:39-47 and rate:26-32: start at the largest true A and step down until the certificate exists.""" + P = 256 + while True: + try: + F = Fix(P) + top = 10 ** B + At = last_true(lambda a: block_holds(F, U, a, B, sbits), top) + Rt = last_true(lambda a: rank_holds(F, U, a, B, sbits), top) + if At is None or Rt is None: + return None + if At + 1 < top and block_holds(F, U, At + 1, B, sbits) is not False: + raise Undecided() + if Rt + 1 < top and rank_holds(F, U, Rt + 1, B, sbits) is not False: + raise Undecided() + Ls = {r: log_upper(F, U["m"], r) for r in list(U["H"]) + [U["m"] - 1, 1]} + break + except Undecided: + P *= 2 + if P > 4096: + raise Refuse("FIG", "the figure could not be decided with 4096 bits") + + def ok(a): + g = block_cert(U, Ls, a, B, sbits) + return g is not None and g > 0 + Ac = last_true(ok, At + 1) + Rc = last_true(lambda a: rank_cert(U, Ls[1], a, B, sbits), Rt + 1) + if Ac is None or Rc is None: + return None + assert ok(Ac) and (Ac == At or not ok(Ac + 1)) + return dict(block=Ac, block_true=At, rank=Rc, rank_true=Rt, bits=P, + slack=float(block_cert(U, Ls, Ac, B, sbits) / ((1 << sbits) * U["W"]))) + + +# ===================================================================================================================== +# 3. the check +# ===================================================================================================================== +KEYS = ("format", "h", "v", "R", "N", "cst", "ports", "frames", "start", "final", "ext", "A", "ret", "scat", "B", "blocks") +KINDS = {("x", "s"), ("s", "s"), ("s", "y"), ("x", "y"), ("x", "x"), ("y", "y")} # gx:161, core:238 +KINDS_A = {("x", "s"), ("s", "s")} # gx:185, core:249 +CLS = "xysc" + + +def check(c, opt, say): + res = {} + # ---- (E0) sizes and ports ----------------------------------------------------------------------------------- + need(type(c) is dict, "F0", "the file is not a JSON object") + for k in KEYS: + need(k in c, "F0", "the key %r is missing" % k) + need(c["format"] == "gcert/1", "E0", "format is not gcert/1") # gx:131, core:21 + h, v, R = c["h"], c["v"], c["R"] + need(all(isint(x) for x in (h, v, R, c["N"], c["cst"])), "F0", "h, v, R, N, cst must be whole numbers") + need(h >= 1 and v >= 1 and R >= 0, "F0", "h, v, R out of range") + nreg, full = 2 * v + R, (1 << h) - 1 # gx:133 + cls = lambda r: "x" if r < v else "y" if r < 2 * v else "s" # gx:148, Lean Data/Raw.lean:8 + ports = c["ports"] + need(islist(ports) and all(isint(q) for q in ports), "F0", "ports") + need(len(ports) == v and len(set(ports)) == v and all(0 < q <= full and wt(q) % 2 == 1 for q in ports), + "E0", "ports: not v distinct labels of odd weight in 1 .. 2^h - 1") # gx:135, core:85 + e8set = set(q for q in range(512) if wt(q) in (3, 7)) + res["e8_family"] = (h == 9 and v == 120 and set(ports) == e8set) + if opt["e8"]: + need(res["e8_family"], "E8", "the family is not exactly the 120 E8 ports (h = 9, weights 3 and 7)") + # ---- (E0) the frame table ------------------------------------------------------------------------------------ + fr = c["frames"] + need(islist(fr) and len(fr) >= 2, "E0", "frame table") # core:86 + nfr, dim, piv, els, seen = len(fr), [], [], [], {} + small = h <= 12 + for i, f in enumerate(fr): + need(islist(f) and all(isint(b) and 0 < b <= full for b in f), "E0", "frame %d: entries" % i) # core:87 + cf = canon(f) + need(tuple(f) == cf, "E0", "frame %d is not written as a reduced echelon basis" % i) # gx:30-34,137 + need(cf not in seen, "E0", "frames %d and %d are the same subspace" % (seen.get(cf, -1), i)) # gx:137, core:88 + seen[cf] = i + dim.append(len(cf)) + piv.append({b.bit_length() - 1: b for b in cf}) + els.append(elements(cf) if small else None) + need(fr[0] == [] and fr[1] == [1 << i for i in range(h - 1, -1, -1)], "E0", "frame 0 is not zero or frame 1 is not the full space") # gx:136 + sub_cache = {} + + def inside(o, f): + """is frame o contained in frame f (two methods when h <= 12; they must agree)""" + if (o, f) not in sub_cache: + a = all(in_span(u, piv[f]) for u in fr[o]) + if small: + assert a == (els[o] & ~els[f] == 0), "the two containment tests disagree" + sub_cache[o, f] = a + return sub_cache[o, f] + # ---- (E1) where every register starts and ends --------------------------------------------------------------- + start, final = c["start"], c["final"] + need(islist(start) and islist(final) and len(start) == len(final) == nreg, "E0", "start / final: not one entry per register") # gx:140 + need(all(isint(f) and 0 <= f < nfr for f in start + final), "F0", "start / final: a frame number outside the table") + need(c["ext"] == [], "EXT", "`ext` is not empty: the tools print no figure for such a file (gxdry.py:45,53)") + for T in range(v): + need(tuple(fr[start[T]]) == (ports[T],), "E1", "x_%d does not start on the line of its port" % T) # gx:143 + need(final[T] == 1, "E1", "x_%d does not end at the full space" % T) # gx:143 + f = fr[final[v + T]] + need(start[v + T] == 0, "E1", "y_%d does not start at the zero frame" % T) # gx:145 + need(len(f) == h - 1 and all(wt(u & ports[T]) % 2 == 0 for u in f), "E1", + "y_%d does not end at the hyperplane of its port" % T) # gx:144-145 + if small: + assert els[final[v + T]] == sum(1 << u for u in range(1 << h) if wt(u & ports[T]) % 2 == 0) + for r in range(2 * v, nreg): + need(start[r] == 0 and final[r] == 1, "E1", "helper %d does not start at zero / end at the full space" % r) # gx:146-147 + # ---- the gates, parsed (gx:120-126; core:32-36; Lean Data/Raw.lean:21-27) ------------------------------------- + def parse(g, where): + need(islist(g) and len(g) >= 1 and type(g[0]) is str, "F0", "gate %s: not a list" % where) + if g[0] == "out": # every tgt += (num/den) * src + need(len(g) == 5, "F0", "gate %s: an 'out' gate has 5 fields" % where) + f, s, tg, ex = g[1:] + need(isint(f) and isint(s) and islist(tg) and islist(ex) and all(isint(e) for e in ex), "F0", "gate %s: fields" % where) + need(all(islist(a) and len(a) == 3 and all(isint(z) for z in a) for a in tg), "F0", "gate %s: an add is [register, num, den]" % where) + need(all(a[2] > 0 for a in tg), "E0", "gate %s: a denominator is not positive" % where) # core:25-27 + return f, [s] + [a[0] for a in tg] + ex, [(a[0], s, a[1], a[2]) for a in tg] + need(g[0] == "in", "E0", "gate %s: unknown kind %r" % (where, g[0])) # core:35 + need(len(g) == 4, "F0", "gate %s: an 'in' gate has 4 fields" % where) + f, t, sr = g[1:] # tgt += sum of (num/den) * src, one after the other + need(isint(f) and isint(t) and islist(sr), "F0", "gate %s: fields" % where) + need(all(islist(a) and len(a) == 3 and all(isint(z) for z in a) for a in sr), "F0", "gate %s: an add is [register, num, den]" % where) + need(all(a[2] > 0 for a in sr), "E0", "gate %s: a denominator is not positive" % where) + return f, [t] + [a[0] for a in sr], [(t, a[0], a[1], a[2]) for a in sr] + need(islist(c["A"]) and islist(c["B"]), "F0", "A / B are not lists") + G = {ph: [parse(g, "%s%d" % (ph, i)) for i, g in enumerate(c[ph])] for ph in "AB"} + # ---- the totals and the scatter, parsed (gx:111-117, 166-171; core:37-41, 223-228) ---------------------------- + ret = c["ret"] + need(islist(ret) and all(islist(z) and len(z) == 3 and all(isint(q) for q in z) for z in ret), "F0", "ret") + nt = len(ret) + need(sorted(z[0] for z in ret) == list(range(nt)), "E2", "the totals are not numbered 0, 1, 2, ..") # gx:166 + tot_reg = {k: s for k, s, _ in ret} + sc = c["scat"] + need(type(sc) is dict, "F0", "scat") + if "table" in sc: + tb = sc["table"] + need(islist(tb) and all(islist(row) and all(islist(a) and len(a) == 3 and all(isint(z) for z in a) for a in row) for row in tb), "F0", "scatter table") + need(len(tb) == v and all(0 <= a[0] < nt for row in tb for a in row), "E2", "scatter table: not v rows, or a total that does not exist") # gx:168 + need(all(a[2] > 0 for row in tb for a in row), "E0", "scatter table: a denominator is not positive") + rows = [[(a[0], a[1], a[2]) for a in row] for row in tb] + else: + need("inside" in sc and "outside" in sc, "F0", "scat: neither a table nor the star rule") + for z in (sc["inside"], sc["outside"]): + need(islist(z) and len(z) == 2 and isint(z[0]) and isint(z[1]) and z[1] > 0, "E0", "star rule: coefficients") + need(nt == h, "E2", "star rule: not exactly one total per coordinate") # gx:171 + rows = [[(k,) + tuple(sc["inside"] if q >> k & 1 else sc["outside"]) for k in range(h)] for q in ports] # gx:116-117 + # ---- (E1, E2, E3, E6) the replay of the frames --------------------------------------------------------------- + cur = list(start) + chain = [[f] for f in start] + Hc = {k: Counter() for k in CLS} + + def climb(r, f, where): + o = cur[r] + if o != f: + need(dim[o] < dim[f], "E1", "%s: register %d would go from dimension %d to dimension %d" % (where, r, dim[o], dim[f])) # gx:157 + need(inside(o, f), "E1", "%s: register %d: its frame is not inside the frame of the gate" % (where, r)) # gx:157 + Hc[cls(r)][dim[f] - dim[o]] += 1 # gx:159 + cur[r] = f + chain[r].append(f) + ysum, pivs, ytg = Counter(), set(), set() + nadds = visits = most = 0 + kinds = Counter() + for ph in "AB": + if ph == "B": # the scatter cut (gx:165-175; core:223-233) + for k, s, f in ret: + need(2 * v <= s < nreg, "E2", "total %d is not held by a helper" % k) # gx:173 + need(0 <= f < nfr and cur[s] == f, "E2", "total %d: helper %d does not stand at the frame the file names" % (k, s)) # gx:173 + Hc["c"][dim[f]] += 1 # gx:174 + need(all(cur[v + t] == 0 for t in range(v)), "E2", "a y left the zero frame before the scatter") # gx:175 + for i, (f, regs, adds) in enumerate(G[ph]): + w = "gate %s%d" % (ph, i) + need(0 <= f < nfr, "F0", "%s: frame number outside the table" % w) + need(all(0 <= r < nreg for r in regs) and len(set(regs)) == len(regs), "E3", "%s: a register that does not exist, or one register twice" % w) # gx:178 + need(ph == "B" or all(cls(r) != "y" for r in regs), "E2", "%s: a y is named before the scatter" % w) # gx:190 + for r in regs: + climb(r, f, w) # gx:180-181 + assert all(cur[r] == f for r in regs) # every register named stands at the frame of the gate + visits += len(regs) + most = max(most, len(regs)) + for t, s, a, b in adds: + kd = (cls(s), cls(t)) + need(kd in KINDS and t != s, "E3", "%s: an addition %s -> %s is not allowed" % (w, kd[0], kd[1])) # gx:184, core:248 + need(ph == "B" or kd in KINDS_A, "E3", "%s: an addition %s -> %s before the scatter" % (w, kd[0], kd[1])) # gx:185 + if kd == ("y", "y"): # gx:186-189, core:250-254 + need(6 % b == 0, "E4", "%s: y reads y with a denominator that does not divide 6" % w) # core:251 + ysum[s, t] += Q(a, b) + pivs.add(s) + ytg.add(t) + nadds += 1 + kinds[ph, kd] += 1 + for r in range(nreg): + climb(r, final[r], "final climb") # gx:191-192 + need(not (pivs & ytg), "E4", "a y that is read by a y is itself the target of an addition reading a y") # gx:193 + need(all(x == 0 for x in ysum.values()), "E4", "the reads of one y by another do not cancel") # gx:194 + # every register's chain, tested once more on its own: strictly growing subspaces from start to final + for r in range(nreg): + ch = chain[r] + assert ch[0] == start[r] and ch[-1] == final[r] + for a, b in zip(ch, ch[1:]): + assert dim[a] < dim[b] and inside(a, b) + if small: + assert els[a] & ~els[b] == 0 and els[a] != els[b] + # ---- (E6) blocks, N, cst (gx:195-199; core:215-219) ---------------------------------------------------------- + mine = {k: {str(r): n for r, n in sorted(Hc[k].items())} for k in CLS} + need(type(c["blocks"]) is dict and all(type(w) is dict and all(isint(n) for n in w.values()) for w in c["blocks"].values()), + "F0", "blocks: not {class: {rank: whole number}}") + need(c["blocks"] == mine, "E6", "the block list of the file is not the one counted by the replay; counted: %s" % json.dumps(mine)) # gx:196 + N = sum(r * n for k in CLS for r, n in Hc[k].items()) + cst = sum(r * n for r, n in Hc["c"].items()) + need(N == c["N"], "E6", "N of the file is %d, the replay counts %d moves" % (c["N"], N)) # gx:199 + need(N == R * h + 2 * v * (h - 1) + c["cst"], "E6", "N is not R h + 2 v (h-1) + cst") # gx:199 + need(cst == c["cst"], "E6", "cst of the file is %d, the totals stand at dimensions that sum to %d" % (c["cst"], cst)) # core:219 + assert N == sum(dim[final[r]] - dim[start[r]] for r in range(nreg)) + cst + res.update(h=h, v=v, R=R, N=N, cst=cst, gates_A=len(G["A"]), gates_B=len(G["B"]), frames=nfr, single_adds=nadds, + scatter_adds=sum(map(len, rows)), visits=visits, most_registers_in_a_gate=most, blocks=mine, + totals=nt, total_dims=sorted(set(dim[f] for _, _, f in ret))) + say("frames: %d subspaces; every register climbs a strictly growing chain; every register named by a gate stands at the gate's frame" % nfr) + nb = {k: Counter() for k in "xys"} + for r in range(nreg): + nb[cls(r)][len(chain[r]) - 1] += 1 + res["blocks_per_register"] = {k: dict(sorted(nb[k].items())) for k in "xys"} + say("blocks per register {number of blocks: registers}: x %s y %s helpers %s" % tuple(dict(sorted(nb[k].items())) for k in "xys")) + say("h=%d v=%d R=%d gates A=%d B=%d single additions=%d (+ %d of the scatter = %d) most registers named by one gate=%d totals=%d at dimension %s" % ( + h, v, R, len(G["A"]), len(G["B"]), nadds, res["scatter_adds"], nadds + res["scatter_adds"], most, nt, res["total_dims"])) + res["additions_by_kind"] = {"%s: %s -> %s" % (ph, a, b): n for (ph, (a, b)), n in sorted(kinds.items())} + say("additions by phase and kind (source -> target; s = helper): %s; scatter: helper -> y %d" % ( + ", ".join("%s: %s" % kv for kv in res["additions_by_kind"].items()), res["scatter_adds"])) + say("moves of one invocation N=%d = R h + 2 v (h-1) + cst; copy moves cst=%d; blocks by class %s" % (N, cst, json.dumps(mine))) + # ---- (E5) exact replay of the contents (gx:209-250; core:268-315) -------------------------------------------- + t0 = time.time() + reg = [dict() for _ in range(nreg)] + for T in range(v): + reg[T][T] = Q(1) # gx:213 + dn = {"x": 1, "y": 1, "s": 1} + mx = {"x": Q(0), "y": Q(0), "s": Q(0)} + + def axpy(t, src, a, b, w, E=None): + if not src: + return + co, d, kk = Q(a, b), reg[t], cls(t) + for key, u in src.items(): + # self-test (h <= 12): an x or a helper receives a source only at a frame that contains the label of + # that source. This follows from the rules (contents move only inside one frame, frames only grow). + assert E is None or kk == "y" or E >> ports[key] & 1, "a source arrived outside its label's frames" + inc = co * u + # the mirror keeps contents in sixths and refuses an addition whose product is not a whole number of + # sixths (core:237, 277-278): (6 u) |a| must be divisible by b + need(6 % inc.denominator == 0, "E5", "%s: register %d would receive %s of source %d: not a multiple of 1/6" % (w, t, inc, key)) + x = d.get(key, 0) + inc + if x: + d[key] = x + if x.denominator != 1 and dn[kk] % x.denominator: + dn[kk] = dn[kk] * x.denominator // gcd(dn[kk], x.denominator) + if abs(x) > mx[kk]: + mx[kk] = abs(x) + else: + d.pop(key, None) + + def run(ph): + for i, (f, regs, adds) in enumerate(G[ph]): + w = "gate %s%d" % (ph, i) + E = els[f] if small else None + if c[ph][i][0] == "out": # the source is read once, before the additions (gx:237) + src = dict(reg[adds[0][1]]) if adds else {} + for t, s, a, b in adds: + axpy(t, src, a, b, w, E) + else: # one source after the other (gx:241-242) + for t, s, a, b in adds: + axpy(t, reg[s], a, b, w, E) + run("A") + tot = {k: dict(reg[s]) for k, s in tot_reg.items()} # gx:244 + for S in range(v): + for k, a, b in rows[S]: + axpy(v + S, tot[k], a, b, "scatter row %d" % S) # gx:245-247 + after_scatter = [dict(reg[v + S]) for S in range(v)] + run("B") + for T in range(v): + need(reg[T] == {T: 1}, "E5", "x_%d does not hold exactly its own source at the end (X3)" % T) # gx:249 + for S in range(v): + need(reg[v + S] == {S: 1}, "E5", "y_%d does not hold exactly 1 x source %d at the end (hid)" % (S, S)) # gx:250 + res["content_denominators"] = dict(dn) + res["content_max"] = {k: str(x) for k, x in mx.items()} + res["helpers_not_empty_at_end"] = sum(1 for r in range(2 * v, nreg) if reg[r]) + say("contents, exact (vectors over the %d sources): every x holds 1 x its own source, every y_S holds 1 x source S and nothing else [%.1f s]" % (v, time.time() - t0)) + say(" denominators met {class: lcm} %s largest entries %s helpers not empty at the end: %d of %d" % ( + dn, res["content_max"], res["helpers_not_empty_at_end"], R)) + # what the scatter alone gives y_S: its own source with coefficient 1, and what else + own = all(after_scatter[S].get(S) == 1 for S in range(v)) + foreign = sum(len(d) - (1 if S in d else 0) for S, d in enumerate(after_scatter)) + known = all(wt(ports[T] & ports[S]) % 2 == 0 for S, d in enumerate(after_scatter) for T in d if T != S) + res["scatter_gives_own_source"] = own + res["scatter_foreign_entries"] = foreign + res["scatter_foreign_all_in_hyperplane"] = known + say(" right after the scatter: every y_S holds its own source with coefficient 1: %s; other sources to be removed in phase B: %d entries, " + "every one with its label inside the hyperplane of S: %s" % (own, foreign, known)) + # ---- (E5 again) the same replay on random values, twice ------------------------------------------------------ + if not opt["norandom"]: + t0 = time.time() + for run_no in range(2): + seed = opt["seed"] + run_no if opt["seed"] is not None else int.from_bytes(os.urandom(16), "big") + rnd = random.Random(seed) + val = [Q(rnd.getrandbits(64) - (1 << 63), rnd.randint(1, 64)) for _ in range(v)] + z = [Q(0)] * nreg + z[:v] = val + for ph in "AB": + if ph == "B": + tv = {k: z[s] for k, s in tot_reg.items()} + for S in range(v): + z[v + S] += sum((Q(a, b) * tv[k] for k, a, b in rows[S]), Q(0)) + for i, (f, regs, adds) in enumerate(G[ph]): + if c[ph][i][0] == "out": + if adds: + sv = z[adds[0][1]] + for t, s, a, b in adds: + z[t] += Q(a, b) * sv + else: + for t, s, a, b in adds: + z[t] += Q(a, b) * z[s] + need(all(z[T] == val[T] and z[v + T] == val[T] for T in range(v)), "E5", "random-value run %d (seed %d): the end state is wrong" % (run_no, seed)) + res.setdefault("random_seeds", []).append(seed) + say("contents, two runs on fresh random rational values (seeds %s): x and y end with the right values [%.1f s]" % (res["random_seeds"], time.time() - t0)) + # ---- the unit of five stages (unit:22-36; fold:24) ----------------------------------------------------------- + inv = Counter() + for k in CLS: + for r, n in Hc[k].items(): + inv[r] += n # core:369-372 + H = Counter() + for r, n in inv.items(): + H[r] += 5 * n # unit:29-30 + for r in (h - 1, 2 * h - 2, 2 * h + 2, 4): + H[r] += 2 * v # unit:31-32, fold:24 + m, W = 5 * h, 4 * v + R # unit:33 + D = W * m - sum(r * n for r, n in H.items()) # unit:34 + need(D == 4 * v - 5 * cst, "UNIT", "moves saved %d is not 4 v - 5 cst = %d" % (D, 4 * v - 5 * cst)) # unit:35 + need(all(1 <= r <= m - 1 for r in H), "UNIT", "a block of the unit has a rank outside 1 .. m-1") + U = dict(m=m, W=W, D=D, H=dict(sorted(H.items()))) + res.update(m=m, W=W, D=D, unit_blocks=sorted(H.items()), invocation_blocks=sorted(inv.items())) + say("one invocation, blocks (rank, count): %s" % sorted(inv.items())) + say("unit of five stages: block size m=%d arrays W=%d moves saved D=%d moves=%d blocks (rank, count): %s" % ( + m, W, D, W * m - D, sorted(H.items()))) + need(D > 0, "UNIT", "the unit saves no move") + # ---- the figure (fold:8, 56-68, 86-111; unit:39-47; rate:26-32; gxdry.py:49-52) ------------------------------ + t0 = time.time() + for B, sb in ((10, 40), (8, 13)): + fg = figures(U, B, sb) + need(fg is not None, "FIG", "no figure at %d decimals" % B) + res["figure_%d" % B] = fg + say("%d decimals, fill 1 - 2^-%d: whole-block %d (the inequality is true up to %d and false at %d); per-rank %d (true up to %d)%s" % ( + B, sb, fg["block"], fg["block_true"], fg["block_true"] + 1, fg["rank"], fg["rank_true"], + " [relative slack of the certificate %.2e; %d-bit interval arithmetic; %.1f s]" % (fg["slack"], fg["bits"], time.time() - t0) if B == 10 else "")) + res["figure"] = res["figure_10"]["block"] + # ---- Lean-facing extras (not rules of the two checkers) ------------------------------------------------------ + extras = [] + + def extra(name, ok, text): + extras.append((name, bool(ok), text)) + say("extra %-3s %s %s" % (name, "pass" if ok else "FAIL", text)) + extra("X1", all(q != full for q in ports), "no port is the all-ones vector (Lean Labels/EndDef.lean:30; gxgen.py:33)") + extra("X2", all(dim[f] >= 1 for _, _, f in ret), "every total stands at a frame of dimension at least 1 (Lean Labels/EndDef.lean:49-52)") + extra("X3", len(set(dim[f] for _, _, f in ret)) == 1, "all totals stand at frames of ONE dimension (gxbind.py:232-233): %s" % res["total_dims"]) + extra("X4", [z[0] for z in ret] == list(range(nt)), "the totals are listed in the order 0, 1, 2, .. (gsmirror.py:98)") + extra("X5", h <= 255, "h <= 255 (Lean Labels/Def.lean:53)") + net_ok = 4 % dn["x"] == 0 and 4 % dn["s"] == 0 and 24 % dn["y"] == 0 + extra("X6", net_ok, "net contents: x and helpers in quarters, y in twenty-fourths (the units gsmirror.py:119-121 tries)") + if not opt["noparts"]: + t0 = time.time() + sp = parts(v, R, G, rows, tot_reg) + if sp is None: + extra("X7", False, "replay with separate positive and negative parts: no unit choice of the grid passes") + else: + res["SPar"] = sp["spar"] + extra("X7", sp["tag_ok"], "replay with separate positive and negative parts (Lean Scalar/Def.lean:62-112, 185-218): passes; " + "SPar d sw ux us uy = <%d, %d, %d, %d, %d>; largest digit %d; additions with a division %d [%.1f s]" % ( + tuple(sp["spar"]) + (sp["digit"], sp["divs"], time.time() - t0))) + res["extras"] = {n: ok for n, ok, _ in extras} + res["extras_ok"] = all(ok for _, ok, _ in extras) + return res + + +# ===================================================================================================================== +# 4. the replay Lean makes: positive and negative parts kept apart, fixed units (own code, written from the Lean text +# Work/GCert/Scalar/Def.lean: gW :85-91, gDiv :62-66, gAcc :95-99, gFin :185-192; unit grid of gsm:117-133) +# ===================================================================================================================== +class Fail(Exception): + pass + + +def parts_run(units, mode, v, R, G, rows, tot_reg): + ux, us, uy = units + v2, nreg = 2 * v, 2 * v + R + unit = lambda r: ux if r < v else uy if r < v2 else us + P = [dict() for _ in range(nreg)] + N = [dict() for _ in range(nreg)] + st = dict(digit=max(ux, uy), cost=0, divs=0, adds=0) + for T in range(v): + if mode == "x": + P[T][T] = ux + else: + P[v + T][T] = uy + + def add(t, s, num, den): + A, Bb = abs(num) * unit(t), den * unit(s) + g = gcd(A, Bb) + a, b = A // g, Bb // g # the weight in digits, reduced (Def.lean:85-91) + st["adds"] += 1 + st["cost"] += 2 * a + (2 * b if b > 1 else 0) + sp, sn = (P[s], N[s]) if num >= 0 else (N[s], P[s]) + if b > 1: # both parts of the source are divided by b, exactly (Def.lean:62-66, 96) + if any(x % b for x in sp.values()) or any(x % b for x in sn.values()): + raise Fail() + st["divs"] += 1 + if a == 0: + return + for dst, src in ((P[t], sp), (N[t], sn)): + for k, x in src.items(): + if x: + y = dst.get(k, 0) + a * (x // b) + dst[k] = y + if y > st["digit"]: + st["digit"] = y + if mode == "x": + for f, regs, adds in G["A"]: + for t, s, a, b in adds: + add(t, s, a, b) + for S in range(v): + for k, a, b in rows[S]: + add(v + S, tot_reg[k], a, b) + for f, regs, adds in G["B"]: + for t, s, a, b in adds: + if mode == "x" or v <= s < v2: # the y check replays only the additions that read a y (Def.lean:21-22) + add(t, s, a, b) + + def net(r): + d = {} + for k in set(P[r]) | set(N[r]): + x = P[r].get(k, 0) - N[r].get(k, 0) + if x: + d[k] = x + return d + for T in range(v): + if mode == "x" and net(T) != {T: ux}: + raise Fail() + if net(v + T) != {T: uy}: + raise Fail() + return st + + +def parts(v, R, G, rows, tot_reg): + best = None + for ux in (1, 2, 4): + for us in (1, 2, 4): + for uy in (1, 2, 3, 6, 12, 24): + try: + s1 = parts_run((ux, us, uy), "x", v, R, G, rows, tot_reg) + s2 = parts_run((ux, us, uy), "y", v, R, G, rows, tot_reg) + except Fail: + continue + dg = max(s1["digit"], s2["digit"]) + sw = dg.bit_length() + 1 # every digit below 2^(sw-1) (Def.lean:15-16) + cand = (sw, s1["cost"] + s2["cost"], ux, us, uy, dg, s1["divs"]) + if best is None or cand < best: + best = cand + if best is None: + return None + sw, _, ux, us, uy, dg, divs = best + nreg = 2 * v + R + d = max(1, (nreg - 1).bit_length()) + half = 1 << (sw - 1) + # Def.lean:207-218: units below half; the 64-bit tag (a sum of digit * weight, weight < 2^32) stays below 2^63 + tag_ok = ux < half and uy < half and v * half < (1 << 31) + return dict(spar=[d, sw, ux, us, uy], digit=dg, divs=divs, tag_ok=tag_ok) + + +# ===================================================================================================================== +def main(): + args = sys.argv[1:] + files = [a for a in args if a not in ("e8", "json", "noparts", "norandom") and not a.startswith("seed=")] + if len(files) != 1: + sys.stderr.write(__doc__) + sys.exit(2) + opt = dict(e8="e8" in args, noparts="noparts" in args, norandom="norandom" in args, seed=None) + for a in args: + if a.startswith("seed="): + opt["seed"] = int(a[5:]) + path = files[0] + t0 = time.time() + + def say(s): + print(" " + s, flush=True) + res, verdict, code = {}, None, 1 + try: + c, sha = load(path) + print("replay.py: %s sha256 %s" % (os.path.basename(path), sha), flush=True) + res["sha256"] = sha + res.update(check(c, opt, say)) + if res["extras_ok"]: + verdict, code = "ACCEPTED", 0 + else: + verdict, code = "ACCEPTED BY THE RULES OF THE TWO CHECKERS, BUT NOT LEAN-READY (extras failed: %s)" % ", ".join( + n for n, ok in res["extras"].items() if not ok), 3 + print("REPLAY %s: R=%d W=%d D=%d cst=%d N=%d figure=%d%s (%.1f s)" % ( + verdict, res["R"], res["W"], res["D"], res["cst"], res["N"], res["figure"], + " E8 family: %s" % res["e8_family"], time.time() - t0), flush=True) + except Refuse as e: + verdict = "REFUSED" + res["refused"] = str(e) + print("REPLAY REFUSED: %s" % e, flush=True) + except Exception as e: # anything unforeseen counts as a refusal + verdict = "REFUSED" + res["refused"] = "CRASH: %r" % (e,) + print("REPLAY REFUSED: CRASH: the program stopped with %r" % (e,), flush=True) + res["verdict"] = verdict + res["exit"] = code + if "json" in args: + print("JSON " + json.dumps(res, sort_keys=True), flush=True) + sys.exit(code) + + +if __name__ == "__main__": + main() diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldgen.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldgen.py new file mode 100644 index 0000000000..a6287172ba --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldgen.py @@ -0,0 +1,128 @@ +"""Lean texts of the rate lemmas of one unit (library; used by crate.py): the block list, the whole-block +fact, its sharpness, the per-rank fact and its sharpness. Lean re-checks every number in the generated module. +""" +from fractions import Fraction +import foldlib as fl +from foldlib import frac_lean + + +NS = 'OAI.PowerSaving.BlockAccounting' + + +def block_text(name, u, A, B, s): + P = fl.plan_block(u, A, B, s) + assert P is not None, 'whole-block fact does not pass the rational check' + m, W, H = u['m'], u['W'], u['H'] + eps = '%d/(10:ℝ)^%d' % (A, B) + z = '(1 - %s)' % eps + blk = 'blocks' + name + o = [] + o.append('/-- **whole-block fact** of `%s` at exponent `1 - %d/10^%d`, fill parameter `s = %d`: the hypothesis `hnum` of `RAM.engine_program_group_list` (u = %d, W = %d). Relative slack of the rational certificate: %.2e. -/' % (blk, A, B, s, m, W, P['slack_rel'])) + o.append('theorem fold_%s :' % name) + o.append(' ((2:ℝ)^%d - 1) * moment %d %s %s' % (s, m, z, blk)) + o.append(' + ((%d:ℕ):ℝ) * (T %d %s (%d - 1) 1 + T %d %s 1 1)' % (W, m, z, m, m, z)) + o.append(' < (2:ℝ)^%d * ((%d:ℕ):ℝ) := by' % (s, W)) + terms = ' + ('.join('T %d %s %d %d' % (m, z, r, H[r]) for r in sorted(H)) + ' + 0' + ')' * (len(H) - 1) + o.append(' have hsum : moment %d %s %s\n = %s := rfl' % (m, z, blk, terms)) + for i, (r, n, L, N, v, q) in enumerate(P['rows'] + P['idle']): + o.append(' have b%d : T %d %s %d %d ≤ %s :=' % (i, m, z, r, n, frac_lean(q))) + o.append(' term_le %d %d %d (%s) %s _ (by norm_num) (by norm_num) (by norm_num) (by norm_num)' % (m, r, n, eps, frac_lean(L))) + o.append(' (log_le_of_le_expsum _ _ %d (by norm_num) (by norm_num)' % N) + o.append(' (by norm_num [Finset.sum_range_succ, Nat.factorial]))') + o.append(' (by norm_num) (by norm_num)') + o.append(' have e1 : ((2:ℝ)^%d - 1) = %d := by norm_num' % (s, 2 ** s - 1)) + o.append(' have e2 : (2:ℝ)^%d = %d := by norm_num' % (s, 2 ** s)) + o.append(' have e3 : ((%d:ℕ):ℝ) = %d := by norm_num' % (W, W)) + o.append(' have e4 : T %d %s (%d - 1) 1 = T %d %s %d 1 := rfl' % (m, z, m, m, z, m - 1)) + o.append(' rw [e1, e2, e3, e4, hsum]') + o.append(' linarith') + o.append('') + return '\n'.join(o), P + + +def sharp_text(name, u, A1, B): + P = fl.plan_sharp(u, A1, B) + assert P is not None, 'no sharpness certificate at %d' % A1 + m, W, H = u['m'], u['W'], u['H'] + eps = '%d/(10:ℝ)^%d' % (A1, B) + z = '(1 - %s)' % eps + blk = 'blocks' + name + o = [] + o.append('/-- **sharpness**: at exponent `1 - %d/10^%d` the moment of one unit is at least its number of live roles `%d`, so the moment criterion fails for EVERY table made of copies of the unit and idle roles (`FoldRate.block_fails`). Relative excess of the rational certificate: %.2e. -/' % (A1, B, W, P['slack_rel'])) + o.append('theorem fold_%s_sharp : ((%d:ℕ):ℝ) ≤ moment %d %s %s := by' % (name, W, m, z, blk)) + terms = ' + ('.join('T %d %s %d %d' % (m, z, r, H[r]) for r in sorted(H)) + ' + 0' + ')' * (len(H) - 1) + o.append(' have hsum : moment %d %s %s\n = %s := rfl' % (m, z, blk, terms)) + for i, (r, n, L, s, nn, v, q) in enumerate(P['rows']): + o.append(' have c%d : %s ≤ T %d %s %d %d :=' % (i, frac_lean(q), m, z, r, n)) + o.append(' term_ge %d %d %d (%s) %s _ (by norm_num) (by norm_num) (by norm_num) (by norm_num)' % (m, r, n, eps, frac_lean(L))) + o.append(' (le_log_of_expbound _ _ %d %d (by norm_num) (by norm_num) (by norm_num)' % (s, nn)) + o.append(' (by norm_num [Finset.sum_range_succ, Nat.factorial]))') + o.append(' (by norm_num)') + o.append(' have e3 : ((%d:ℕ):ℝ) = %d := by norm_num' % (W, W)) + o.append(' rw [e3, hsum]') + o.append(' linarith') + o.append('') + return '\n'.join(o), P + + +def rank_text(name, u, A, B, s): + P = fl.plan_rank(u, A, B, s) + assert P is not None, 'per-rank fact does not pass the rational check' + m, W, D = u['m'], u['W'], u['D'] + eps = '%d/(10:ℝ)^%d' % (A, B) + o = [] + o.append('/-- **per-rank fact** at exponent `1 - %d/10^%d`, fill parameter `s = %d`: the hypothesis `hnum` of `RAM.engine_program_group_perRank` (u = %d, W = %d, D = %d). Relative slack: %.2e. -/' % (A, B, s, m, W, D, P['slack_rel'])) + o.append('theorem foldRank_%s :' % name) + o.append(' (2:ℝ)^%d * ((%d:ℕ):ℝ) * (((%d:ℕ):ℝ) - ((%d:ℕ):ℝ)^(1 - %s)) < ((2:ℝ)^%d - 1) * ((%d:ℕ):ℝ) :=' % (s, W, m, m, eps, s, D)) + o.append(' FoldRate.rank_fact3 %d %d %d %d (%s) %s (by norm_num) (by norm_num) (by norm_num)' % (m, W, D, s, eps, frac_lean(P['L']))) + o.append(' (log_le_of_le_expsum _ _ %d (by norm_num) (by norm_num)' % P['N']) + o.append(' (by norm_num [Finset.sum_range_succ, Nat.factorial]))') + o.append(' (by norm_num) (by norm_num)') + o.append('') + return '\n'.join(o), P + + +def list_text(name, u, doc): + m, W, D, H = u['m'], u['W'], u['D'], u['H'] + blk = 'blocks' + name + lst = '[' + ', '.join('(%d, %d)' % (r, H[r]) for r in sorted(H)) + ']' + o = [] + o.append('/-- %s -/' % doc) + o.append('def %s : List (ℕ × ℕ) := %s' % (blk, lst)) + o.append('') + o.append('/-- total rank of one unit (= number of unit moves it stands for): `W * m - D` -/') + o.append('theorem %s_rank : (%s.map fun b => b.1 * b.2).sum = %d * %d - %d := by' % (blk, blk, W, m, D)) + o.append(' norm_num [%s]' % blk) + o.append('') + o.append('/-- the same as a price: the unit list at the price list `r ↦ r` (shape of `hPid` in `RAM.engine_program_group_perRank`) -/') + o.append('theorem %s_tally : (%s.map fun b => (b.2:ℝ) * ((b.1:ℕ):ℝ)).sum = ((%d:ℕ):ℝ) * ((%d:ℕ):ℝ) - ((%d:ℕ):ℝ) := by' % (blk, blk, W, m, D)) + o.append(' norm_num [%s]' % blk) + o.append('') + o.append('theorem %s_count : (%s.map fun b => b.2).sum = %d := by' % (blk, blk, sum(H.values()))) + o.append(' norm_num [%s]' % blk) + o.append('') + o.append('theorem %s_proper : ∀ b ∈ %s, 1 ≤ b.1 ∧ b.1 < %d := by' % (blk, blk, m)) + o.append(' decide') + o.append('') + return '\n'.join(o) + + +def rank_sharp_text(name, u, A1, B): + """D <= W (m - m^(1-eps')) from a rational lower bound of log m""" + m, W, D = u['m'], u['W'], u['D'] + eps = Fraction(A1, 10 ** B) + L, s, nn = fl.gen_sharp.log_lower(m, 1, 12) + x = eps * L + if not (x <= 1 and D <= W * m * (x - x * x / 2)): + return None + e = '%d/(10:ℝ)^%d' % (A1, B) + o = [] + o.append('/-- **per-rank sharpness**: at exponent `1 - %d/10^%d` the deficit of one unit is at most `W (m - m^z)`, so the per-rank inequality fails for EVERY table made of copies of the unit and idle roles (`FoldRate.rank_fails`). -/' % (A1, B)) + o.append('theorem foldRank_%s_sharp :' % name) + o.append(' ((%d:ℕ):ℝ) ≤ ((%d:ℕ):ℝ) * (((%d:ℕ):ℝ) - ((%d:ℕ):ℝ)^(1 - %s)) :=' % (D, W, m, m, e)) + o.append(' FoldRate.rank_fact_sharp %d %d %d (%s) %s (by norm_num) (by norm_num) (by norm_num)' % (m, W, D, e, frac_lean(L))) + o.append(' (le_log_of_expbound _ _ %d %d (by norm_num) (by norm_num) (by norm_num)' % (s, nn)) + o.append(' (by norm_num [Finset.sum_range_succ, Nat.factorial]))') + o.append(' (by norm_num) (by norm_num)') + o.append('') + return '\n'.join(o) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldlib.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldlib.py new file mode 100644 index 0000000000..2cd642ec9e --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/foldlib.py @@ -0,0 +1,146 @@ +"""Numbers for the rate lemmas of one unit (library; used by crate.py and foldgen.py). Exact rational +certificates; Lean re-checks all. + +One UNIT = one element of the group: W live roles, block list H = {rank: count} (all blocks of the +unit, live and scratch), label dimension m, deficit D = W*m - sum r*H[r]. + +Table of the generic lemma (Work/FoldRate/Group.lean): fill parameter s, t = 2^s. + whole-block fact : (t-1) * M(z) + W * ((m-1)/m)^z + W * (1/m)^z < t * W, M(z) = sum H[r] (r/m)^z + whole-block sharp : W <= M(z') (then the fact fails for EVERY s) + per-rank fact : t * W * (m - m^z) < (t-1) * D +""" +from fractions import Fraction +from decimal import Decimal, getcontext +import gen_rates, gen_sharp # log_upper, log_lower, frac_lean +from gen_rates import frac_lean +getcontext().prec = 80 + + +# bank blocks of the bridged word B_2 beyond `5 * 2v` blocks of rank h-1 (see unit()): +# B2 (merged idle climbs) : X1,Y1 = 3 x (h-1), 2h+2; X2,Y2 = 2h-2, h-1, 2 x (h-1), 4 +# B2t (only the tail of pair 1) : X1,Y1 = 3 x (h-1), 2h+2; X2,Y2 = 5 x (h-1), 4 +# B2u (unmerged) : every bank role 5 x (h-1), 4 +BANK = { + 'B2': [(2, lambda h: h - 1), (2, lambda h: 2 * h - 2), (2, lambda h: 2 * h + 2), (2, lambda h: 4)], + 'B2t': [(6, lambda h: h - 1), (2, lambda h: 2 * h + 2), (2, lambda h: 4)], + 'B2u': [(10, lambda h: h - 1), (4, lambda h: 4)], + # two more cuts, NOT generated by default (only if the network delivers them): + # B2s : X1,Y1 = 3 x (h-1), 2h-2, 4; X2,Y2 = 2h-2, h-1, 2 x (h-1), 4 (L16: 40380 / 40381) + # B2w : X1,Y1 = 5 x (h-1), 4; X2,Y2 = 2h-2, h-1, 2 x (h-1), 4 (L16: 40017 / 40018) + 'B2s': [(2, lambda h: h - 1), (4, lambda h: 2 * h - 2), (4, lambda h: 4)], + 'B2w': [(6, lambda h: h - 1), (2, lambda h: 2 * h - 2), (4, lambda h: 4)], +} + + +def moment_dec(H, m, eps): + z = Decimal(1) - Decimal(eps.numerator) / Decimal(eps.denominator) + return sum(Decimal(n) * (Decimal(r) / Decimal(m)) ** z for r, n in H.items()) + + +def block_lhs_dec(u, eps, s): + """(t-1) M + W c - t W (negative = holds)""" + t = 2 ** s + m, W = u['m'], u['W'] + z = Decimal(1) - Decimal(eps.numerator) / Decimal(eps.denominator) + c = (Decimal(m - 1) / Decimal(m)) ** z + (Decimal(1) / Decimal(m)) ** z + return (t - 1) * moment_dec(u['H'], m, eps) + W * c - t * W + + +def rank_lhs_dec(u, eps, s): + t = 2 ** s + m, W, D = u['m'], u['W'], u['D'] + z = Decimal(1) - Decimal(eps.numerator) / Decimal(eps.denominator) + return t * W * (Decimal(m) - Decimal(m) ** z) - (t - 1) * D + + +def best_units(u, B, s): + """largest A with the whole-block fact at fill parameter s, the first A' with W <= M (fails at + every fill), and the same two for per-rank; by high-precision evaluation""" + def last_true(f): + lo, hi = 0, 10 ** B + while hi - lo > 1: + mid = (lo + hi) // 2 + if f(mid): + lo = mid + else: + hi = mid + return lo + A = last_true(lambda a: block_lhs_dec(u, Fraction(a, 10 ** B), s) < 0) + Af = last_true(lambda a: moment_dec(u['H'], u['m'], Fraction(a, 10 ** B)) < u['W']) + 1 + Ar = last_true(lambda a: rank_lhs_dec(u, Fraction(a, 10 ** B), s) < 0) + m, W, D = u['m'], u['W'], u['D'] + Arf = last_true(lambda a: W * (Decimal(m) - Decimal(m) ** (Decimal(1) - Decimal(a) / Decimal(10 ** B))) < D) + 1 + return A, Af, Ar, Arf + + +def ceil_frac(x, G): + y = x * 10 ** G + return Fraction(-((-y.numerator) // y.denominator), 10 ** G) + + +def floor_frac(x, G): + y = x * 10 ** G + return Fraction(y.numerator // y.denominator, 10 ** G) + + +def plan_block(u, A, B, s, Dd=12): + """upper bounds q of every term T m z r n (unit list) and of the two idle terms, with + (t-1) sum q + W (qa + qb) < t W checked exactly""" + eps = Fraction(A, 10 ** B) + t = 2 ** s + m, W, H = u['m'], u['W'], u['H'] + rows = [] + for r, n in [(r, H[r]) for r in sorted(H)] + [(m - 1, 1), (1, 1)]: + L, N = gen_rates.log_upper(m, r, Dd) + x = eps * L + assert x <= 1 + val = n * Fraction(r, m) * (1 + x + x * x / 2 + x ** 3 * Fraction(2, 9)) + rows.append([r, n, L, N, val]) + nH = len(H) + exact = (t - 1) * sum(row[4] for row in rows[:nH]) + W * (rows[nH][4] + rows[nH + 1][4]) + margin = t * W - exact + if margin <= 0: + return None + G = 0 + while Fraction((t - 1) * nH + 2 * W, 10 ** G) > margin / 50: + G += 1 + for row in rows: + row.append(ceil_frac(row[4], G)) + tot = (t - 1) * sum(row[5] for row in rows[:nH]) + W * (rows[nH][5] + rows[nH + 1][5]) + assert tot < t * W + return dict(rows=rows[:nH], idle=rows[nH:], G=G, slack_rel=float(margin / (t * W))) + + +def plan_sharp(u, A1, B, Dd=12): + """lower bounds q of every term with sum q >= W""" + eps = Fraction(A1, 10 ** B) + m, W, H = u['m'], u['W'], u['H'] + rows = [] + for r in sorted(H): + n = H[r] + L, s, nn = gen_sharp.log_lower(m, r, Dd) + x = eps * L + rows.append([r, n, L, s, nn, n * Fraction(r, m) * (1 + x + x * x / 2 + x ** 3 / 6)]) + margin = sum(row[5] for row in rows) - W + if margin < 0: + return None + G = 0 + while margin > 0 and Fraction(len(rows), 10 ** G) > margin / 50: + G += 1 + for row in rows: + row.append(floor_frac(row[5], G)) + assert sum(row[6] for row in rows) >= W + return dict(rows=rows, G=G, slack_rel=float(margin / W)) + + +def plan_rank(u, A, B, s, Dd=12): + """rational upper bound L of log m with t W m (x - x^2/2 + x^3/4) < (t-1) D, x = eps L""" + eps = Fraction(A, 10 ** B) + t = 2 ** s + m, W, D = u['m'], u['W'], u['D'] + L, N = gen_rates.log_upper(m, 1, Dd) + x = eps * L + lhs = t * W * m * (x - x * x / 2 + x ** 3 / 4) + if not (x <= 1 and lhs < (t - 1) * D): + return None + return dict(L=L, N=N, slack_rel=float(1 - lhs / ((t - 1) * D))) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_rates.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_rates.py new file mode 100644 index 0000000000..8f90a197ba --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/gen_rates.py @@ -0,0 +1,30 @@ +"""Rational bounds used by the rate lemmas (library; used by foldlib.py). + +log_upper(m, r, D): a rational upper bound L of log(m/r) with D decimals and the number N of terms of the +exponential series with m/r <= sum_{i 0 + s = 0 + while L / 2 ** s > Fraction(1, 2): + s += 1 + y = L / 2 ** s + target = Fraction(m, r) + n = 2 + while True: + S, term = Fraction(0), Fraction(1) + for i in range(n): + S += term + term = term * y / (i + 1) + fact = 1 + for i in range(2, n + 1): + fact *= i + U = S + y ** n * (n + 1) / (fact * n) + if U ** (2 ** s) <= target: + return L, s, n + n += 1 + assert n < 60 diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/ChallengeB2L16x.lean.txt b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/ChallengeB2L16x.lean.txt new file mode 100644 index 0000000000..5863ad32a0 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/ChallengeB2L16x.lean.txt @@ -0,0 +1,331 @@ +import Mathlib + +/-! +Comparator challenge `Work.BridgeRate.ChallengeB2L16x` (not part of github.com/openai/math). + +Statement: the Walsh-Hadamard corollary with the exponent `1 - 4059928/10^10` in place of +`1 - 2/10^11`. Theorem: `OAI.PowerSaving.WHT.wht_main_block_B2L16x`. + +GENERATED by checks/wht9/bridge-rate/pack.py: this file is the comparator-passed +`Corollaries/WHTTwoStage/Challenge.lean` with exactly three changes: (1) this header comment; +(2) the name of the theorem (`wht_main_two_stage` there) and the exponent quoted in its doc +comment; (3) the exponent constant in the statement (`1 - 66451/(10:ℝ)^12` there, +`1 - 4059928/(10:ℝ)^10` here). All other lines are byte-for-byte the lines of that file: the RAM +cost model, `whtInKind`, `whtOutKind`, `wht`, `WHTProgram` and `WHTTimeBoundsAt`. + +The proof is `sorry` on purpose: this file is a STATEMENT. The proof is in +`Work.BridgeRate.SolutionB2L16x`. +-/ + +namespace OAI + +/-! +# Exact scalar and index RAM used for the algorithm + +Finite, first-order, expression/program syntax. Arrays below are random-access arrays of +registers (an array-valued register holds its address). An expression building an array uses +a fresh array; `sow` builds by a loop of writes instead of a loop supplying consecutive +entries. Programs have their usual sequential stack evaluation. Evaluation here records work +(including stack, index and array work), the high water mark on produced/logically looped-over +integer values (addresses *within* arrays are integers too), the value, and the side condition +required along the executed path (in particular no division by zero). The charged units of +work are constant time; as usual constant rescalings between ways to charge a fixed number +of scalar or address operations are immaterial. + +Enough address bits must be provided BOTH for the integer high water mark (and inputs), AND +for the work bound together with input size, as will be required in the theorem. Indeed we +use the particularly simple RAM convention where temporaries aren't reused: one work unit can +leave at most a constant number of cells (stack, pairs or array cells); whenever many array +entries are made their number is charged. So a constant number of words of those sizes also +suffices for arena addresses. Nothing charges constant work for changing an already published +array to a different array as a whole. Register and stack layouts, and the convention whether +registers hold pairs or addresses of pairs, only have constant factors (the program is fixed). + +Scalar and data field registers are separated. Tests and loop/request sizes are on nonnegative +integer registers. There is no instruction for an arbitrary complex constant. A supplied +specified root will be an input. Divisions are on prepared scalars; valid runs require every +such denominator nonzero; the side condition is *not* a test performed by the algorithm. +The Bool mode on the syntax allows or prohibits general products (two-input convolution +versus the transform); even when allowed we use separate register kinds before and after +the bilinear products. + +Definitions are mathematical operation-count semantics, not a model of running Lean code. +E.g. a function on Fin n represents the n cells of a random-access array, not a function +closure at runtime. +-/ + +namespace PowerSaving + +universe u v + +variable {α : Type u} {β : Type v} + +/-- Register arrays. -/ +structure Tape (α : Type u) where + len : ℕ + pos : Fin len → α + +namespace Tape + +def empty (α : Type u) : Tape α := ⟨0, Fin.elim0⟩ + +/-- Materialized array. -/ +def tab (n : ℕ) (f : ℕ → α) : Tape α := ⟨n, fun i => f i.val⟩ + +/-- Read with fixed out of bounds default. -/ +def look (v : Tape α) (i : ℕ) (z : α) : α := + if h : i < v.len then v.pos ⟨i,h⟩ else z + +@[simp] theorem look_of_lt (v : Tape α) (z : α) {i} (h : i < v.len) : + v.look i z = v.pos ⟨i,h⟩ := by simp [look, h] + +@[simp] theorem look_of_le (v : Tape α) (z : α) {i} (h : v.len ≤ i) : + v.look i z = z := by simp [look, Nat.not_lt.mpr h] + +/-- Semantics of a write into fresh storage; out-of-range writes are ignored. Only used + during construction, never a whole-tape functional update instruction. -/ +def set (v : Tape α) (i : ℕ) (x : α) : Tape α := + ⟨v.len, fun j => if j.val = i then x else v.pos j⟩ + +def sow (len count : ℕ) (z : α) (f : ℕ → ℕ × α) : Tape α := + iter count +where + iter : ℕ → Tape α + | 0 => tab len (fun _ => z) + | i+1 => (iter i).set (f i).1 (f i).2 + +def map (f : α → β) (v : Tape α) : Tape β := ⟨v.len, fun i => f (v.pos i)⟩ + +end Tape + +namespace RAM + +inductive Paint + | scalar + | left + | right + | both + +inductive Ty + | w + | c : Paint → Ty + | p : Ty → Ty → Ty + | a : Ty → Ty + +open Ty + +abbrev sc := c .scalar + +@[reducible] def Ty.T : Ty → Type + | w => ℕ + | c _ => ℂ + | p s b => s.T × b.T + | a b => Tape b.T + +noncomputable def Ty.blank : (t : Ty) → t.T + | w => 0 + | c _ => 0 + | p s t => (s.blank, t.blank) + | a b => Tape.empty b.T + +/-- One basic work unit below pays for O(1) primitive RAM operations; includes loop and + stack overhead. `peak` tracks produced/needed integer quantities beyond inputs + (total allocation for stack and array bases is covered separately by work). -/ +structure Bill (α : Type u) where + val : α + work : ℕ + peak : ℕ + valid : Prop + +namespace Bill + +/-- Charge some work and optionally a new word bound. -/ +def pay (b : Bill α) (n : ℕ) (m : ℕ) : Bill α := + ⟨b.val, b.work+n, max b.peak m, b.valid⟩ + +/-- Both computations are evaluated. -/ +def pass (b : Bill α) (f : α → Bill β) : Bill β := + let d := f b.val + ⟨d.val, b.work+d.work, max b.peak d.peak, b.valid ∧ d.valid⟩ + +def one (x : α) : Bill α := ⟨x,1,0,True⟩ +def word (x : ℕ) : Bill ℕ := ⟨x,1,x,True⟩ + +/-- Execute f 0 through f (n-1), iterating an accumulator. -/ +def steps (init : α) (f : ℕ → α → Bill α) : ℕ → Bill α + | 0 => Bill.one init + | i+1 => ((steps init f i).pass (f i)).pay 1 (i+1) + +/-- Build Tape len by count writes (initialized with a blank z). -/ +def sow (len count : ℕ) (z : α) (f : ℕ → Bill (ℕ × α)) : Bill (Tape α) := + (steps (Tape.tab len (fun _ => z)) + (fun i v => (f i).pass (fun s => one (v.set s.1 s.2))) count).pay (1+len) len + +/-- Build Tape len. As for sow we can first allocate then perform writes. -/ +def tab (len : ℕ) (z : α) (f : ℕ → Bill α) : Bill (Tape α) := + sow len len z (fun i => (f i).pass (fun y => one (i,y))) + +end Bill + +inductive NOp + | add | sub | mul | div | mod | lt -- truncated subtraction; compare returns 1 or 0 + +inductive Atom (allow : Bool) : Ty → Ty → Type + | lit {a} (n : ℕ) : Atom allow a w + | int (f : NOp) : Atom allow (p w w) w + | cz (t) {a} : Atom allow a (c t) + | cone {a} : Atom allow a sc + | add (t) : Atom allow (p (c t) (c t)) (c t) + | sub (t) : Atom allow (p (c t) (c t)) (c t) + | scale (t) : Atom allow (p sc (c t)) (c t) + | inv : Atom allow sc sc + | cross (h : allow = true) : + Atom allow (p (c .left) (c .right)) (c .both) + | id {a} : Atom allow a a + | fst {a b} : Atom allow (p a b) a + | snd {a b} : Atom allow (p a b) b + | len {s} : Atom allow (a s) w + | look {s} : Atom allow (p (a s) w) s + +noncomputable def NOp.run : NOp → (ℕ × ℕ) → Bill ℕ + | .add, (i,j) => Bill.word (i+j) + | .sub, (i,j) => Bill.word (i-j) + | .mul, (i,j) => Bill.word (i*j) + | .div, (i,j) => Bill.word (i/j) -- includes usual guard (returns zero) + | .mod, (i,j) => Bill.word (i%j) -- like Lean: returns i if j=0 + | .lt, (i,j) => Bill.word (if i Bill.word n + | .int f, x => f.run x + | .cz _, _ => Bill.one 0 + | .cone, _ => Bill.one 1 + | .add _, (x,y) => Bill.one (x+y) + | .sub _, (x,y) => Bill.one (x-y) + | .scale _, (x,y) => Bill.one (x*y) + | .inv, x => ⟨x⁻¹,1,0,x ≠ 0⟩ + | .cross _, (x,y) => Bill.one (x*y) + | .id, x => Bill.one x + | .fst, x => Bill.one x.1 + | .snd, x => Bill.one x.2 + | .len, x => Bill.word x.len + | @Atom.look _ s, (x,i) => Bill.one (x.look i s.blank) + +abbrev Port := Option (Ty × Ty) + +/-- `call` is internal for bounded recursion; a program has Port = none. `loop`, `tab` + and `sow` retain the input to access parameters in the body. `descend` sets up bounded + recursion, reading fuel and initial argument. -/ +inductive Code (allow : Bool) : Port → Ty → Ty → Type + | atom {r s t} (op : Atom allow s t) : Code allow r s t + | comp {r s t u} (f : Code allow r s t) (g : Code allow r t u) : Code allow r s u + | fork {r s t u} (f : Code allow r s t) (g : Code allow r s u) : Code allow r s (p t u) + | ifz {r s t} (q : Code allow r s w) (f g : Code allow r s t) : Code allow r s t + | loop {r s t} (n : Code allow r s w) (init : Code allow r s t) + (body : Code allow r (p s (p w t)) t) : Code allow r s t + | tab {r s t} (n : Code allow r s w) + (body : Code allow r (p s w) t) : Code allow r s (a t) + | sow {r s t} (n count : Code allow r s w) + (body : Code allow r (p s w) (p w t)) : Code allow r s (a t) + | importClosed {r s t} (f : Code allow none s t) : Code allow r s t + | call {s t} : Code allow (some (s,t)) s t + | descend {r s t} (base : Code allow none s t) + (body : Code allow (some (s,t)) s t) : Code allow r (p w s) t + +@[reducible] def Handler : Port → Type + | none => Unit + | some (s,t) => s.T → Bill t.T + +def depthRun (base : α → Bill β) + (step : (α → Bill β) → (α → Bill β)) : ℕ → α → Bill β + | 0, x => (base x).pay 1 0 + | n+1, x => (step (depthRun base step n) x).pay 1 (n+1) + +noncomputable def Code.run {allow r s t} : Code allow r s t → Handler r → s.T → Bill t.T + | .atom op, _, x => op.run x + | .comp f g, h, x => ((f.run h x).pass (g.run h)).pay 1 0 + | .fork f g, h, x => (f.run h x).pass (fun y => (g.run h x).pass (fun z => Bill.one (y,z))) + | .ifz q f g, h, x => ((q.run h x).pass (fun y => + if (y : ℕ) = 0 then f.run h x else g.run h x)).pay 1 0 + | .loop n init body, h, x => + ((n.run h x).pass (fun l => (init.run h x).pass (fun y => + Bill.steps y (fun i z => body.run h (x,(i,z))) l))).pay 1 0 + | @Code.tab _ _ _ t n body, h, x => + ((n.run h x).pass (fun l => + Bill.tab l t.blank (fun i => body.run h (x,i)))).pay 1 0 + | @Code.sow _ _ _ t n count body, h, x => + ((n.run h x).pass (fun l => (count.run h x).pass (fun k => + Bill.sow l k t.blank (fun i => body.run h (x,i))))).pay 1 0 + | .importClosed f, _, x => (f.run () x).pay 1 0 + | .call, h, x => (h x).pay 1 0 + | .descend base step, _, (k,x) => + (depthRun (base.run ()) (step.run) k x).pay 1 k + +abbrev Prog (allow : Bool) (s t : Ty) := Code allow none s t + +noncomputable abbrev run {allow s t} (f : Prog allow s t) (x : s.T) : Bill t.T := + f.run () x + +end RAM +end PowerSaving + +namespace PowerSaving +namespace WHT +noncomputable section + +section Statement +open RAM RAM.Ty Filter Asymptotics + +/-- Input `(k, I, x)`: the exponent, the scalar constant `I` (the RAM has no instruction +producing it), and the data array of length `2^k`. Same register kinds as `dftInKind`. -/ +abbrev whtInKind := p w (p sc (a (c Paint.left))) +abbrev whtOutKind := a (c Paint.left) + +/-- Walsh-Hadamard transform of length `2^k` in natural (Sylvester) order: +`wht k x j = ∑ l, (-1)^(number of common 1-bits of j and l) * x l`. -/ +def wht (k : ℕ) (x : Fin (2^k) → ℂ) : Fin (2^k) → ℂ := + fun j => ∑ l : Fin (2^k), + (∏ i ∈ Finset.range k, if j.val.testBit i && l.val.testBit i then (-1 : ℂ) else 1) * x l + +/-- One fixed program `solve`; on input `(k, I, x)` it returns the Walsh-Hadamard transform +of `x`, every run is valid (no division by zero), all integers produced and the work +allowance are polynomial in `N = 2^k`, and the work is at most `W k`. -/ +def WHTProgram (solve : Prog false whtInKind whtOutKind) (W : ℕ → ℕ) : Prop := + ∃ cBound : ℕ, ∀ k : ℕ, + let N := 2^k + let cap := (N+2)^cBound + W k + 10*(N+2) ≤ cap ∧ + ∀ x : Fin N → ℂ, + let result := run solve (k, Complex.I, (⟨N,x⟩ : Tape ℂ)) + result.valid ∧ result.peak ≤ cap ∧ result.work ≤ W k ∧ + result.val = (⟨N, wht k x⟩ : Tape ℂ) + +end Statement + +-- Same `open`/`universe` context as `Exponent.lean` (lines 32, 266-267, 321-322), minus the +-- namespaces that do not exist without the upstream development +-- (`Bench`, `Selection`, `Cluster`, `RAM.Bench`, `Binary`). +open RAM Filter Asymptotics +open RAM RAM.Ty Matrix Finset Complex +universe U V + +section Explicit +open Filter Asymptotics + +/-- `W = O(2^k (k+1)^β)` and `W = o(2^k k)` (`WHTTimeBounds` is the case `β = 1 - 2/10^11`). -/ +def WHTTimeBoundsAt (β : ℝ) (W : ℕ → ℕ) : Prop := + let W' := fun k : ℕ => (W k : ℝ) + W' =O[atTop] (fun k : ℕ => (2:ℝ)^k * ((k:ℝ)+1)^β) ∧ + W' =o[atTop] (fun k : ℕ => (2:ℝ)^k * (k:ℝ)) + +/-- **Walsh-Hadamard transform with the improved exponent**: the statement `WHTGoal` of +`WHTCheck/Challenge.lean` with `1 - 2/10^11` replaced by `1 - 4059928/10^10`. -/ +theorem wht_main_block_B2L16x : + ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 4059928/(10:ℝ)^10) W := by + sorry + +end Explicit +end +end WHT +end PowerSaving +end OAI diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/SolutionB2L16x.lean.txt b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/SolutionB2L16x.lean.txt new file mode 100644 index 0000000000..c111b98f65 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gen/templates/SolutionB2L16x.lean.txt @@ -0,0 +1,38 @@ +import Work.BridgeRate.B2L16x + +/-! +Comparator solution `Work.BridgeRate.SolutionB2L16x` (not part of github.com/openai/math). + +The whole proof is in `Work.BridgeRate.B2L16x` (and its imports), which ends with + + theorem wht_main_B2L16x : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - 4059928/(10:ℝ)^10) W + +This module adds nothing mathematical: it defines `WHT.WHTTimeBoundsAt` with the text of the +challenge (the same definition as `BlockWHT.WHTTimeBoundsAt` of `Work.Block.WHT`) and restates +the theorem under the name the challenge uses. Its proof is that single term. +`WHTProgram`, `wht`, `whtInKind`, `whtOutKind` come from `WHTCheck.Solution`. +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open Filter Asymptotics + +/-- `W = O(2^k (k+1)^β)` and `W = o(2^k k)` (`WHTTimeBounds` is the case `β = 1 - 2/10^11`). -/ +def WHTTimeBoundsAt (β : ℝ) (W : ℕ → ℕ) : Prop := + let W' := fun k : ℕ => (W k : ℝ) + W' =O[atTop] (fun k : ℕ => (2:ℝ)^k * ((k:ℝ)+1)^β) ∧ + W' =o[atTop] (fun k : ℕ => (2:ℝ)^k * (k:ℝ)) + +/-- **Walsh-Hadamard transform with the improved exponent**: the statement `WHTGoal` of +`WHTCheck/Challenge.lean` with `1 - 2/10^11` replaced by `1 - 4059928/10^10`. -/ +theorem wht_main_block_B2L16x : + ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 4059928/(10:ℝ)^10) W := + wht_main_B2L16x + +end WHT +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.WHT.wht_main_block_B2L16x diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gsmirror.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gsmirror.py new file mode 100644 index 0000000000..35af7ef46b --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gsmirror.py @@ -0,0 +1,332 @@ +#!/usr/bin/python3 -I +"""gx-scalar: Python mirror of GS.scalCheck / GS.yCheck (Work/GCert/Scalar/Def.lean). + +usage: gsmirror.py [emit=] [cuts=i,j,..] + prints the parameters (d, sw, ux, us, uy) for which both checks pass, and sizes; + emit= writes TEST modules Work/GCert/Scalar/Gen/.lean (scalar fields of GXD.Raw only), + Scal0.lean (one evaluation), Y.lean, and with cuts= Seg.lean (segments cut before these items). +As a library (gx-data): params(c), bigreplay(c, pr, lo, n, itemsA, itemsB, cuts), lean_state(name, state). +""" +import sys, json, gzip, os +from math import gcd + +import gxpaths +ROOT = gxpaths.OUT.rstrip('/') + + +def load(path): + op = gzip.open if path.endswith(".gz") else open + with op(path, "rt") as f: + return json.load(f) + + +def adds_of(g): + if g[0] == "out": + return [(t, g[2], a, b) for t, a, b in g[3]] + if g[0] == "inn" or g[0] == "in": + return [(g[2], s, a, b) for s, a, b in g[3]] + raise SystemExit("unknown gate %r" % (g[0],)) + + +def scat_rows(c): + sc = c["scat"] + if "table" in sc: + return [[(k, a, b) for k, a, b in row] for row in sc["table"]] + (ia, ib), (oa, ob) = sc["inside"], sc["outside"] + return [[(k, ia, ib) if p >> k & 1 else (k, oa, ob) for k in range(c["h"] - 1, -1, -1)] for p in c["ports"]] + + +class Fail(Exception): + pass + + +def replay(c, units, mode): + """mode 'x': scalCheck with one batch (0, v); mode 'y': yCheck. Returns the largest digit.""" + v, R = c["v"], c["R"] + v2, nr = 2 * v, 2 * v + R + ux, us, uy = units + unit = lambda r: ux if r < v else uy if r < v2 else us + P = [dict() for _ in range(nr)] + N = [dict() for _ in range(nr)] + mx = [max(ux, uy)] + nadd = [0, 0, 0] + if mode == "x": + for t in range(v): + P[t][t] = ux + else: + for t in range(v): + P[v + t][t] = uy + + def add(t, s, a, b, ok): + if not ok or t == s or not (t < nr and s < nr) or b <= 0: + raise Fail("kind / bounds: %d += (%d/%d) %d" % (t, a, b, s)) + A, B = abs(a) * unit(t), b * unit(s) + g = gcd(A, B) + wa, wb = A // g, B // g + nadd[0] += 1 + nadd[1] += 2 * wa + (2 * wb if wb > 1 else 0) + sp, sn = (P[s], N[s]) if a >= 0 else (N[s], P[s]) + if wb > 1 and any(x % wb for x in sp.values()) or wb > 1 and any(x % wb for x in sn.values()): + raise Fail("digit not divisible by %d" % wb) + if wb > 1: + nadd[2] += 1 + if wa == 0: + return + for dst, src in ((P[t], sp), (N[t], sn)): + for k, x in src.items(): + if x == 0: + continue + y = dst.get(k, 0) + wa * (x // wb) + dst[k] = y + if y > mx[0]: + mx[0] = y + + okA = lambda t, s: v2 <= t and (s < v or v2 <= s) + okS = lambda t, s: v <= t < v2 and v2 <= s < nr + okB = lambda t, s: (v <= t or s < v) and (s < v or v2 <= s or v <= t < v2) + if mode == "x": + for g in c["A"]: + for t, s, a, b in adds_of(g): + add(t, s, a, b, okA(t, s)) + rows = scat_rows(c) + if len(rows) != v: + raise Fail("scatter rows") + for t, row in enumerate(rows): + for k, a, b in row: + if not k < len(c["ret"]): + raise Fail("scatter total") + s = c["ret"][k][1] + add(v + t, s, a, b, okS(v + t, s)) + for g in c["B"]: + for t, s, a, b in adds_of(g): + if mode == "x" or v <= s < v2: + add(t, s, a, b, okB(t, s)) + net = lambda r: {k: x - N[r].get(k, 0) for k, x in P[r].items() if x != N[r].get(k, 0)} + for r in range(nr): + if any(k not in P[r] for k in N[r]): + for k in N[r]: + P[r].setdefault(k, 0) + for t in range(v): + if mode == "x" and net(t) != {t: ux}: + raise Fail("X3 at %d" % t) + if net(v + t) != {t: uy}: + raise Fail("identity at y %d" % t) + return mx[0], nadd + + +def params(c): + best = None + for ux in (1, 2, 4): + for us in (1, 2, 4): + for uy in (1, 2, 3, 6, 12, 24): + try: + m1, n1 = replay(c, (ux, us, uy), "x") + m2, n2 = replay(c, (ux, us, uy), "y") + except Fail as e: + continue + sw = max(m1, m2).bit_length() + 1 + cand = (sw, n1[1] + n2[1], ux, us, uy, m1, m2, n1, n2) + if best is None or cand < best: + best = cand + if best is None: + raise SystemExit("REJECTED for every unit choice") + return best + + +TAU = lambda T: (2654435761 * (T + 1)) % 4294967296 + + +def bigreplay(c, pr, lo, n, itemsA, itemsB, cuts=()): + """EXACT mirror of GS.segCheck on Python integers (leaves with tags). + itemsA / itemsB: the chunks of gates (lists of gates) of A and B as in raw.A / raw.B; item index: + A chunks 0 .. len(itemsA)-1, the scatter = len(itemsA), B chunks after it. + cuts: item indices i; the state BEFORE item i is returned as a sorted list of (register, leaf), leaf != 0. + Raises Fail if a test of the kernel check fails.""" + d, sw, ux, us, uy = pr + v, R = c["v"], c["R"] + v2, nr, hi = 2 * v, 2 * v + R, lo + n + K = 64 + sw * n + m2 = 1 << K + rep = sum(1 << (sw * i) for i in range(n)) + tm = ((rep << (sw - 1)) << 64) | (1 << 63) + half = 1 << (sw - 1) + if not (ux >= 1 and us >= 1 and uy >= 1 and sw >= 1 and nr <= 1 << d and hi <= v and ux < half and uy < half): + raise Fail("parameters") + unit = lambda r: ux if r < v else uy if r < v2 else us + P, N = [0] * nr, [0] * nr + for T in range(n): + P[lo + T] = (ux << (64 + sw * T)) + ux * TAU(T) + + def div(b, X): + if b == 1: + return X + q = X // b + if q & tm or q * b != X: + raise Fail("division by %d" % b) + for j in range(1, b + 1): + if (j * q) & tm: + raise Fail("division mask") + return q + + def addn(acc, q, a): + for _ in range(a): + acc += q + if acc & tm: + raise Fail("digit overflow") + return acc + + def add(t, s, ca, cb, ok): + if not ok or t == s or cb < 1: + raise Fail("kind / bounds: %d += (%d/%d) %d" % (t, ca, cb, s)) + A, B = abs(ca) * unit(t), cb * unit(s) + g = gcd(A, B) + a, b = A // g, B // g + qp, qn = div(b, P[s]), div(b, N[s]) + if ca < 0: + qp, qn = qn, qp + pt, nt = addn(P[t], qp, a), addn(N[t], qn, a) + if not pt < m2: + raise Fail("positive part too long") + P[t], N[t] = pt, nt + + inr = lambda t, s: t < nr and s < nr + okA = lambda t, s: inr(t, s) and v2 <= t and (s < v or v2 <= s) + okS = lambda t, s: v <= t < v2 and v2 <= s < nr + okB = lambda t, s: inr(t, s) and (v <= t or s < v) and (s < v or v2 <= s or v <= t < v2) + out = {} + snap = lambda: sorted((r, P[r] + (N[r] << K)) for r in range(nr) if P[r] or N[r]) + idx = 0 + for gs in itemsA: + if idx in cuts: + out[idx] = snap() + for g in gs: + for t, s, ca, cb in adds_of(g): + add(t, s, ca, cb, okA(t, s)) + idx += 1 + if idx in cuts: + out[idx] = snap() + rows = scat_rows(c) + ret = [s for _, s, _ in sorted(c["ret"])] + for t, row in enumerate(rows): + for k, ca, cb in row: + if not k < len(ret): + raise Fail("scatter total") + add(v + t, ret[k], ca, cb, okS(v + t, ret[k])) + if len(rows) != v: + raise Fail("scatter rows") + idx += 1 + for gs in itemsB: + if idx in cuts: + out[idx] = snap() + for g in gs: + for t, s, ca, cb in adds_of(g): + add(t, s, ca, cb, okB(t, s)) + idx += 1 + for S in range(v): + E = lambda u: (u << (sw * (S - lo))) if lo <= S < hi else 0 + if (P[S] >> 64) != (N[S] >> 64) + E(ux) or (P[v + S] >> 64) != (N[v + S] >> 64) + E(uy): + raise Fail("final test at %d" % S) + return out + + +def lean_state(name, st, size=100): + """Lean text of a cut state: chunk definitions and `name : List (List (Nat × Nat))` (argument of GS.loadK)""" + out, names = [], [] + for i in range(0, len(st), size): + nm = "%s_%d" % (name, i // size) + names.append(nm) + out.append("noncomputable def %s : List (Nat × Nat) := [\n %s]" % ( + nm, ",\n ".join("(%d, 0x%x)" % rw for rw in st[i:i + size]))) + out.append("noncomputable def %s : List (List (Nat × Nat)) := [%s]" % (name, ", ".join(names))) + return "\n".join(out) + + +def co(a, b): + return "⟨%s, %d, %d⟩" % ("true" if a < 0 else "false", abs(a), b) + + +def lgate(g): + if g[0] == "out": + return "(.out %d %d [%s] [%s])" % (g[1], g[2], ", ".join("(%d, %s)" % (t, co(a, b)) for t, a, b in g[3]), + ", ".join(map(str, g[4]))) + return "(.inn %d %d [%s])" % (g[1], g[2], ", ".join("(%d, %s)" % (s, co(a, b)) for s, a, b in g[3])) + + +CH = 150 + + +def emit(c, name, pr, cutlist): + """TEST modules: data (scalar fields only), one-evaluation check, y check, and (if cutlist) a segmented check""" + d, sw, ux, us, uy = pr + gen = ROOT + "/Work/GCert/Scalar/Gen" + os.makedirs(gen, exist_ok=True) + out = ["import Work.GCert.Scalar.Seg", "/-! generated by checks/wht26/gx-scalar/py/gsmirror.py: SCALAR TEST DATA (frames, pairs, cuts left empty) -/", + "set_option maxRecDepth 100000", "namespace GS.Gen.%s" % name, "open GXD"] + chunks = {} + for ph in ("A", "B"): + chunks[ph] = [c[ph][i:i + CH] for i in range(0, len(c[ph]), CH)] + for i, gs in enumerate(chunks[ph]): + out.append("noncomputable def %s%d : List Gate := [\n %s]" % (ph, i, ",\n ".join(map(lgate, gs)))) + out.append("noncomputable def %s : List (List Gate) := [%s]" % (ph, ", ".join("%s%d" % (ph, i) for i in range(len(chunks[ph]))))) + sc = c["scat"] + if "table" in sc: + scat = ".table [\n %s]" % ",\n ".join("[%s]" % ", ".join("(%d, %s)" % (k, co(a, b)) for k, a, b in row) for row in sc["table"]) + else: + scat = ".star %s %s" % (co(*sc["inside"]), co(*sc["outside"])) + out.append("noncomputable def ports : List Nat := [%s]" % ", ".join(map(str, c["ports"]))) + out.append("noncomputable def scat : Scat := %s" % scat) + out.append("noncomputable def raw : Raw :=\n { h := %d, v := %d, R := %d, N := %d, cst := %d, ports := ports, frames := [], start := [], final := [],\n" + " ret := [%s], scat := scat, A := A, B := B, pairs := [], cuts := [], ext := [], obase := [] }" % ( + c["h"], c["v"], c["R"], c["N"], c["cst"], ", ".join("(%d, %d)" % (s, f) for _, s, f in sorted(c["ret"])))) + out.append("end GS.Gen.%s" % name) + open("%s/%s.lean" % (gen, name), "w").write("\n".join(out) + "\n") + v = c["v"] + par = "⟨%d, %d, %d, %d, %d⟩" % pr + tpl = ("import Work.GCert.Scalar.Gen.%s\nset_option maxRecDepth 100000\nnamespace GS.Gen.%s\n" % (name, name)) + open("%s/%sScal0.lean" % (gen, name), "w").write( + tpl + "theorem scal0_ok : GS.scalCheck raw %s 0 %d = true := by decide +kernel\n#print axioms scal0_ok\nend GS.Gen.%s\n" % (par, v, name)) + open("%s/%sY.lean" % (gen, name), "w").write( + tpl + "theorem ychk_ok : GS.yCheck raw %s 0 %d = true := by decide +kernel\n#print axioms ychk_ok\nend GS.Gen.%s\n" % (par, v, name)) + if cutlist: + nA, nB = len(chunks["A"]), len(chunks["B"]) + items = ["Item.cA A%d" % i for i in range(nA)] + ["Item.scat"] + ["Item.cB B%d" % i for i in range(nB)] + sts = bigreplay(c, pr, 0, v, chunks["A"], chunks["B"], cutlist) + body = [tpl.replace("import Work.GCert.Scalar.Gen.%s" % name, "import Work.GCert.Scalar.Gen.%s" % name) + "open GS"] + for i in cutlist: + body.append(lean_state("L%d" % i, sts[i])) + body.append("noncomputable def T%d : SSC.Trie := loadK %d L%d" % (i, d, i)) + bounds = [0] + list(cutlist) + [len(items)] + for j in range(len(bounds) - 1): + pre = "none" if j == 0 else "(some T%d)" % bounds[j] + post = "none" if j == len(bounds) - 2 else "(some T%d)" % bounds[j + 1] + body.append("theorem seg%d_ok : segCheck raw %s 0 %d %s [%s] %s = true := by decide +kernel" % ( + j, par, v, pre, ", ".join(items[bounds[j]:bounds[j + 1]]), post)) + body.append("end GS.Gen.%s" % name) + open("%s/%sSeg.lean" % (gen, name), "w").write("\n".join(body) + "\n") + print("segments at items", cutlist, "of", len(items), "; state sizes (non-zero leaves):", [len(sts[i]) for i in cutlist]) + print("emitted", name) + + +def main(): + path = sys.argv[1] + opts = dict(a.split("=") for a in sys.argv[2:]) + c = load(path) + sw, _, ux, us, uy, m1, m2, n1, n2 = params(c) + nr = 2 * c["v"] + c["R"] + d = max(1, (nr - 1).bit_length()) + print("file", os.path.basename(path), "h v R", c["h"], c["v"], c["R"], "registers", nr) + print("SPar d sw ux us uy = ⟨%d, %d, %d, %d, %d⟩" % (d, sw, ux, us, uy)) + print("largest digit: x-replay %d, y-replay %d; adds x-replay %d (bignum additions %d, adds with a division %d), y-replay %d (%d)" % ( + m1, m2, n1[0], n1[1], n1[2], n2[0], n2[1])) + print("vector bits (one batch):", sw * c["v"]) + pr = (d, sw, ux, us, uy) + chA = [c["A"][i:i + CH] for i in range(0, len(c["A"]), CH)] + chB = [c["B"][i:i + CH] for i in range(0, len(c["B"]), CH)] + bigreplay(c, pr, 0, c["v"], chA, chB) + print("exact mirror of segCheck (integers with tags): ACCEPTED; items", len(chA) + 1 + len(chB)) + if "emit" in opts: + emit(c, opts["emit"], pr, [int(x) for x in opts["cuts"].split(",")] if "cuts" in opts else []) + + +if __name__ == "__main__": + main() diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxbind.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxbind.py new file mode 100644 index 0000000000..fcb625619c --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxbind.py @@ -0,0 +1,438 @@ +"""gxbind.py: THE BINDING of the generator to the Lean terms of gx-scalar / gx-labels / +gx-chain. Everything that names somebody else's definition is in this file (tables SCAL, LAB, CHAIN).""" +import os, re, subprocess +import gxpaths +ROOT = gxpaths.OUT +GSM = gxpaths.HERE + '/gsmirror.py' + +# gx-scalar (gcert-interface.md, SCALAR v1): GS.scalCheck c p lo n, GS.yCheck c p lo n, p : GS.SPar = +SCAL = dict(imports=['Work.GCert.Scalar.Seg'], scal='GS.scalCheck raw ⟨%(d)d, %(sw)d, %(ux)d, %(us)d, %(uy)d⟩ %(lo)d %(n)d', + ychk='GS.yCheck raw ⟨%(d)d, %(sw)d, %(ux)d, %(us)d, %(uy)d⟩ 0 %(v)d') +# gx-labels (gcert-interface.md LABELS v1 + questions.md N1): namespace GLab; frame = code, table and states = SSC.Trie, +# GLab.Par = . `end` = GLab.endK of Labels/EndDef.lean (questions.md N2; no obaseK: Q1 closed). +LAB = dict(imports=['Work.GCert.Labels.Def'], end_imports=['Work.GCert.Labels.EndDef'], par='⟨%(h)d, %(n)d, %(d)d, %(K)d, tab⟩', ns='GLab', + tab='GLab.tabK %(h)d %(sub)s', seg='GLab.segK par %(gs)s st%(i)d st%(j)d %(rs)s', + end='GLab.endK par %(v)d ports (raw.ret.map Prod.fst) st0 st%(a)d st%(f)d', noadds='GLab.noAdds fins') +# gx-chain (CHAIN v1): GX.wht_of_halves; the terms below are PLACEHOLDERS until Labels/Main and Scalar/Main compile +CHAIN = dict(imports=['Work.GCert.Chain.End', 'Work.GCert.Labels.Main'], scal='(GS.ScalOK.scal GXD.%(c)s.scalOK)', + lab='(GXD.%(c)s.valid.lab GXD.%(c)s.scalOK)', lab_cost='GXD.%(c)s.lab_cost') + + +def code(h, basis): + """gx-labels' code of a reduced echelon basis: dim + 2^8 M + 2^(8+h) P (M = pivot mask, vector of pivot p at digit p)""" + M = P = 0 + for b in basis: + p = b.bit_length() - 1 + M |= 1 << p + P |= b << (h * p) + return len(basis) + (M << 8) + (P << (8 + h)) + + +MOD = '''import %(imports)s +/-! Kernel check (%(doc)s) of the gcert/1 certificate `GXD.%(name)s.raw`. Source: %(src)s. +Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +namespace GXD.%(name)s +open GXD +theorem %(thm)s : %(stmt)s := by decide +kernel +end GXD.%(name)s +#print axioms GXD.%(name)s.%(thm)s +''' + + +def spar(D, path): + """scalar parameters: from gx-scalar's mirror when it exists, else from my own replay (sw is then a GUESS)""" + import gxcore as gc + n, d = 2 * D['v'] + D['R'], 0 + while (1 << d) < n: + d += 1 + dg = gc.digits(D) + S = dict(d=d, sw=16, ux=dg['x'][0], us=dg['s'][0], uy=dg['y'][0], source='gx-data replay; sw = 16 is a GUESS', digits=dg) + if os.path.exists(GSM): + try: + o = subprocess.run(['python3', '-B', GSM, path], capture_output=True, text=True, timeout=1800).stdout + m = re.search(r'SPar[^\d]*(\d+)[, ]+(\d+)[, ]+(\d+)[, ]+(\d+)[, ]+(\d+)', o) + if m: + S.update(zip(('d', 'sw', 'ux', 'us', 'uy'), map(int, m.groups())), source='gsmirror.py') + except Exception as e: + S['source'] += ' (gsmirror.py failed: %r)' % (e,) + return S + + +def write_checks(D, M, name, src, out, L, S, plan): + base = out[len(ROOT):].replace('/', '.') + raw = '%s.Gen.%s' % (base, name) + h, v, n = D['h'], D['v'], 2 * D['v'] + D['R'] + res = [] + + def mod(suffix, imports, thm, stmt, doc): + m = '%s.Gen.%s%s' % (base, name, suffix) + open('%s/Gen/%s%s.lean' % (out, name, suffix), 'w').write(MOD % dict( + imports='\nimport '.join(imports), doc=doc, name=name, src=src, thm=thm, stmt=stmt)) + res.append((m, thm, stmt)) + for i, (lo, hi) in enumerate(M['scal']['batches']): + mod('Scal%d' % i, SCAL['imports'] + [raw], 'scal%d_ok' % i, SCAL['scal'] % dict(S, lo=lo, n=hi - lo) + ' = true', + 'scalar identity E3 E5 for the sources %d .. %d' % (lo, hi - 1)) + mod('YChk', SCAL['imports'] + [raw], 'ychk_ok', SCAL['ychk'] % dict(S, v=v) + ' = true', 'the y -> y adds, E4') + par = '%s.Gen.%sPar' % (base, name) + open('%s/Gen/%sPar.lean' % (out, name), 'w').write( + 'import %s\nimport %s\n/-! Parameters `GLab.Par` of the label check of `GXD.%s.raw` (h, registers, trie depth, K, frame table).\n' + 'Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/\nnamespace GXD.%s\nopen GXD\n' + 'noncomputable def par : GLab.Par := %s\nend GXD.%s\n' + % (LAB['imports'][0], raw, name, name, LAB['par'] % dict(h=h, n=n, d=L['d'], K=L['K']), name)) + paths = [format(i, '0%db' % L['ts']) for i in range(1 << L['ts'])] if L['ts'] else [''] + for i, pth in enumerate(paths): + mod('Tab%d' % i, LAB['imports'] + [raw], 'tab%d_ok' % i, + LAB['tab'] % dict(h=h, sub='tab_n' + pth if pth else 'tab') + ' = true', + 'E0: subtrie %d of %d of the frame table (codes of reduced echelon bases)' % (i, len(paths))) + for i in range(L['nseg']): + mod('Seg%d' % i, [par], 'seg%d_ok' % i, + LAB['seg'] % dict(gs='seg%d' % i, i=i, j=i + 1, rs='rs%d' % i) + ' = true', + 'E1: replay of the gates %d .. %d (phase %s) and their block ranks' % ( + M['cuts'][i], M['cuts'][i + 1] - 1, 'A' if i < L['nsegA'] else 'B')) + mod('SegF', [par], 'segF_ok', LAB['seg'] % dict(gs='fins', i=L['nseg'], j=L['nseg'] + 1, rs='rF') + ' = true', + 'E1: the final climbs and their block ranks') + if LAB['end']: + mod('End', LAB['end_imports'] + [par], 'end_ok', LAB['end'] % dict(v=v, a=L['nsegA'], f=L['nseg'] + 1) + ' = true', + 'E1 E2: frames at the start, at the scatter, at the end') + return res + + +def nest(xs): + return ' ++ ('.join(xs) + ')' * (len(xs) - 1) if xs else '[]' + + +def write_hist(D, M, name, src, out, L): + """kernel counts of the block ranks on the EXPLICIT rank lists rA, rB, rF (no replay)""" + base = out[len(ROOT):].replace('/', '.') + h, rs = D['h'], M['lab']['rs'] + ph = {'A': sum(rs[:L['nsegA']], []), 'B': sum(rs[L['nsegA']:], []), 'F': M['lab']['rF']} + top = max(max(x) if x else 0 for x in ph.values()) + cop = [M['dim'][f] for _, f in D['ret']] + tot = {r: sum(x.count(r) for x in ph.values()) + cop.count(r) for r in range(1, max(top, max(cop)) + 1)} + assert {r: c for r, c in tot.items() if c} == M['hist'], 'histogram of the rank lists differs from the mirror' + lines = ['/-- block ranks of phase A / phase B, in order (the lists of the replay segments) -/', + 'noncomputable def rA : List Nat := ' + nest(['rs%d' % i for i in range(L['nsegA'])]), + 'noncomputable def rB : List Nat := ' + nest(['rs%d' % i for i in range(L['nsegA'], L['nseg'])])] + names = [] + for X, lst in sorted(ph.items()): + l = 'r' + X + lines.append('theorem rankBound%s : wsumK (SSC.wGt %d) %s 0 = 0 := by decide +kernel' % (X, top, l)) + lines += ['theorem rank%s%d_ok : wsumK (SSC.wEq %d) %s 0 = %d := by decide +kernel' % (X, r, r, l, lst.count(r)) + for r in range(top + 1)] + names += ['rankBound' + X] + ['rank%s%d_ok' % (X, r) for r in range(top + 1)] + txt = ('import Work.GCert.Data.Count\nimport %s.Gen.%s\n' % (base, name) + + '/-! Kernel count of the BLOCK RANKS of the gcert/1 certificate `GXD.%s.raw` (h = %d) on the explicit rank lists\n' + '`rA`, `rB`, `rF` (phase A, phase B, final climbs): `wsumK (SSC.wEq r) l 0` blocks of rank `r`, none above %d\n' + '(`GXD.sum_of_wsumK` turns a count into `(l.map wt).sum` = `SSC.wsum wt l`).\n' + 'The %d scratch copies (ranks %s) are not in these lists. Whole invocation, by rank: %s.\n' + 'Source: %s. Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/\n' + 'set_option maxRecDepth 100000\nnamespace GXD.%s\nopen GXD\n' % ( + name, h, top, len(cop), sorted(set(cop)), M['hist'], src, name) + '\n'.join(lines) + + '\nend GXD.%s\n' % name + '\n'.join('#print axioms GXD.%s.%s' % (name, x) for x in names[:2]) + '\n') + open('%s/Gen/%sHist.lean' % (out, name), 'w').write(txt) + return '%s.Gen.%sHist' % (base, name) + + +def write_price(D, M, name, src, out, L): + """Mathlib module: the price of the rank lists rA, rB, rF from the kernel counts, and of one whole invocation""" + base = out[len(ROOT):].replace('/', '.') + rs = M['lab']['rs'] + ph = {'A': sum(rs[:L['nsegA']], []), 'B': sum(rs[L['nsegA']:], []), 'F': M['lab']['rF']} + top = max(max(x) if x else 0 for x in ph.values()) + cop = [M['dim'][f] for _, f in D['ret']] + tm = lambda cnt: ' + '.join('%d * φ %d' % (n, r) for r, n in sorted(cnt.items()) if n) or '0' + thms = '' + for X in 'ABF': + cnt = {r: ph[X].count(r) for r in range(1, top + 1)} + thms += ''' +/-- price of the blocks of %s, from the kernel counts -/ +theorem r%s_cost (φ : ℕ → ℝ) : rcost φ r%s = %s := by + rw [GXD.rcost_wsumK φ r%s %d rankBound%s] + simp only [Finset.sum_range_succ, Finset.sum_range_zero, %s] + norm_num [bcost] +''' % ({'A': 'phase A', 'B': 'phase B', 'F': 'the final climbs'}[X], X, X, tm(cnt), X, top, X, + ', '.join('rank%s%d_ok' % (X, r) for r in range(top + 1))) + copies = tm({r: cop.count(r) for r in set(cop)}) + txt = '''import Work.GCert.Data.Price +import %(base)s.Gen.%(name)sHist + +/-! +# (key: gx-data) gcert/1 certificate `%(name)s` (h = %(h)d): the price of one invocation + +GENERATED by checks/wht26/gx-data/py/gxgen.py from %(src)s. No `sorry`. +`rA_cost`, `rB_cost`, `rF_cost`: the price of the block rank lists of phase A, phase B and the final climbs +(lists `GXD.%(name)s.rA / rB / rF`, counted by the kernel in `Gen.%(name)sHist`); +`inv_cost`: with the %(nc)d scratch copies (%(copies)s) the blocks of ONE invocation cost +`invPrice φ` = %(terms)s; `inv_moves`: they stand for `R h + 2 v (h - 1) + cst = %(N)d` unit moves. +-/ + +namespace GXD.%(name)s +open GXD OAI.PowerSaving.CB +%(thms)s +/-- price of the blocks of ONE invocation (x roles, y roles, slots, scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := %(terms)s + +/-- **Price of ONE invocation** in the shape of `GX.Lab.cost`: phase A, the scratch copies, phase B, final climbs. -/ +theorem inv_cost (φ : ℕ → ℝ) : rcost φ rA + (%(copies)s) + rcost φ rB + rcost φ rF = invPrice φ := by + rw [rA_cost, rB_cost, rF_cost] + unfold invPrice + ring + +theorem inv_moves : invPrice (fun r => (r:ℝ)) = %(R)d * %(h)d + 2 * %(v)d * (%(h)d - 1) + %(cst)d := by + unfold invPrice + norm_num + +theorem inv_count : invPrice (fun _ => (1:ℝ)) = %(count)d := by + unfold invPrice + norm_num + +end GXD.%(name)s +#print axioms GXD.%(name)s.inv_cost +#print axioms GXD.%(name)s.inv_moves +''' % dict(base=base, name=name, h=D['h'], src=src, nc=len(cop), copies=copies, terms=tm(M['hist']), N=D['N'], thms=thms, + R=D['R'], v=D['v'], cst=D['cst'], count=sum(M['hist'].values())) + open('%s/%sPrice.lean' % (out, name), 'w').write(txt) + return '%s.%sPrice' % (base, name) + + +def write_cert(D, M, name, src, out, chk, L): + """Cert: THE LABEL HALF (aux, valid : GLab.Valid raw aux, lab_cost, lab_price) -- compiles without the scalar half; + ScalOK: the scalar half `scalOK : GS.ScalOK raw` (needs Work/GCert/Scalar/Main).""" + base = out[len(ROOT):].replace('/', '.') + bs = M['scal']['batches'] + hs = '' + for i, (lo, hi) in enumerate(bs): + lo_pf = 'Nat.zero_le t' if i == 0 else 'Nat.le_of_not_lt h%d' % (i - 1) + if i + 1 < len(bs): + hs += ' if h%d : t < %d then ⟨%d, %d, %s, h%d, GS.XRun.of_check scal%d_ok⟩ else\n' % (i, hi, lo, hi - lo, lo_pf, i, i) + else: + hs += ' ⟨%d, %d, %s, Nat.lt_of_lt_of_le ht (by decide), GS.XRun.of_check scal%d_ok⟩' % (lo, hi - lo, lo_pf, i) + terms = ' + '.join('%d * φ %d' % (n, r) for r, n in M['hist'].items()) + info = dict(base=base, name=name, h=D['h'], src=src, v=D['v'], R=D['R'], nc=len(D['ret']), cst=D['cst'], N=D['N'], + nb=len(bs), terms=terms, hs=hs) + txt = '''import Work.GCert.Scalar.Main +import %(imps)s +/-! # (key: gx-data) gcert/1 certificate `%(name)s` (h = %(h)d): THE SCALAR HALF `scalOK : GS.ScalOK raw` +GENERATED by checks/wht26/gx-data/py/gxgen.py from %(src)s. No `sorry`. +Kernel checks `scal_ok` (%(nb)d source batches) and `ychk_ok`. -/ +namespace GXD.%(name)s +open GXD +theorem scalOK : GS.ScalOK raw where + hv := by decide + hs := fun t ht => +%(hs)s + hyc := fun t ht => ⟨0, %(v)d, Nat.zero_le t, Nat.lt_of_lt_of_le ht (by decide), GS.YRun.of_check ychk_ok⟩ +end GXD.%(name)s +#print axioms GXD.%(name)s.scalOK +''' % dict(info, imps='\nimport '.join(c[0] for c in chk if 'Scal' in c[0] or 'YChk' in c[0])) + open('%s/%sScalOK.lean' % (out, name), 'w').write(txt) + # ---- the label half + nA, ns, ts = L['nsegA'], L['nseg'], L['ts'] + cop = sorted(set(M['dim'][f] for _, f in D['ret'])) + assert len(cop) == 1, 'scratch copies of several ranks %s: lab_cost of gxbind.py assumes one' % cop + + def tabpf(path): + if len(path) == ts: + return 'tab%d_ok' % (int(path, 2) if path else 0) + return '(GLab.tabK_node _ _ _ %s %s)' % (tabpf(path + '0'), tabpf(path + '1')) + + def runpf(a, b): + return 'GLab.Run.of_seg seg%d_ok' % a if a + 1 == b else 'GLab.Run.append (GLab.Run.of_seg seg%d_ok) (%s)' % (a, runpf(a + 1, b)) + + def run(X, a, b): + segs = ['seg%d' % i for i in range(a, b)] + return '''theorem gates%(X)s_eq : raw.gates%(X)s = %(cat)s := by + show List.flatten %(lst)s = _ + simp only [List.flatten_cons, List.flatten_nil, List.append_nil] +/-- the replay of phase %(X)s, composed from its kernel-checked segments -/ +theorem run%(X)s : GLab.Run par st%(a)d raw.gates%(X)s st%(b)d r%(X)s := by + rw [gates%(X)s_eq] + exact %(pf)s +''' % dict(X=X, cat=nest(segs), lst=ll_(segs), a=a, b=b, pf=runpf(a, b)) + lab = 'valid.lab S Ro cf hMA hMAi hMB hMBi reg hCc hreg' + txt = '''import Work.GCert.Labels.Main +import %(base)s.%(name)sPrice +import %(imps)s +/-! # (key: gx-data) gcert/1 certificate `%(name)s` (h = %(h)d): THE LABEL HALF and its price +GENERATED by checks/wht26/gx-data/py/gxgen.py from %(src)s. No `sorry`. +`v = %(v)d` ports, `R = %(R)d` slots, %(nc)d scratch copies of rank %(c)d, copy cost `cst = %(cst)d`, `N = %(N)d` unit moves. +* `aux : GLab.Aux`, `valid : GLab.Valid raw aux`: frame table (`tab_ok` composed by `tabK_node`), the replays of phase A + and phase B (`seg_ok` composed by `Run.append`), the final climbs (`segF_ok`, `fin_ok`), the ends (`end_ok`); +* `lab_cost`, `lab_price`: for ANY scalar half `S` the label half `valid.lab S ..` costs + `rcost rA + card C * bcost %(c)d + rcost rB + rcost rF` = `invPrice φ` = %(terms)s + (`Gen.%(name)sHist`, `%(name)sPrice`) when there are %(nc)d copies. -/ +set_option maxRecDepth 100000 +namespace GXD.%(name)s +open GXD OAI.PowerSaving OAI.PowerSaving.CB +theorem raw_h : raw.h = %(h)d := rfl +theorem raw_v : raw.v = %(v)d := rfl +theorem raw_R : raw.R = %(R)d := rfl +/-- what the label checks read next to `raw` -/ +noncomputable def aux : GLab.Aux := ⟨par, st0, st%(a)d, st%(n)d, st%(f)d, fins, rA, rB, rF⟩ +theorem fin_ok : GLab.noAdds fins = true := by decide +kernel +theorem cen_ok : (raw.ret.map Prod.fst).all (fun r => Nat.beq (GLab.cdim (par.tab.get (st%(a)d.get r))) %(c)d) = true := by + decide +kernel +theorem tab_ok : GLab.tabK par.h par.tab = true := %(tabpf)s +%(runA)s%(runB)s/-- **the kernel-checked label facts** of the certificate -/ +theorem valid : GLab.Valid raw aux where + hn := rfl + tab := tab_ok + runA := runA + runB := runB + runF := GLab.Run.of_seg segF_ok + fin := fin_ok + ends := end_ok +theorem cen_dim (r : Nat) (hr : r ∈ raw.ret.map Prod.fst) : GLab.cdim (par.tab.get (st%(a)d.get r)) = %(c)d := + Nat.eq_of_beq_eq_true (List.all_eq_true.mp cen_ok r hr) +/-- price of the label half over ANY scalar half -/ +theorem lab_cost {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (φ : ℕ → ℝ) : + (%(lab)s).cost φ + = rcost φ rA + (Fintype.card C : ℝ) * bcost φ %(c)d + rcost φ rB + rcost φ rF := by + obtain ⟨h1, h2, h3, h4⟩ := valid.lab_ranks S Ro cf hMA hMAi hMB hMBi reg hCc hreg + have h5 : ∀ k, bcost φ (((%(lab)s).cen k).dim) = bcost φ %(c)d := + fun k => by rw [h4 k]; exact congrArg (bcost φ) (cen_dim _ (hreg k)) + rw [GX.Lab.cost, h1, h2, h3, Finset.sum_congr rfl (fun k _ => h5 k), Finset.sum_const, Finset.card_univ, nsmul_eq_mul] + rfl +/-- **the label half costs one invocation price** (`invPrice`, by rank, from the kernel counts) -/ +theorem lab_price {C : Type} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin raw.v) (Fin raw.R) C) + {emb : CR.L3 (Fin raw.v) (Fin raw.R) → Nat} {un : Nat → CR.L3 (Fin raw.v) (Fin raw.R)} + (Ro : GLab.Roles raw.v raw.R emb un) (cf : Co → SSC.Coef) (hMA) (hMAi) (hMB) (hMBi) + (reg : C → Nat) (hCc) (hreg) (hC : Fintype.card C = %(nc)d) (φ : ℕ → ℝ) : + (%(lab)s).cost φ = invPrice φ := by + rw [lab_cost S Ro cf hMA hMAi hMB hMBi reg hCc hreg φ, hC, ← inv_cost φ] + norm_num [bcost] +end GXD.%(name)s +#print axioms GXD.%(name)s.valid +#print axioms GXD.%(name)s.lab_price +''' % dict(info, imps='\nimport '.join(c[0] for c in chk if 'Scal' not in c[0] and 'YChk' not in c[0]), c=cop[0], a=nA, n=ns, + f=ns + 1, tabpf=tabpf(''), runA=run('A', 0, nA), runB=run('B', nA, ns), lab=lab) + open('%s/%sCert.lean' % (out, name), 'w').write(txt) + return ['%s.%sCert' % (base, name), '%s.%sScalOK' % (base, name)] + + +def ll_(xs): + return '[' + ', '.join(xs) + ']' + + +def final_module(name, cname, d, dx, g, out): + """.lean: the final theorems OVER ANY SCALAR HALF (compiles as soon as Cert does): label half, price, + unit list, rate fact and gx-chain's `GX.wht_of_halves` are all closed; what is left is `S : GX.Scal` with its + gate matrices = the ordered products of the adds of `raw` (gx-scalar).""" + h, v, R, W, m, nc = g['h'], g['v'], g['R'], d['W'], d['m'], g['nc'] + X = 'GXD.%s' % cname + args = 'S Ro cf hMA hMAi hMB hMBi reg hCc hreg' + + def thm(nm, rate, A, B, s, ux): + return f''' +/-- **Walsh-Hadamard transform, whole-block recursion on the bridged word B_2 with the gcert/1 circuit `{cname}`**, +over any scalar half of `{X}.raw`: the statement `WHTGoal` of `WHTCheck/Challenge.lean` with `1 - 2/10^11` +replaced by `1 - {A}/10^{B}`. -/ +theorem {nm} (Ro : GLab.Roles {X}.raw.v {X}.raw.R emb un) + (hMA : S.MA = SSC.matP un (GLab.mic cf ({X}.raw.gatesA.flatMap GXD.Gate.adds))) + (hMAi : S.MAi = SSC.matPinv un (GLab.mic cf ({X}.raw.gatesA.flatMap GXD.Gate.adds))) + (hMB : S.MB = SSC.matP un (GLab.mic cf ({X}.raw.gatesB.flatMap GXD.Gate.adds))) + (hMBi : S.MBi = SSC.matPinv un (GLab.mic cf ({X}.raw.gatesB.flatMap GXD.Gate.adds))) + (reg : C → Nat) (hCc : ∀ k (q : Fin {X}.raw.R), S.Cc k q ≠ 0 → reg k = 2 * {X}.raw.v + q.val) + (hreg : ∀ k, reg k ∈ {X}.raw.ret.map Prod.fst) (hC : Fintype.card C = {nc}) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - {A}/(10:ℝ)^{B}) W := + GX.wht_of_halves S ({X}.valid.lab {args}) + (by rw [Fintype.card_fin]; decide) {m} {W} (by rw [Fintype.card_fin]; rfl) + (by rw [Fintype.card_fin, Fintype.card_fin]; rfl) (by norm_num) BlockAccounting.blocks{rate} + (fun φ => by + rw [{X}.lab_price {args} hC φ, Fintype.card_fin, Fintype.card_fin] + exact BridgeRate.{name}.unit_cost{ux} φ) + {s} (1 - {A}/(10:ℝ)^{B}) (by norm_num) (by norm_num) BlockAccounting.fold_{rate} + +/-- the same from the FIVE scalar identities of gx-scalar's matrices of `{X}.raw` (`Work/GCert/Data/Glue.lean`) -/ +theorem {nm.replace('_of_scal', '_of_ids')} (hv : 0 < {X}.raw.v) + (hAi : GS.MAi {X}.raw hv * GS.MA {X}.raw hv = 1) (hBi : GS.MBi {X}.raw hv * GS.MB {X}.raw hv = 1) + (hx : ∀ (t : Fin {X}.raw.v) (j : GS.Rl {X}.raw), (GS.MB {X}.raw hv * CR.scatM (GS.Jrm {X}.raw * GS.Ccm {X}.raw) + * GS.MA {X}.raw hv) (CR.lX t) j = if CR.lX t = j then 1 else 0) + (hy : ∀ (i : GS.Rl {X}.raw) (t : Fin {X}.raw.v), (GS.MB {X}.raw hv * CR.scatM (GS.Jrm {X}.raw * GS.Ccm {X}.raw) + * GS.MA {X}.raw hv) i (CR.lY t) = if i = CR.lY t then 1 else 0) + (hid : ∀ S t : Fin {X}.raw.v, (GS.MB {X}.raw hv * CR.scatM (GS.Jrm {X}.raw * GS.Ccm {X}.raw) + * GS.MA {X}.raw hv) (CR.lY S) (CR.lX t) = if S = t then 1 else 0) : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - {A}/(10:ℝ)^{B}) W := + {nm} (GXD.scalOf {X}.raw hv hAi hBi hx hy hid) GS.toCoef (GXD.roles {X}.raw hv) + (GXD.scalOf_MA _ hv hAi hBi hx hy hid) (GXD.scalOf_MAi _ hv hAi hBi hx hy hid) + (GXD.scalOf_MB _ hv hAi hBi hx hy hid) (GXD.scalOf_MBi _ hv hAi hBi hx hy hid) + (GXD.reg {X}.raw) (GXD.reg_slot {X}.raw hv hAi hBi hx hy hid) (GXD.reg_mem {X}.raw) + (by rw [Fintype.card_fin]; decide) +''' + txt = f'''import Work.GCert.Chain.End +import Work.GCert.Data.Glue +import Work.GCert.Data.{cname}Cert +import Work.GCert.Data.Inst{name} + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `{cname}` (h = {h}, m = {m}): final theorems over a scalar half +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`GX.wht_of_halves` (gx-chain) on the label half `{X}.valid` (kernel checks of `Work/GCert/Data/Gen/{cname}*`), its +price `{X}.lab_price`, the unit list `BlockAccounting.blocks{name}` (`W = {W}` live roles) and the rate facts +`fold_{name}` (`1 - {d['A']}/10^{d['B']}`), `fold_{name}x` (`1 - {dx['A']}/10^{dx['B']}`). +The ONLY hypothesis left is the scalar half: `S : GX.Scal (Fin {v}) (Fin {R}) C` whose gate matrices are the ordered +products of the adds of `raw` (`hMA .. hMBi`), with `{nc}` copies read from the retained registers (`reg`, `hCc`, `hreg`, `hC`); +`wht_{name}_of_ids`, `wht_{name}x_of_ids`: the same from the five identities `hAi hBi hx hy hid` of gx-scalar's matrices +`GS.MA GS.MAi GS.MB GS.MBi GS.Jrm GS.Ccm` of `raw` (the fields of the planned `GS.ScalOK`). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT + +variable {{C : Type}} [Fintype C] [DecidableEq C] (S : GX.Scal (Fin {X}.raw.v) (Fin {X}.raw.R) C) + {{emb : CR.L3 (Fin {X}.raw.v) (Fin {X}.raw.R) → Nat}} {{un : Nat → CR.L3 (Fin {X}.raw.v) (Fin {X}.raw.R)}} + (cf : GXD.Co → SSC.Coef) +''' + thm('wht_' + name + '_of_scal', name, d['A'], d['B'], d['s'], '') + thm('wht_' + name + 'x_of_scal', name + 'x', dx['A'], dx['B'], dx['s'], '_x') + f''' +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_{name}_of_scal +#print axioms OAI.PowerSaving.WHT.wht_{name}x_of_scal +#print axioms OAI.PowerSaving.WHT.wht_{name}_of_ids +#print axioms OAI.PowerSaving.WHT.wht_{name}x_of_ids +''' + open(out + '%s.lean' % name, 'w').write(txt) + + +def main_module(name, cname, d, dx, out): + """Main.lean: the CLOSED theorems (what the comparator solution cites). WRITTEN against gx-scalar's planned + `GS.ScalOK` (fields / theorems hv hAi hBi hx hy hid, SCALAR v2); compiles when Work/GCert/Scalar/Main.lean exists.""" + K = 'GXD.%s.scalOK' % cname + + def thm(sfx, A, B): + return f''' +/-- **Walsh-Hadamard transform in `O(n (log n)^(1 - {A}/10^{B}))`-type time bounds: whole-block recursion on the bridged +word B_2 with the kernel-checked gcert/1 circuit `{cname}`.** -/ +theorem wht_main_{name}{sfx} : + ∃ solve W, WHTProgram solve W ∧ BlockWHT.WHTTimeBoundsAt (1 - {A}/(10:ℝ)^{B}) W := + wht_{name}{sfx}_of_ids {K}.hv {K}.hAi {K}.hBi {K}.hx {K}.hy {K}.hid +''' + txt = f'''import Work.GCert.Scalar.Main +import Work.GCert.Data.{cname}ScalOK +import Work.GCert.Data.{name} + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `{cname}`: THE CLOSED THEOREMS +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. +`wht_{name}_of_ids` (label half, price, unit list, rate fact, gx-chain's end theorem) applied to the scalar half +`{K} : GS.ScalOK GXD.{cname}.raw` (kernel checks `scal_ok`, `ychk_ok`; soundness: gx-scalar). +-/ + +namespace OAI +namespace PowerSaving +namespace WHT +open BlockWHT +''' + thm('', d['A'], d['B']) + thm('x', dx['A'], dx['B']) + f''' +end WHT +end PowerSaving +end OAI +#print axioms OAI.PowerSaving.WHT.wht_main_{name} +#print axioms OAI.PowerSaving.WHT.wht_main_{name}x +''' + open(out + '%sMain.lean' % name, 'w').write(txt) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxcore.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxcore.py new file mode 100644 index 0000000000..3e3f0a3076 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxcore.py @@ -0,0 +1,375 @@ +"""gxcore.py: gcert/1 JSON -> normal data D, PYTHON MIRROR of the two Lean checks +(label side: E0 frames, E1 pairs, E1/E2/E6 replay in segments; scalar side: E3 kinds, E4 bracket, E5 replay +in source batches, E7), derived data (distinct climbs, cut states, block histogram) and kernel sizes. +Own code; the reference is gx.py (check1), not imported. Python 3, standard library only.""" +import json, gzip +from collections import Counter +from math import gcd + + +class Reject(Exception): + pass + + +def need(c, msg): + if not c: + raise Reject(msg) + + +def load(path): + c = json.load(gzip.open(path, "rt") if path.endswith(".gz") else open(path)) + need(c.get("format") == "gcert/1", "E0: format is not gcert/1") + return c + + +def co(num, den): + need(den > 0, "E0: denominator") + return (num < 0, abs(num), den) + + +def normal(c): + """the Lean-facing data: gates as tuples, coefficients (neg, num, den), ret by total""" + def gate(g): + if g[0] == "out": + return ("out", g[1], g[2], [(t, co(a, b)) for t, a, b in g[3]], list(g[4])) + need(g[0] == "in", "E0: unknown gate kind %r" % (g[0],)) + return ("in", g[1], g[2], [(s, co(a, b)) for s, a, b in g[3]]) + ret = sorted(c["ret"]) + need([k for k, _, _ in ret] == list(range(len(ret))), "E2: retained totals numbered 0..") + sc = c["scat"] + scat = ("table", [[(k, co(a, b)) for k, a, b in row] for row in sc["table"]]) if "table" in sc else \ + ("star", co(*sc["inside"]), co(*sc["outside"])) + return dict(h=c["h"], v=c["v"], R=c["R"], N=c["N"], cst=c["cst"], ports=list(c["ports"]), + frames=[list(f) for f in c["frames"]], start=list(c["start"]), final=list(c["final"]), + ext=[tuple(e) for e in c.get("ext", [])], ret=[(s, f) for _, s, f in ret], scat=scat, + A=[gate(g) for g in c["A"]], B=[gate(g) for g in c["B"]], + blocks={k: {int(r): n for r, n in c["blocks"][k].items()} for k in "xysc"}) + + +def regs(g): + return [g[2]] + [t for t, _ in g[3]] + (g[4] if g[0] == "out" else []) + + +def adds(g): + """single adds (tgt, src, coef) in order""" + return [(t, g[2], k) for t, k in g[3]] if g[0] == "out" else [(g[2], s, k) for s, k in g[3]] + + +def reduce(u, basis): + for b in basis: + if u >> (b.bit_length() - 1) & 1: + u ^= b + return u + + +def echelon_ok(f): + piv = [b.bit_length() - 1 for b in f] + if any(b == 0 for b in f) or any(piv[i] <= piv[i + 1] for i in range(len(piv) - 1)): + return False + return all(not (b >> p & 1) for i, b in enumerate(f) for j, p in enumerate(piv) if i != j) + + +def par(x): + return bin(x).count("1") & 1 + + +def cls(D, r): + return "x" if r < D["v"] else "y" if r < 2 * D["v"] else "s" + + +# ---- label side ------------------------------------------------------------------------------------------ +def chk_frames(D): + """E0: ports; frame table reduced echelon, no repeats, zero first, full second""" + h, v, fr = D["h"], D["v"], D["frames"] + p = D["ports"] + need(len(p) == v == len(set(p)) and all(par(q) and 0 < q < 1 << h for q in p), "E0: ports") + need(len(fr) >= 2 and fr[0] == [] and fr[1] == [1 << i for i in range(h - 1, -1, -1)], "E0: frames 0 and 1") + need(all(echelon_ok(f) and all(b < 1 << h for b in f) for f in fr), "E0: frame table not reduced echelon") + need(len(set(map(tuple, fr))) == len(fr), "E0: frame table has repeats") + return [len(f) for f in fr] + + +def derive(D): + """distinct climbs in order of first use (NOT a check: plain replay of the frame ids)""" + cur, seen, pairs = list(D["start"]), set(), [] + + def go(r, f): + o = cur[r] + if o != f: + if (o, f) not in seen: + seen.add((o, f)) + pairs.append((o, f)) + cur[r] = f + for g in D["A"] + D["B"]: + for r in regs(g): + go(r, g[1]) + for r, f in enumerate(D["final"]): + go(r, f) + return pairs + + +def chk_pairs(D, dim, pairs): + """E1, level 2: every listed pair is a nested pair of the table; returns the mask-operation count""" + fr, n, work = D["frames"], len(D["frames"]), 0 + for a, b in pairs: + need(a < n and b < n and dim[a] < dim[b], "E1: pair (%d, %d) does not climb" % (a, b)) + need(all(reduce(u, fr[b]) == 0 for u in fr[a]), "E1: pair (%d, %d) is not nested" % (a, b)) + work += dim[a] * dim[b] + return work + + +def cut_points(D, gmax, wmax=210000): + """replay segments: each phase (A, B) is cut into k pieces of equal gate count, k = the least number with at + most `gmax` gates AND at most `wmax` work per piece on average (work = sum over gates of the dimension of the + gate's frame; measured at h = 22: about 1 ms of kernel time per unit, NOTES.md). + Cut points = gate counts in A ++ B (always 0, |A| and the end).""" + nA, nB = len(D["A"]), len(D["B"]) + cuts = [0] + for off, gs in ((0, D["A"]), (nA, D["B"])): + n = len(gs) + k = max(1, -(-n // gmax), -(-sum(len(D["frames"][g[1]]) for g in gs) // wmax)) + cuts += [off + (n * i) // k for i in range(1, k + 1)] + return sorted(set(cuts)) + + +def label_data(D, dim, cuts): + """for gx-labels (gcert-interface.md LABELS v1): ordered block ranks per replay segment, the final climbs as + gates without adds (same final frame, at most 32 registers, only registers that still climb), their ranks, + the largest number of registers named by one gate. Plain replay (the mirror has accepted the file).""" + cur, G = list(D["start"]), D["A"] + D["B"] + rs, most = [], 0 + for a, b in zip(cuts, cuts[1:]): + r = [] + for g in G[a:b]: + most = max(most, len(regs(g))) + for x in regs(g): + if cur[x] != g[1]: + r.append(dim[g[1]] - dim[cur[x]]) + cur[x] = g[1] + rs.append(r) + by = {} + for x, f in enumerate(D["final"]): + if cur[x] != f: + by.setdefault(f, []).append(x) + fins, rF = [], [] + for f in sorted(by): + for i in range(0, len(by[f]), 32): + xs = by[f][i:i + 32] + fins.append(("out", f, xs[0], [], xs[1:])) + rF += [dim[f] - dim[cur[x]] for x in xs] + return dict(rs=rs, fins=fins, rF=rF, most=max(most, 32 if fins else 0)) + + +def chk_replay(D, dim, pairs, cuts): + """E1 (labels), E2 (scatter cut), E6 (price), in the segments given by `cuts`. + Returns (states at the cuts, histogram by class, visits per segment).""" + h, v, R, fr = D["h"], D["v"], D["R"], D["frames"] + n = 2 * v + R + start, final, ext = D["start"], D["final"], dict(D["ext"]) + need(len(start) == len(final) == n, "E0: start / final") + for t in range(v): + need(fr[start[t]] == [D["ports"][t]] and final[t] == 1, "E1: x start / final") + f = fr[final[v + t]] + need(start[v + t] == 0 and len(f) == h - 1 and all(par(u & D["ports"][t]) == 0 for u in f), "E1: y start / final") + for r in range(2 * v, n): + need(start[r] == ext.get(r, 0) and final[r] == 1, "E1: slot start / final") + ok = set(pairs) + need(len(ok) == len(pairs), "E1: pair list has repeats") + cur = list(start) + H = {k: Counter() for k in "xysc"} + + def climb(r, f, where): + o = cur[r] + if o != f: + need((o, f) in ok, "E1: climb (%d, %d) is not a tested pair (%s, register %d)" % (o, f, where, r)) + H[cls(D, r)][dim[f] - dim[o]] += 1 + seg[dim[f] - dim[o]] += 1 + cur[r] = f + seg, segs = Counter(), [] + G, nA = D["A"] + D["B"], len(D["A"]) + states, visits = [], [] + need(cuts[0] == 0 and cuts[-1] == len(G) and cuts == sorted(cuts), "cut points") + for a, b in zip(cuts, cuts[1:]): + states.append(list(cur)) + vs = 0 + for i in range(a, b): + if i == nA: + scatter_cut(D, cur, dim, H, seg) + g = G[i] + rs = regs(g) + need(all(0 <= r < n for r in rs) and len(set(rs)) == len(rs), "E3: registers of gate %d" % i) + need(i >= nA or all(r < v or r >= 2 * v for r in rs), "E2: y role named in phase A (gate %d)" % i) + vs += len(rs) + for r in rs: + climb(r, g[1], "gate %d" % i) + visits.append(vs) + if b < len(G): + segs.append(seg) + seg = Counter() + if nA == len(G): + scatter_cut(D, cur, dim, H, seg) + states.append(list(cur)) + for r in range(n): + climb(r, final[r], "final") + segs.append(seg) + Hb = {k: dict(sorted(w.items())) for k, w in H.items()} + need(Hb == D["blocks"], "E6: block histogram differs from `blocks`") + N = sum(r * c for w in H.values() for r, c in w.items()) + need(N == D["N"] and N + sum(dim[f] for f in ext.values()) == R * h + 2 * v * (h - 1) + D["cst"], "E6: N") + need(sum(r * c for r, c in H["c"].items()) == D["cst"], "E6: cst") + return states, Hb, visits, [[w[r] for r in range(h + 1)] for w in segs] + + +def scatter_cut(D, cur, dim, H, seg): + v = D["v"] + if D["scat"][0] == "table": + need(len(D["scat"][1]) == v and all(k < len(D["ret"]) for row in D["scat"][1] for k, _ in row), "E2: scatter table") + else: + need(len(D["ret"]) == D["h"], "E2: one retained total per coordinate (star rule)") + for s, f in D["ret"]: + need(s >= 2 * v and cur[s] == f, "E2: retained slot %d is not at its frame" % s) + H["c"][dim[f]] += 1 + seg[dim[f]] += 1 + need(all(cur[v + t] == 0 for t in range(v)), "E2: a y role left frame 0 before the scatter") + + +# ---- scalar side ----------------------------------------------------------------------------------------- +SC = 6 # all scalar entries are kept as integers in units of 1/6 +KINDS = {("x", "s"), ("s", "s"), ("s", "y"), ("x", "y"), ("x", "x"), ("y", "y")} + + +def chk_shape(D): + """E3 kinds, E4 bracket""" + ysum, piv, ytg = Counter(), set(), set() + for ph in "AB": + for i, g in enumerate(D[ph]): + for t, s, (ng, a, b) in adds(g): + kd = (cls(D, s), cls(D, t)) + need(kd in KINDS and t != s, "E3: gate kind %s -> %s (gate %s%d)" % (kd + (ph, i))) + need(ph == "B" or kd in {("x", "s"), ("s", "s")}, "E3: bank gate before the scatter (gate A%d)" % i) + if kd == ("y", "y"): + need(SC % b == 0, "E4: denominator beyond sixths") + ysum[s, t] += (-a if ng else a) * (SC // b) + piv.add(s) + ytg.add(t) + need(not (piv & ytg), "E4: a pivot is the target of a gate reading y") + need(all(x == 0 for x in ysum.values()), "E4: y-reads of a (pivot, target) pair do not cancel") + return len(ysum) + + +def scat_row(D, t): + sc = D["scat"] + if sc[0] == "table": + return sc[1][t] + return [(k, sc[1] if D["ports"][t] >> k & 1 else sc[2]) for k in range(D["h"])] + + + +def replay(D, init, count=None): + """exact replay through A, scatter, B of sparse vectors with entries in sixths; `init` = register -> {key: 6}""" + v = D["v"] + reg = [dict(init.get(r, ())) for r in range(2 * v + D["R"])] + + def axpy(t, src, k): + ng, a, b = k + d = reg[t] + for key, u in src.items(): + w = u * a + need(w % b == 0, "E5: an entry needs a denominator beyond sixths (register %d)" % t) + w = w // b + w = d.get(key, 0) + (-w if ng else w) + if count is not None: + count[key] += 1 + if w: + d[key] = w + else: + d.pop(key, None) + + def run(gates): + for g in gates: + if g[0] == "out": + src = dict(reg[g[2]]) + for t, k in g[3]: + axpy(t, src, k) + else: + for s, k in g[3]: + axpy(g[2], reg[s], k) + run(D["A"]) + afterA = sum(len(d) for d in reg) + tot = [dict(reg[s]) for s, _ in D["ret"]] + for t in range(v): + for k, cf in scat_row(D, t): + if tot[k]: + axpy(v + t, tot[k], cf) + run(D["B"]) + return reg, afterA + + +def chk_scalar(D, batches=1): + """E5 (+ E7 when `ext` is non-empty). Returns stats: denominators and largest numerators per class in the + units of the spec (x halves, y sixths, slots integers), updates per source batch, entries after A.""" + v = D["v"] + count = Counter() + reg, afterA = replay(D, {t: {t: SC} for t in range(v)}, count) + need(all(reg[t] == {t: SC} for t in range(v)), "E5: an x role is not restored (X3)") + need(all(reg[v + t] == {t: SC} for t in range(v)), "E5: a target does not receive exactly its source (hid)") + if D["ext"]: + rg, _ = replay(D, {r: {r: SC} for r, _ in D["ext"]}) + need(all(not rg[v + t] for t in range(v)), "E7: the dirt of an exterior-gauged slot reaches a y role") + step = -(-v // batches) + per = [sum(count[k] for k in range(lo, min(lo + step, v))) for lo in range(0, v, step)] + return dict(updates=sum(count.values()), per_batch=per, afterA=afterA, + batches=[(lo, min(lo + step, v)) for lo in range(0, v, step)]) + + +def digits(D): + """largest |entry| met and denominators per class, by a second replay that watches every write (slow path + kept separate from the check): returns {class: (lcm of denominators, largest |numerator| in units 1/den)}""" + v = D["v"] + den = {"x": 1, "y": 1, "s": 1} + mx = {"x": 0, "y": 0, "s": 0} + reg = [({r: SC} if r < v else {}) for r in range(2 * v + D["R"])] + + def axpy(t, src, k): + ng, a, b = k + d, kk = reg[t], cls(D, t) + for key, u in src.items(): + w = d.get(key, 0) + (-(u * a // b) if ng else u * a // b) + if w: + d[key] = w + q = SC // gcd(w, SC) + if den[kk] % q: + den[kk] = den[kk] * q // gcd(den[kk], q) + if abs(w) > mx[kk]: + mx[kk] = abs(w) + else: + d.pop(key, None) + for g in D["A"]: + for t, s, k in adds(g): + axpy(t, reg[s], k) + tot = [dict(reg[s]) for s, _ in D["ret"]] + for t in range(v): + for k, cf in scat_row(D, t): + axpy(v + t, tot[k], cf) + for g in D["B"]: + for t, s, k in adds(g): + axpy(t, reg[s], k) + return {k: (den[k], mx[k] * den[k] // SC if (mx[k] * den[k]) % SC == 0 else "%d/6" % mx[k]) for k in "xys"} + + +def mirror(D, gmax=12000, batches=1, pairs=None, cuts=None): + """both checks; returns everything the generator and the dry run need""" + dim = chk_frames(D) + pairs = derive(D) if pairs is None else pairs + work = chk_pairs(D, dim, pairs) + cuts = cut_points(D, gmax) if cuts is None else cuts + states, H, visits, segH = chk_replay(D, dim, pairs, cuts) + ysh = chk_shape(D) + S = chk_scalar(D, batches) + hist = Counter() + for k in "xysc": + for r, n in H[k].items(): + hist[r] += n + return dict(dim=dim, pairs=pairs, pair_work=work, cuts=cuts, states=states, H=H, visits=visits, ysh=ysh, + scal=S, hist=dict(sorted(hist.items())), segH=segH, + lab=label_data(D, dim, cuts)) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxgen.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxgen.py new file mode 100644 index 0000000000..12d847f09d --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxgen.py @@ -0,0 +1,256 @@ +"""gxgen.py: gcert/1 JSON -> Lean data modules for `GXD.Raw` (Work/GCert/Data/Raw.lean) +in SEGMENTS, the kernel-check modules of gx-scalar and gx-labels (one module per kernel evaluation), the +kernel-counted block histogram and the interface (Cert) module; after the Python MIRROR of both checks (gxcore). + +usage: gxgen.py [mirror-only] [gseg=] [batches=] + [tsplit=] [frames=1] [seg=] [out=] + writes /Gen//S.lean data segments (namespace GXD.) + /Gen/.lean `raw : GXD.Raw` + /Gen/.lean one per kernel evaluation (table BIND in gxbind.py) + /Gen/Hist.lean, /Cert.lean + /logs/gen-.json everything the rate / instance generator (gxrate.py) needs +""" +import sys, os, json +import gxpaths +import gxcore as gc +import gxunit as gu +import gxbind as gb + +ROOT = gxpaths.OUT +MY = ROOT +SEG = 1000000 # bytes of Lean text per data module: measured 0.55 GB + 1.15 GB per MB, 26 s per MB (NOTES.md) +PER = 250 # items per list literal + + +# ---- derived data: an orthonormal basis through every port (questions.md Q1) ------------------------------- +def dot(a, b): + return bin(a & b).count('1') & 1 + + +def obase(p, h): + """h masks, first = p, pairwise dots = delta. W = current complement (basis), c = its characteristic vector.""" + full = (1 << h) - 1 + gc.need(gc.par(p) and p != full, 'obase: port %d is even or all-ones' % p) + W, c, out, x = [1 << i for i in range(h)], full, [], p + while True: + out.append(x) + c ^= x + nw = [] + for y in W: # project W onto x^perp, keep a basis + y ^= x if dot(y, x) else 0 + for b in nw: + y = min(y, y ^ b) + if y: + nw.append(y) + W = nw + if not W: + break + cand = [y for y in W if gc.par(y)] + [a ^ b for i, a in enumerate(W) for b in W[:i] if gc.par(a ^ b)] + cand = [y for y in cand if y != c or len(W) == 1] + gc.need(cand, 'obase: no odd vector left (port %d)' % p) + x = cand[0] + gc.need(len(out) == h and all(dot(a, b) == (i == j) for i, a in enumerate(out) for j, b in enumerate(out)), + 'obase: not orthonormal (port %d)' % p) + return out + + +# ---- Lean text --------------------------------------------------------------------------------------------- +def ll(xs): + return '[' + ', '.join(xs) + ']' + + +class Emit: + """collects definitions (text, bytes) and packs them into segment modules""" + + def __init__(s, name, cos): + s.name, s.defs = name, [] + s.co = {k: 'k%d' % i for i, k in enumerate(cos)} + + def add(s, nm, typ, body): + s.defs.append('noncomputable def %s : %s := %s' % (nm, typ, body)) + + def lst(s, nm, typ, items, fmt, per=PER, nested=False): + """`nm : List typ` as a concatenation of literals of `per` items; nested=True: `nm : List (List typ)`""" + parts = [] + for i in range(0, max(len(items), 1), per): + pn = '%s_%d' % (nm, i // per) + parts.append(pn) + s.add(pn, 'List (%s)' % typ, ll(map(fmt, items[i:i + per]))) + if nested: + s.add(nm, 'List (List (%s))' % typ, ll(parts)) + else: + s.add(nm, 'List (%s)' % typ, ' ++ ('.join(parts) + ')' * (len(parts) - 1)) # right-nested appends + + def trie(s, nm, vals, d, low=8): + """`nm : SSC.Trie` of depth d (key bit 0 first: left = even keys), leaf i = vals[i], 0 beyond; literals of + 2^low leaves named nm_. Returns the list of subtries at every depth (for the split table check).""" + vals = list(vals) + [0] * ((1 << d) - len(vals)) + cnt = [0] + + def lit(vs): + return '.leaf %d' % vs[0] if len(vs) == 1 else '.node (%s) (%s)' % (lit(vs[0::2]), lit(vs[1::2])) + + def go(vs, depth, path): + if depth <= low: + pn = '%s_%d' % (nm, cnt[0]) + cnt[0] += 1 + s.add(pn, 'SSC.Trie', lit(vs)) + return pn + l, r = go(vs[0::2], depth - 1, path + '0'), go(vs[1::2], depth - 1, path + '1') + pn = nm if not path else '%s_n%s' % (nm, path) + s.add(pn, 'SSC.Trie', '.node %s %s' % (l, r)) + return pn + root = go(vals, d, '') + if root != nm: + s.add(nm, 'SSC.Trie', root) + + def cf(s, k): + return s.co[k] + + def gate(s, g): + pr = lambda x: '(%d, %s)' % (x[0], s.co[x[1]]) + if g[0] == 'out': + return '.out %d %d %s %s' % (g[1], g[2], ll(map(pr, g[3])), ll(map(str, g[4]))) + return '.inn %d %d %s' % (g[1], g[2], ll(map(pr, g[3]))) + + def modules(s, seg): + mods, cur, size = [], [], 0 + for d in s.defs: + if cur and size + len(d) > seg: + mods.append(cur) + cur, size = [], 0 + cur.append(d) + size += len(d) + return mods + [cur] + + +def coefs(D): + cs = [] + def see(k): + if k not in cs: + cs.append(k) + for g in D['A'] + D['B']: + for _, k in g[3]: + see(k) + if D['scat'][0] == 'star': + see(D['scat'][1]), see(D['scat'][2]) + else: + for row in D['scat'][1]: + for _, k in row: + see(k) + return cs + + +def data(D, M, name, opt): + E = Emit(name, coefs(D)) + for k, nm in E.co.items(): + E.add(nm, 'Co', '⟨%s, %d, %d⟩' % ('true' if k[0] else 'false', k[1], k[2])) + num, pair = str, lambda x: '(%d, %d)' % x + E.lst('ports', 'Nat', D['ports'], num) + E.lst('start', 'Nat', D['start'], num) + E.lst('final', 'Nat', D['final'], num) + E.lst('ret', 'Nat × Nat', D['ret'], pair) + E.lst('ext', 'Nat × Nat', D['ext'], pair) + if D['scat'][0] == 'star': + E.add('scat', 'Scat', '.star %s %s' % (E.cf(D['scat'][1]), E.cf(D['scat'][2]))) + else: + E.lst('scatRows', 'List (Nat × Co)', D['scat'][1], lambda r: ll('(%d, %s)' % (k, E.cf(c)) for k, c in r), per=60) + E.add('scat', 'Scat', '.table scatRows') + E.lst('obase', 'List Nat', [obase(p, D['h']) for p in D['ports']], lambda b: ll(map(str, b)), per=60) + if opt.get('frames') == '1': + E.lst('frames', 'List Nat', D['frames'], lambda f: ll(map(str, f)), per=150, nested=True) + else: + E.add('frames', 'List (List (List Nat))', '[]') + # replay segments = the chunks of raw.A / raw.B (gx-labels: a cut state between two chunks) + G, nA, cuts, L = D['A'] + D['B'], len(D['A']), M['cuts'], M['lab'] + ch = {'A': [], 'B': []} + for i, (a, b) in enumerate(zip(cuts, cuts[1:])): + E.lst('seg%d' % i, 'Gate', G[a:b], E.gate, per=150) + E.lst('rs%d' % i, 'Nat', L['rs'][i], num) + ch['A' if b <= nA else 'B'].append('seg%d' % i) + E.add('gA', 'List (List Gate)', ll(ch['A'])) + E.add('gB', 'List (List Gate)', ll(ch['B'])) + E.lst('fins', 'Gate', L['fins'], E.gate, per=150) + E.lst('rF', 'Nat', L['rF'], num) + E.add('pairs', 'List (List (Nat × Nat))', '[]') + E.add('cuts', 'List (Nat × List Nat)', '[]') + # gx-labels: frame table as codes, register states as tries + h, n = D['h'], 2 * D['v'] + D['R'] + dF, d = bits(len(D['frames'])), bits(n) + ts = min(int(opt.get('tsplit', gu.TSPLIT)), max(0, dF - 2)) + E.trie('tab', [gb.code(h, f) for f in D['frames']], dF, low=min(8, dF - ts - 1)) + for i, st in enumerate(M['states'] + [D['final']]): + E.trie('st%d' % i, st, d) + return E, dict(dF=dF, d=d, nseg=len(cuts) - 1, nsegA=len(ch['A']), K=h * L['most'], ts=ts) + + +def bits(n): + d = 0 + while (1 << d) < n: + d += 1 + return d + + +HEAD = '''/-! gcert/1 certificate `%(name)s` (h = %(h)d, v = %(v)d ports, R = %(R)d slots, N = %(N)d unit moves): %(what)s. +Source: %(src)s. Generated by checks/wht26/gx-data/py/gxgen.py (do not edit). -/ +set_option maxRecDepth 100000 +''' + + +def write_data(D, M, name, src, out, opt): + E, npc = data(D, M, name, opt) + E.npc = npc + mods = E.modules(int(opt.get('seg', SEG))) + d = '%s/Gen/%s' % (out, name) + os.makedirs(d, exist_ok=True) + base = out[len(ROOT):].replace('/', '.') + info = dict(name=name, h=D['h'], v=D['v'], R=D['R'], N=D['N'], src=src) + sizes = [] + for i, m in enumerate(mods): + imp = 'import Work.GCert.Data.Raw\nimport Work.SharedSumChecker.Check\n' + ('import %s.Gen.%s.S%d\n' % (base, name, i - 1) if i else '') + txt = imp + HEAD % dict(info, what='data segment %d of %d' % (i, len(mods))) + \ + 'namespace GXD.%s\nopen GXD\n' % name + '\n'.join(m) + '\nend GXD.%s\n' % name + open('%s/S%d.lean' % (d, i), 'w').write(txt) + sizes.append(len(txt.encode())) + txt = ('import %s.Gen.%s.S%d\n' % (base, name, len(mods) - 1) + HEAD % dict(info, what='the record `raw : GXD.Raw`') + + 'namespace GXD.%s\nopen GXD\n/-- the certificate -/\nnoncomputable def raw : Raw :=\n' % name + + ' { h := %d, v := %d, R := %d, N := %d, cst := %d, ports := ports, frames := frames, start := start,\n' + ' final := final, ret := ret, scat := scat, A := gA, B := gB, pairs := pairs, cuts := cuts, ext := ext,\n' + ' obase := obase }\n' % (D['h'], D['v'], D['R'], D['N'], D['cst']) + 'end GXD.%s\n' % name) + open('%s/Gen/%s.lean' % (out, name), 'w').write(txt) + return ['%s.Gen.%s.S%d' % (base, name, i) for i in range(len(mods))] + ['%s.Gen.%s' % (base, name)], sizes, npc + + +def main(): + path, name = sys.argv[1], sys.argv[2] + opt = dict(a.split('=') for a in sys.argv[3:] if '=' in a) + out = opt.get('out', ROOT + 'Work/GCert/Data').rstrip('/') + D = gc.normal(gc.load(path)) + plan = gu.plan(D, opt) + try: + M = gc.mirror(D, gmax=plan['gseg'], batches=plan['batches']) + except gc.Reject as e: + print('REJECTED by the Python mirror (nothing written):', e) + sys.exit(2) + print('%s: mirror accepts; h=%d v=%d R=%d N=%d; pairs=%d; replay segments=%d; scalar batches=%d' + % (name, D['h'], D['v'], D['R'], D['N'], len(M['pairs']), len(M['visits']), len(M['scal']['batches']))) + if 'mirror-only' in sys.argv: + return + src = os.path.basename(path) + mods, sizes, npc = write_data(D, M, name, src, out, opt) + S = gb.spar(D, path) + chk = gb.write_checks(D, M, name, src, out, npc, S, plan) + hist = gb.write_hist(D, M, name, src, out, npc) + price = gb.write_price(D, M, name, src, out, npc) + cert, scalok = gb.write_cert(D, M, name, src, out, chk, npc) + info = dict(name=name, src=path, h=D['h'], v=D['v'], R=D['R'], N=D['N'], cst=D['cst'], nc=len(D['ret']), + hist={str(r): n for r, n in M['hist'].items()}, H={k: {str(r): n for r, n in w.items()} for k, w in M['H'].items()}, + data_modules=mods, data_bytes=sizes, check_modules=chk, hist_module=hist, price_module=price, cert_module=cert, scalok_module=scalok, + spar=S, lab=npc, cuts=M['cuts'], visits=M['visits'], batches=M['scal']['batches'], per_batch=M['scal']['per_batch']) + json.dump(info, open(MY + 'logs/gen-%s.json' % name, 'w'), indent=1) + print('wrote %d data modules (%s bytes), %d check modules, %s, %s' % (len(mods), sizes, len(chk), hist, cert)) + print('build order: ' + ' '.join(mods + [c[0] for c in chk] + [hist, price, cert, scalok])) + + +if __name__ == '__main__': + main() diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxpaths.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxpaths.py new file mode 100644 index 0000000000..355613a9c9 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxpaths.py @@ -0,0 +1,21 @@ +"""gxpaths.py: the paths of this repository for the scripts of tools/gx/ (written for the release; +the working copies of the scripts used absolute paths of the author's machine). + + HERE tools/gx/ the scripts + GEN tools/gen/ foldlib.py, foldgen.py (rate search and Lean text of the rate lemmas), templates/ + OUT output root, default tools/gx/out/ (ignored by git); set the environment variable GX_OUT to change it. + The generators write OUT/Work/GCert/Data/... (the Lean modules, same relative paths as in the + repository), OUT/logs/*.json (figures passed from gxgen.py to gxrate.py) and OUT/cmp/*.json. +""" +import os +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +REPO = os.path.dirname(os.path.dirname(HERE)) + '/' +GEN = REPO + 'tools/gen' +OUT = os.path.abspath(os.environ.get('GX_OUT', REPO + 'tools/gx/out')).rstrip('/') + '/' +for _p in (GEN, HERE): + if _p not in sys.path: + sys.path.insert(0, _p) +for _d in ('Work/GCert/Data/Gen', 'logs', 'cmp'): + os.makedirs(OUT + _d, exist_ok=True) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxrate.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxrate.py new file mode 100644 index 0000000000..6a58830d4c --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxrate.py @@ -0,0 +1,195 @@ +"""gxrate.py: rate, instance, final, challenge and solution modules of the bridged word +B_2 (m = 5 h, any h) for a gcert/1 certificate generated by gxgen.py. tools/gen/crate.py with the +generalised end theorem; bridge-rate's text generators (tools/gen/foldlib.py, foldgen.py) are used READ-ONLY. + +usage: gxrate.py [rate-only] [B=8 s=13] [Bx=10 sx=40] e.g. gxrate.py B2Gp11 P11 + reads /logs/gen-.json (block histogram of one invocation, from gxgen.py) + writes Work/GCert/Data/Rate.lean, Ratex.lean rate lemmas (arithmetic only) + Work/GCert/Data/Inst.lean unit price list = block list (arithmetic only) + Work/GCert/Data/.lean final theorems through GX.wht_of_halves (gxbind.CHAIN) + Work/GCert/Data/Challengex.lean, Solutionx.lean, /cmp/x.json + /logs/rate-.json, rate-x.json +""" +import sys, json +import gxpaths +import foldlib as fl +import foldgen as fg +import gxunit as gu +import gxbind as gb + +ROOT = gxpaths.OUT +MY = ROOT +OUT = ROOT + 'Work/GCert/Data/' +NS = 'OAI.PowerSaving.BlockAccounting' + + +def rate_module(name, u, B, s, cname): + A, Af, Ar, Arf = fl.best_units(u, B, s) + Ae, Are = A, Ar + while fl.plan_block(u, A, B, s) is None: + A -= 1 + while fl.plan_rank(u, Ar, B, s) is None: + Ar -= 1 + while fl.plan_sharp(u, Af, B) is None: + Af += 1 + k = 0 + while fg.rank_sharp_text(name, u, Arf, B) is None and k < 20: + Arf += 1 + k += 1 + m, W, D = u['m'], u['W'], u['D'] + doc = ('Block list `(rank, count)` of ONE unit of the bridged five-stage word B_2 with the gcert/1 circuit `%s` ' + '(h = %d, m = %d): five invocations (ALL blocks of one invocation: x roles, y roles, slots, scratch copies; ' + 'the kernel-counted list `GXD.%s.hist`), and for each of the v = %d ports the idle climbs of its two twins ' + '(2 blocks each of rank h-1, 2h-2, 2h+2, 4); R = %d slots shared by the five stages.' + % (cname, u['h'], m, cname, u['v'], u['R'])) + lst = fg.list_text(name, u, doc) + blk, P = fg.block_text(name, u, A, B, s) + shp, PS = fg.sharp_text(name, u, Af, B) + rk, PR = fg.rank_text(name, u, Ar, B, s) + rks = fg.rank_sharp_text(name, u, Arf, B) + assert rks is not None + head = f'''import Work.BlockAccounting.Moment +import Work.BlockAccounting.Sharp +import Work.FoldRate.RankTools + +/-! +# (key: gx-data) Rate lemmas for one unit of the bridged word B_2 with the gcert/1 circuit `{cname}` (h = {u['h']}) + +GENERATED by checks/wht26/gx-data/py/gxrate.py with the text generators of checks/wht9/bridge-rate/py +(used read-only). No `sorry`. Arithmetic only. + +One unit: `W = {W}` live roles, label dimension `m = {m}`, deficit `D = {D}`. + +* `blocks{name}` the block list (rank, count) of ONE unit; +* `fold_{name}` whole-block fact at `1 - {A}/10^{B}`, fill parameter `s = {s}` (slack {P["slack_rel"]:.2e}); +* `fold_{name}_sharp` `W ≤ moment` at `1 - {Af}/10^{B}`: fails for every table (excess {PS["slack_rel"]:.2e}); +* `foldRank_{name}` per-rank fact at `1 - {Ar}/10^{B}`, `s = {s}` (slack {PR["slack_rel"]:.2e}); +* `foldRank_{name}_sharp` per-rank: fails for every table at `1 - {Arf}/10^{B}`. + +That a Lean word has `G` times this list as its block histogram is NOT proved here. +-/ + +set_option maxRecDepth 4000 + +namespace {NS} +open Finset + +''' + foot = f'\nend {NS}\n\n' + '\n'.join('#print axioms %s.%s_%s' % (NS, a, b) for a, b in + [('fold', name), ('fold', name + '_sharp'), ('foldRank', name), + ('foldRank', name + '_sharp')]) + '\n' + open(OUT + 'Rate%s.lean' % name, 'w').write(head + lst + '\n' + blk + '\n' + shp + '\n' + rk + '\n' + rks + foot) + info = dict(name=name, m=m, W=W, D=D, H=u['H'], A=A, A_eval=Ae, A_fails=Af, A_rank=Ar, A_rank_eval=Are, + A_rank_fails=Arf, B=B, s=s, slack=P['slack_rel'], excess=PS['slack_rel'], rank_slack=PR['slack_rel'], + kind='B2', h=u['h'], R=u['R'], v=u['v'], inv=u['inv'], circuit='gcert1:' + cname) + json.dump(info, open(MY + 'logs/rate-%s.json' % name, 'w'), indent=1) + print('Rate%s: block %d/10^%d (evaluated %d, fails %d), rank %d (evaluated %d, fails %d), s=%d, slack %.2e, rank slack %.2e' + % (name, A, B, Ae, Af, Ar, Are, Arf, s, P['slack_rel'], PR['slack_rel'])) + return info + + +def inst_module(name, cname, d, dx, u): + """arithmetic only: 5 x (price of the kernel-counted histogram) + v x bankPrice h = listCost of the unit list""" + h, m, W, D, v, R = d['h'], d['m'], d['W'], d['D'], d['v'], d['R'] + terms = ' + '.join('%d * φ %d' % (n, r) for r, n in sorted(u['inv'].items())) + blk = 'blocks' + name + txt = f'''import Work.BridgeGeom.B2 +import Work.FoldRate.Group +import Work.GCert.Data.Rate{name} +import Work.GCert.Data.Rate{name}x + +/-! +# (key: gx-data) Bridged word B_2 with the gcert/1 circuit `{cname}`, h = {h}: the unit price is the price of the block list + +GENERATED by checks/wht26/gx-data/py/gxrate.py. No `sorry`. Arithmetic only (no certificate is imported). + +One unit: `W = {W}` live roles (`4 v + R`, `v = {v}`, `R = {R}`), label dimension `m = {m}`, deficit `D = {D}`. +`invPrice φ` = the price of the blocks of ONE invocation (the kernel-counted list `GXD.{cname}.hist`, by rank); +`unitPrice φ = 5 * invPrice φ + v * BG.bankPrice h φ = listCost φ BlockAccounting.{blk}` (`unit_cost`). +Whole-block `1 - {d['A']}/10^{d['B']}` (fails at {d['A_fails']}), ten decimals `1 - {dx['A']}/10^{dx['B']}` (fails at {dx['A_fails']}). +-/ + +namespace OAI +namespace PowerSaving +namespace BridgeRate +namespace {name} +open Finset Binary Matrix RAM CB FoldRate +noncomputable section + +/-- price of the blocks of ONE invocation of `{cname}` (all roles and scratch copies), by rank -/ +def invPrice (φ : ℕ → ℝ) : ℝ := {terms} + +/-- price of ONE unit of the bridged word B_2 -/ +def unitPrice (φ : ℕ → ℝ) : ℝ := 5 * invPrice φ + (({v}:ℕ):ℝ) * BG.bankPrice {h} φ + +/-- **The unit price is the price of the unit block list.** -/ +theorem unit_cost (φ : ℕ → ℝ) : unitPrice φ = listCost φ BlockAccounting.{blk} := by + unfold unitPrice invPrice + simp only [BG.bankPrice, listCost, BlockAccounting.{blk}, List.map_cons, List.map_nil, + List.sum_cons, List.sum_nil] + norm_num [bcost] + try ring + +theorem blocks_x : BlockAccounting.{blk} = BlockAccounting.{blk}x := rfl + +theorem unit_cost_x (φ : ℕ → ℝ) : unitPrice φ = listCost φ BlockAccounting.{blk}x := by + rw [unit_cost, blocks_x] + +/-- one unit stands for `W * m - D` unit moves -/ +theorem unit_tally : unitPrice (fun r => (r:ℝ)) = (({W}:ℕ):ℝ) * (({m}:ℕ):ℝ) - (({D}:ℕ):ℝ) := by + rw [unit_cost] + exact BlockAccounting.{blk}_tally + +end +end {name} +end BridgeRate +end PowerSaving +end OAI + +#print axioms OAI.PowerSaving.BridgeRate.{name}.unit_cost +#print axioms OAI.PowerSaving.BridgeRate.{name}.unit_tally +''' + open(OUT + 'Inst%s.lean' % name, 'w').write(txt) + + +def pack(name, A, B, term, pname): + """comparator package: Work/BridgeRate/ChallengeB2L16x.lean with theorem name and exponent changed""" + src = open(gxpaths.GEN + '/templates/ChallengeB2L16x.lean.txt').read() + thm = 'wht_main_block_' + name + assert src.count('wht_main_block_B2L16x') == 2 and src.count('4059928/(10:ℝ)^10') == 2 and src.count('4059928/10^10') == 2 + sub = lambda t: t.replace('4059928/(10:ℝ)^10', '%d/(10:ℝ)^%d' % (A, B)).replace('4059928/10^10', '%d/10^%d' % (A, B)) + new = (sub(src.replace('wht_main_block_B2L16x', thm)) + .replace('Work.BridgeRate.ChallengeB2L16x', 'Work.GCert.Data.Challenge' + pname) + .replace('Work.BridgeRate.SolutionB2L16x', 'Work.GCert.Data.Solution' + pname)) + a, b = src.split('\n'), new.split('\n') + assert len(a) == len(b) + code = [k for k in range(len(a)) if a[k] != b[k] and k > a.index('-/')] + assert len(code) == 3, code # doc line of the theorem, theorem name, statement + open(OUT + 'Challenge%s.lean' % pname, 'w').write(new) + sol = open(gxpaths.GEN + '/templates/SolutionB2L16x.lean.txt').read() + assert sol.count('wht_main_B2L16x') == 2 + sol = sub(sol.replace('wht_main_block_B2L16x', thm).replace('wht_main_B2L16x', term) + .replace('Work.BridgeRate.B2L16x', 'Work.GCert.Data.' + (name[:-1] if name.endswith('x') else name) + 'Main') + .replace('Work.BridgeRate.SolutionB2L16x', 'Work.GCert.Data.Solution' + pname)) + open(OUT + 'Solution%s.lean' % pname, 'w').write(sol) + cfg = {"challenge_module": 'Work.GCert.Data.Challenge' + pname, "solution_module": 'Work.GCert.Data.Solution' + pname, + "theorem_names": ['OAI.PowerSaving.WHT.' + thm], "definition_names": [], + "permitted_axioms": ["propext", "Quot.sound", "Classical.choice"], "enable_nanoda": False} + json.dump(cfg, open(MY + 'cmp/%s.json' % pname, 'w'), indent=2) + print('packed', pname, thm, '1 - %d/10^%d' % (A, B), 'challenge code lines changed (0-based):', code) + + +if __name__ == '__main__': + name, cname = sys.argv[1], sys.argv[2] + g = json.load(open(MY + 'logs/gen-%s.json' % cname)) + u = gu.unit({int(r): n for r, n in g['hist'].items()}, g['h'], g['v'], g['R'], g['cst']) + print('unit %s: W=%d m=%d D=%d tally=%d blocks=%s' % (name, u['W'], u['m'], u['D'], u['W'] * u['m'] - u['D'], + sorted(u['H'].items()))) + d = rate_module(name, u, 8, 13, cname) + dx = rate_module(name + 'x', u, 10, 40, cname) + inst_module(name, cname, d, dx, u) + if 'rate-only' not in sys.argv: + gb.final_module(name, cname, d, dx, g, OUT) + gb.main_module(name, cname, d, dx, OUT) + pack(name + 'x', dx['A'], dx['B'], 'wht_main_%sx' % name, name + 'x') + pack(name, d['A'], d['B'], 'wht_main_%s' % name, name) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxunit.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxunit.py new file mode 100644 index 0000000000..2c4587038c --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/gxunit.py @@ -0,0 +1,47 @@ +"""gxunit.py: unit of the bridged word B_2 for a gcert/1 block histogram, expected +exponents (bridge-rate's foldlib, READ-ONLY), and the split plan (sizes -> segment counts).""" +import sys +import gxpaths +import foldlib as fl + +# split plan (defaults from MEASURED runs of the new checks on my data, NOTES.md "Measured") +GSEG = 12000 # most gates in one replay segment (gx-labels: one packed elimination per gate) +SCAL_ADDS = 30000 # most single adds (scatter entries included) checked in ONE source batch. Measured with the tagged + # GS.scalCheck (Work/GCert/Scalar/Seg.lean): time and memory follow the ADDS, not the sources: + # 7,440 adds 3 s 1.2 GB (p6); 14,407 adds 6 s 2.0 GB (p7); 81,103 adds x 165 sources 168 s 6.8 GB (#168); + # 80,821 adds x 660 sources 180 s 7.0 GB (#193). Above SCAL_ADDS: two batches (each under the 5-minute hold). +TSPLIT = 2 # the frame table is checked in 2^TSPLIT subtries + + +def plan(D, opt): + adds = sum(len(g[3]) for g in D['A'] + D['B']) + (D['v'] * D['h'] if D['scat'][0] == 'star' else sum(map(len, D['scat'][1]))) + b = int(opt.get('batches', 1 if adds <= SCAL_ADDS else 2)) + return dict(gseg=int(opt.get('gseg', GSEG)), batches=b, tsplit=int(opt.get('tsplit', TSPLIT))) + + +def unit(inv, h, v, R, cst): + """block list of one unit: 5 x (blocks of one invocation) + 2v x {h-1, 2h-2, 2h+2, 4}""" + H = {} + + def add(r, n): + if n: + H[r] = H.get(r, 0) + n + for r, n in inv.items(): + add(r, 5 * n) + for cv, rk in fl.BANK['B2']: + add(rk(h), cv * v) + m, W = 5 * h, 4 * v + R + D = W * m - sum(r * n for r, n in H.items()) + assert D == 4 * v - 5 * cst, (D, 4 * v - 5 * cst) + return dict(kind='B2', h=h, m=m, W=W, D=D, v=v, R=R, H=H, inv=dict(inv), cst=cst) + + +def rates(u, B, s): + """as crate.rate_module chooses them: evaluated units, then the largest with a rational certificate""" + A0, Af, Ar0, Arf = fl.best_units(u, B, s) + A, Ar = A0, Ar0 + while fl.plan_block(u, A, B, s) is None: + A -= 1 + while fl.plan_rank(u, Ar, B, s) is None: + Ar -= 1 + return dict(A=A, A_eval=A0, A_fails=Af, A_rank=Ar, A_rank_eval=Ar0, A_rank_fails=Arf, B=B, s=s) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check.py new file mode 100644 index 0000000000..720c4c06af --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +"""Regenerate the Lean modules of a generalised certificate (gcert/1) and compare them with this repository. + +usage (from anywhere): python3 tools/gx/regen_check.py [ ] [--keep ] +default: tools/certificate/gcert1-p11-pr193.json.gz P193 B2Gp193 + +Runs, into a fresh directory (a temporary one, or with --keep; never into the source tree): + tools/gx/gxgen.py Python mirror of both Lean checks, then data and check modules + tools/gx/gxrate.py rate lemmas, unit price list, final modules, comparator package +and compares every generated Lean file with the file of the same path in this repository, and every generated +comparator configuration with comparator/. A generated file that this repository does not contain +is listed as "(not in the repository)". Exit code 0 = no generated file differs and at least one was compared. + +Needs only Python 3 (standard library). No Lean is run. +""" +import hashlib +import os +import shutil +import subprocess +import sys +import tempfile + +ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +DEFAULT = ["tools/certificate/gcert1-p11-pr193.json.gz", "P193", "B2Gp193"] + + +def sha(path): + h = hashlib.sha256() + with open(path, "rb") as f: + for block in iter(lambda: f.read(1 << 20), b""): + h.update(block) + return h.hexdigest() + + +def main(): + args = sys.argv[1:] + keep = None + if "--keep" in args: + i = args.index("--keep") + keep = os.path.abspath(args[i + 1]) + del args[i:i + 2] + if os.path.exists(keep) and os.listdir(keep): + sys.exit("--keep: the directory must be empty or absent: " + keep) + os.makedirs(keep, exist_ok=True) + cert, name, inst = args if len(args) == 3 else DEFAULT + out = keep or tempfile.mkdtemp(prefix="regen-gx-") + print("certificate %s\n sha256 %s" % (cert, sha(os.path.join(ROOT, cert)))) + env = dict(os.environ, PYTHONDONTWRITEBYTECODE="1", GX_OUT=out) + for cmd in (["tools/gx/gxgen.py", cert, name], ["tools/gx/gxrate.py", inst, name]): + print("$ GX_OUT= python3 " + " ".join(cmd), flush=True) + r = subprocess.run([sys.executable] + cmd, cwd=ROOT, env=env) + if r.returncode != 0: + sys.exit("generator failed with exit code %d" % r.returncode) + made = sorted(os.path.relpath(os.path.join(d, f), out) for d, _, fs in os.walk(out) for f in fs) + same = diff = extra = 0 + for rel in made: + if rel.startswith("logs/"): + continue # figures passed between the two generators + tgt = "comparator/" + rel[4:] if rel.startswith("cmp/") else rel + a, b = os.path.join(out, rel), os.path.join(ROOT, tgt) + if not os.path.isfile(b): + extra += 1 + print("(not in the repository) %s" % tgt) + continue + ok = open(a, "rb").read() == open(b, "rb").read() + same += ok + diff += not ok + print("%-9s %9d bytes %s %s" % ("IDENTICAL" if ok else "DIFFERENT", os.path.getsize(a), sha(a)[:16], tgt)) + if keep is None: + shutil.rmtree(out) + else: + print("generated files kept in " + keep) + good = diff == 0 and same > 0 + print("RESULT: %s (%d repository files reproduced byte for byte, %d different, %d generated files not in the repository)" + % ("REPRODUCED" if good else "FAIL", same, diff, extra)) + sys.exit(0 if good else 1) + + +if __name__ == "__main__": + main() diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check_e8.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check_e8.py new file mode 100644 index 0000000000..c4db78c06f --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/inputs/e8/tools/gx/regen_check_e8.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +"""Regenerate the Lean modules of the E8 certificate and compare them with this repository. + +usage (from anywhere): python3 tools/gx/regen_check_e8.py [--keep ] + +This runs tools/gx/regen_check.py, unchanged, with the arguments of the E8 certificate: + + python3 tools/gx/regen_check.py tools/certificate/gcert1-e8-r783.json.gz E8 B2Ge8 + +so that each certificate of this repository has one command without arguments. Before that it checks that +the certificate file has the expected sha256. The two generators (tools/gx/gxgen.py, tools/gx/gxrate.py) +write, into a fresh directory, the 24 Lean modules under Work/GCert/Data/ that carry the names E8 and B2Ge8 +and the comparator configuration comparator/B2Ge8x.json; every generated file is compared byte for byte with +the file of the same path in this repository. Expected last line, exit code 0: + + RESULT: REPRODUCED (25 repository files reproduced byte for byte, 0 different, 3 generated files not in the repository) + +The three generated files that are not in the repository are the eight-decimal variant (ChallengeB2Ge8, +SolutionB2Ge8 and its comparator configuration), as for the certificate P193. The exit code is that of +tools/gx/regen_check.py: 0 when no generated file differs and at least one was compared, so read the counts +of the last line as well. + +Needs only Python 3 (standard library). No Lean is run. +""" +import hashlib +import os +import subprocess +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +ROOT = os.path.dirname(os.path.dirname(HERE)) +ARGS = ["tools/certificate/gcert1-e8-r783.json.gz", "E8", "B2Ge8"] +CERT_SHA256 = "4b92f00fc7454b9b15e6d71a3b05062792eacca0a0ca4efee46f87827d57c8aa" + +extra = sys.argv[1:] +if extra and not (len(extra) == 2 and extra[0] == "--keep"): + sys.exit(__doc__) +got = hashlib.sha256(open(os.path.join(ROOT, ARGS[0]), "rb").read()).hexdigest() +if got != CERT_SHA256: + sys.exit("RESULT: FAIL (%s has sha256 %s, expected %s)" % (ARGS[0], got, CERT_SHA256)) +sys.exit(subprocess.run([sys.executable, os.path.join(HERE, "regen_check.py")] + ARGS + extra).returncode) diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/new-derived-pins.json b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/new-derived-pins.json new file mode 100644 index 0000000000..5f1e0df1a0 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/new-derived-pins.json @@ -0,0 +1,42 @@ +{ + "frames": 948, + "gates": [ + 775, + 1226 + ], + "label_histogram": { + "1": 2093, + "2": 606, + "3": 524, + "4": 119, + "5": 215, + "6": 341, + "7": 43, + "8": 24, + "9": 8 + }, + "ledger": [ + 29491, + 94473, + 216, + 38 + ], + "scalar_steps": [ + 68158, + 72856 + ], + "climbed": { + "A": 1237, + "B": 1953, + "final": 775 + }, + "climb_forward": 3965, + "climb_backward": 3965, + "local_bill": 2271769336984, + "stock_bits": [ + 1892, + 1903, + 1903, + 1908 + ] +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8-b3.json b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8-b3.json new file mode 100644 index 0000000000..4dcc074355 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8-b3.json @@ -0,0 +1,59 @@ +{ + "V": 120, + "R": 783, + "H": 9, + "cst": 72, + "N": 9039, + "frames": 946, + "scatter": "8178452d0315a0e454b6230b41fd4dca2a55b5519718a2c1ba523f60917a79d4", + "gates": [ + 773, + 1220 + ], + "centre_ranks": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9 + ], + "label_histogram": { + "1": 2091, + "2": 604, + "3": 518, + "4": 140, + "5": 215, + "6": 331, + "7": 43, + "8": 24, + "9": 8 + }, + "scalar_steps": [ + 68158, + 72856 + ], + "climbed": { + "A": 1239, + "B": 1952, + "final": 775 + }, + "climb_forward": 3966, + "climb_backward": 3966, + "K": 3, + "ledger": [ + 29978, + 94473, + 216, + 31 + ], + "local_bill": 2271903554712, + "stock_bits": [ + 1892, + 1903, + 1903, + 1908 + ] +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8.json b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8.json new file mode 100644 index 0000000000..ba757ae806 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/pins-e8.json @@ -0,0 +1,58 @@ +{ + "V": 120, + "R": 783, + "H": 9, + "cst": 72, + "N": 9039, + "frames": 946, + "scatter": "8178452d0315a0e454b6230b41fd4dca2a55b5519718a2c1ba523f60917a79d4", + "gates": [ + 773, + 1220 + ], + "centre_ranks": [ + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9 + ], + "label_histogram": { + "1": 2091, + "2": 604, + "3": 518, + "4": 140, + "5": 215, + "6": 331, + "7": 43, + "8": 24, + "9": 8 + }, + "ledger": [ + 20830, + 56715, + 120, + 20 + ], + "scalar_steps": [ + 68158, + 72856 + ], + "climbed": { + "A": 1239, + "B": 1952, + "final": 775 + }, + "climb_forward": 3966, + "climb_backward": 3966, + "local_bill": 839986392216, + "stock_bits": [ + 947, + 957, + 958, + 963 + ] +} \ No newline at end of file diff --git a/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/portable_complex.py b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/portable_complex.py new file mode 100644 index 0000000000..0bc6f87c10 --- /dev/null +++ b/research/e8-signed-donor-gauge/pr378-complex-screen/candidate-guard/portable_complex.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +"""Fresh complex label, scalar, splice and finite-guard checks from primary inputs. +No saved PASS receipts, workstation paths, network or Lean rebuild are required. +p = 10 packages: the complex program itself is admitted by Sussman's gx.check1 with the exact scalar identity and by +his gxcore mirror (code/complex_gx.py), added by DreamingOfClouds with Anthropic Claude assistance. +E8 package: the scatter (table or star rule), the number of retained totals and each centre child's rank are read +from the certificate (code/scatter.py) instead of the paired-cube star rule with h centres of rank h - 2. +""" +from collections import Counter +from copy import deepcopy +from fractions import Fraction as Q +from hashlib import sha256 +from math import prod +from pathlib import Path +import gzip, importlib.util, json, sys, os +sys.dont_write_bytecode = True +sys.path.insert(0,str(Path(__file__).resolve().parent/'code')) +from p10pins import PINS, pin, RECORD +import bridged +KL=int(PINS.get('K',2)); SL=2*KL+1 # bridged word B_K: KL bank pairs per class, SL = 2K+1 stages (KL=2: Sussman's five-stage B_2) + +PIN='f010392c923279e3dd59ef3aa5fedad23affc5fd' +CHRONOLOGY=(['stage0','stage1','climbA','bridgeA','stage2','climbB','bridgeB','stage3','stage4','final_climbs','bridgeC','terminal_shifts','signed_exchange'] if KL==2 else + ['stage0','stage1','climbA12','bridgeA12','stage2','climbB12','bridgeB12']+[x for q in range(2,KL) for x in ('stage%d'%(2*q-1),'climbA%d%d'%(q,q+1),'bridgeA%d%d'%(q,q+1),'stage%d'%(2*q),'climbB%d%d'%(q,q+1),'bridgeB%d%d'%(q,q+1))] + +['stage%d'%(2*KL-1),'stage%d'%(2*KL),'final_climbs']+['bridgeC%d%d'%(q-1,q) for q in range(KL,1,-1)]+['terminal_shifts','signed_exchange']) + +def need(ok, why): + if not ok: raise ValueError(why) + +def module(root, name): + spec=importlib.util.spec_from_file_location('portable_'+name,root/'code'/(name+'.py')) + result=importlib.util.module_from_spec(spec);spec.loader.exec_module(result) + return result + +def finite_guard(m, b, basis): + p=m['parameters'];l=m['ledger'];dim=p['m'];R=p['R'];h=p['h'];W=p['W_live'] + need((dim,R,h,W)==(SL*PINS['H'],PINS['R'],PINS['H'],2*KL*PINS['V']+PINS['R']),'complex family changed') + scalar=max(b[o]['totals']['real_component_primitive_steps'] for o in ['forward','backward']) + macros=max(b[o]['totals']['scalar_macros'] for o in ['forward','backward']) + scalar5=(KL+1)*b['forward']['totals']['real_component_primitive_steps']+KL*b['backward']['totals']['real_component_primitive_steps'] + physical=W+R+h+1 + adapters=8*(macros+m['checks']['invocation_calls']+p['invocation_live']+h)+32*dim + outside=8*(l['idle_calls']+6*(KL-1)*p['v']+physical)+32*dim + compiler=64*(dim+1)**3 + local=scalar+adapters*compiler + pervertex=scalar5+12*(KL-1)*p['v']+(SL*adapters+outside)*compiler+64*physical + group=(1<<(dim-1+(dim//2-1)**2))*prod((1<<(2*i))-1 for i in range(1,dim//2)) + live_stock=group*W;physical_stock=group*physical;s=group*l['rank_mass'] + K=group*pervertex+64;router=compiler*(K+1)*(physical_stock+1)**2 + G,E,C0=1<<30000,1<<100000,1<<210000;B=s+E + literal=2*G*physical_stock**2+8*s+4*physical_stock+4+32*dim + pin('local_bill',local,'fresh local/global bill');need(local<1<<48 and K<1<<6050,'fresh local/global bill') + pin('stock_bits',[group.bit_length(),live_stock.bit_length(),physical_stock.bit_length(),s.bit_length()],'fresh cover/work stock') + need(router=1,'completed-child induction') + # least halving degree t: dim^t > 2 max_child^t (t = 1 is the half-shrink guard of the original bridge). The external + # row coefficient charges t times the stock logarithm, as in PR #144's integration (4*2571+9909+252) and + # copied-centers-assembly.tex (D_j(e) = t_j ceil(log2 e)); the cover bound V < 2^(m m) <= 2^5184 needs m <= 72. + t=1 + while dim**t<=2*l['max_child']**t:t+=1 + need(32*dim*B*B0,'row reserve gap') + need(2*(dim*(dim-1)+3*dim+dim+3*dim*(dim-1)//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 array, false --> object). + + @param[in] is_array Determines if the element list being read is to be + treated as an object (@a is_array == false), or as an + array (@a is_array == true). + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_list(const bool is_array) + { + string_t key; + + while (auto element_type = get()) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + { + return false; + } + + const std::size_t element_type_parse_position = chars_read; + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) + { + return false; + } + + if (!is_array && !sax->key(key)) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) + { + return false; + } + + // get_bson_cstr only appends + key.clear(); + } + + return true; + } + + /*! + @brief Reads an array from the BSON input and passes it to the SAX-parser. + @return whether a valid BSON-array was passed to the SAX parser + */ + bool parse_bson_array() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) + { + return false; + } + + return sax->end_array(); + } + + ////////// + // CBOR // + ////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) + { + switch (get_char ? get() : current) + { + // EOF + case char_traits::eof(): + return unexpect_eof(input_format_t::cbor, "value"); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return sax->number_unsigned(static_cast(current)); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return sax->number_integer(static_cast(0x20 - 1 - current)); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) + - static_cast(number)); + } + + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: // Binary data (one-byte uint8_t for n follows) + case 0x59: // Binary data (two-byte uint16_t for n follow) + case 0x5A: // Binary data (four-byte uint32_t for n follow) + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + case 0x5F: // Binary data (indefinite length) + { + binary_t b; + return get_cbor_binary(b) && sax->binary(b); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + string_t s; + return get_cbor_string(s) && sax->string(s); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + return get_cbor_array( + conditional_static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0x98: // array (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast(len), tag_handler); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast(len), tag_handler); + } + + case 0x9F: // array (indefinite length) + return get_cbor_array(detail::unknown_size(), tag_handler); + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + return get_cbor_object(conditional_static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0xB8: // map (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast(len), tag_handler); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast(len), tag_handler); + } + + case 0xBF: // map (indefinite length) + return get_cbor_object(detail::unknown_size(), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + + case cbor_tag_handler_t::ignore: + { + // ignore binary subtype + switch (current) + { + case 0xD8: + { + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xD9: + { + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDA: + { + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDB: + { + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + return parse_cbor_internal(true, tag_handler); + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + case 0xF4: // false + return sax->boolean(false); + + case 0xF5: // true + return sax->boolean(true); + + case 0xF6: // null + return sax->null(); + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte1 << 8u) + byte2); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + default: // anything else (0xFF is handled inside the other types) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + } + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_cbor_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + { + return false; + } + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + while (get() != 0xFF) + { + string_t chunk; + if (!get_cbor_string(chunk)) + { + return false; + } + result.append(chunk); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); + } + } + } + + /*! + @brief reads a CBOR byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into the byte array. + Additionally, CBOR's byte arrays with indefinite lengths are supported. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_cbor_binary(binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + { + return false; + } + + switch (current) + { + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + { + return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x58: // Binary data (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x59: // Binary data (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5A: // Binary data (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5F: // Binary data (indefinite length) + { + while (get() != 0xFF) + { + binary_t chunk; + if (!get_cbor_binary(chunk)) + { + return false; + } + result.insert(result.end(), chunk.begin(), chunk.end()); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); + } + } + } + + /*! + @param[in] len the length of the array or detail::unknown_size() for an + array of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether array creation completed + */ + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + if (len != detail::unknown_size()) + { + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) + { + return false; + } + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object or detail::unknown_size() for an + object of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether object creation completed + */ + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + if (len != 0) + { + string_t key; + if (len != detail::unknown_size()) + { + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + } + + return sax->end_object(); + } + + ///////////// + // MsgPack // + ///////////// + + /*! + @return whether a valid MessagePack value was passed to the SAX parser + */ + bool parse_msgpack_internal() + { + switch (get()) + { + // EOF + case char_traits::eof(): + return unexpect_eof(input_format_t::msgpack, "value"); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return sax->number_unsigned(static_cast(current)); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + return get_msgpack_object(conditional_static_cast(static_cast(current) & 0x0Fu)); + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + return get_msgpack_array(conditional_static_cast(static_cast(current) & 0x0Fu)); + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + { + string_t s; + return get_msgpack_string(s) && sax->string(s); + } + + case 0xC0: // nil + return sax->null(); + + case 0xC2: // false + return sax->boolean(false); + + case 0xC3: // true + return sax->boolean(true); + + case 0xC4: // bin 8 + case 0xC5: // bin 16 + case 0xC6: // bin 32 + case 0xC7: // ext 8 + case 0xC8: // ext 16 + case 0xC9: // ext 32 + case 0xD4: // fixext 1 + case 0xD5: // fixext 2 + case 0xD6: // fixext 4 + case 0xD7: // fixext 8 + case 0xD8: // fixext 16 + { + binary_t b; + return get_msgpack_binary(b) && sax->binary(b); + } + + case 0xCA: // float 32 + { + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCB: // float 64 + { + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCC: // uint 8 + { + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCD: // uint 16 + { + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCE: // uint 32 + { + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCF: // uint 64 + { + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xD0: // int 8 + { + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD1: // int 16 + { + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD2: // int 32 + { + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD3: // int 64 + { + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xDC: // array 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDD: // array 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast(len)); + } + + case 0xDE: // map 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + case 0xDF: // map 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast(len)); + } + + // negative fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return sax->number_integer(static_cast(current)); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_msgpack_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + { + return false; + } + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); + } + + case 0xD9: // str 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDA: // str 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDB: // str 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); + } + } + } + + /*! + @brief reads a MessagePack byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into a byte array. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_msgpack_binary(binary_t& result) + { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + + switch (current) + { + case 0xC4: // bin 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC5: // bin 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC6: // bin 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC7: // ext 8 + { + std::uint8_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC8: // ext 16 + { + std::uint16_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC9: // ext 32 + { + std::uint32_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xD4: // fixext 1 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && + assign_and_return_true(subtype); + } + + case 0xD5: // fixext 2 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && + assign_and_return_true(subtype); + } + + case 0xD6: // fixext 4 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && + assign_and_return_true(subtype); + } + + case 0xD7: // fixext 8 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && + assign_and_return_true(subtype); + } + + case 0xD8: // fixext 16 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && + assign_and_return_true(subtype); + } + + default: // LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + /*! + @param[in] len the length of the array + @return whether array creation completed + */ + bool get_msgpack_array(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object + @return whether object creation completed + */ + bool get_msgpack_object(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + key.clear(); + } + + return sax->end_object(); + } + + //////////// + // UBJSON // + //////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether a valid UBJSON value was passed to the SAX parser + */ + bool parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[out] result created string + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether string creation completed + */ + bool get_ubjson_string(string_t& result, const bool get_char = true) + { + if (get_char) + { + get(); // TODO(niels): may we ignore N here? + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + { + return false; + } + + switch (current) + { + case 'U': + { + std::uint8_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'i': + { + std::int8_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'I': + { + std::int16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'l': + { + std::int32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'L': + { + std::int64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + default: + break; + } + auto last_token = get_token_string(); + std::string message; + + if (input_format != input_format_t::bjdata) + { + message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token; + } + else + { + message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; + } + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); + } + + /*! + @param[out] dim an integer vector storing the ND array dimensions + @return whether reading ND array size vector is successful + */ + bool get_ubjson_ndarray_size(std::vector& dim) + { + std::pair size_and_type; + size_t dimlen = 0; + bool no_ndarray = true; + + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) + { + return false; + } + + if (size_and_type.first != npos) + { + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) + { + return false; + } + dim.push_back(dimlen); + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) + { + return false; + } + dim.push_back(dimlen); + } + } + } + else + { + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) + { + return false; + } + dim.push_back(dimlen); + get_ignore_noop(); + } + } + return true; + } + + /*! + @param[out] result determined size + @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector + or ndarray dimension is not allowed; `false` means ndarray + is allowed; for output, `true` means an ndarray is found; + is_ndarray can only return `true` when its initial value + is `false` + @param[in] prefix type marker if already read, otherwise set to 0 + + @return whether size determination completed + */ + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) + { + if (prefix == 0) + { + prefix = get_ignore_noop(); + } + + switch (prefix) + { + case 'U': + { + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'i': + { + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char + return true; + } + + case 'I': + { + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'l': + { + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'L': + { + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + if (!value_in_range_of(number)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + exception_message(input_format, "integer value overflow", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = conditional_static_cast(number); + return true; + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (!value_in_range_of(number)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + exception_message(input_format, "integer value overflow", "size"), nullptr)); + } + result = detail::conditional_static_cast(number); + return true; + } + + case '[': + { + if (input_format != input_format_t::bjdata) + { + break; + } + if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); + } + std::vector dim; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) + { + return false; + } + if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector + { + result = dim.at(dim.size() - 1); + return true; + } + if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format + { + for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container + { + if ( i == 0 ) + { + result = 0; + return true; + } + } + + string_t key = "_ArraySize_"; + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) + { + return false; + } + result = 1; + for (auto i : dim) + { + result *= i; + if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast(i)))) + { + return false; + } + } + is_ndarray = true; + return sax->end_array(); + } + result = 0; + return true; + } + + default: + break; + } + auto last_token = get_token_string(); + std::string message; + + if (input_format != input_format_t::bjdata) + { + message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token; + } + else + { + message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; + } + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @param[out] result pair of the size and the type + @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector + + @return whether pair creation completed + */ + bool get_ubjson_size_type(std::pair& result, bool inside_ndarray = false) + { + result.first = npos; // size + result.second = 0; // type + bool is_ndarray = false; + + get_ignore_noop(); + + if (current == '$') + { + result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (input_format == input_format_t::bjdata + && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second))) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) + { + return false; + } + + get_ignore_noop(); + if (JSON_HEDLEY_UNLIKELY(current != '#')) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + { + return false; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); + } + + const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + if (input_format == input_format_t::bjdata && is_ndarray) + { + if (inside_ndarray) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, + exception_message(input_format, "ndarray can not be recursive", "size"), nullptr)); + } + result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters + } + return is_error; + } + + if (current == '#') + { + const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + if (input_format == input_format_t::bjdata && is_ndarray) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, + exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); + } + return is_error; + } + + return true; + } + + /*! + @param prefix the previously read or set type prefix + @return whether value creation completed + */ + bool get_ubjson_value(const char_int_type prefix) + { + switch (prefix) + { + case char_traits::eof(): // EOF + return unexpect_eof(input_format, "value"); + + case 'T': // true + return sax->boolean(true); + case 'F': // false + return sax->boolean(false); + + case 'Z': // null + return sax->null(); + + case 'B': // byte + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'U': + { + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'i': + { + std::int8_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'I': + { + std::int16_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'l': + { + std::int32_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'L': + { + std::int64_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'h': + { + if (input_format != input_format_t::bjdata) + { + break; + } + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte2 << 8u) + byte1); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 'd': + { + float number{}; + return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + } + + case 'D': + { + double number{}; + return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); + } + + case 'C': // char + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(current > 127)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); + } + string_t s(1, static_cast(current)); + return sax->string(s); + } + + case 'S': // string + { + string_t s; + return get_ubjson_string(s) && sax->string(s); + } + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + break; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); + } + + /*! + @return whether array creation completed + */ + bool get_ubjson_array() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata): + // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]} + + if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) + { + size_and_type.second &= ~(static_cast(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker + auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t) + { + return p.first < t; + }); + string_t key = "_ArrayType_"; + if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); + } + + string_t type = it->second; // sax->string() takes a reference + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) + { + return false; + } + + if (size_and_type.second == 'C' || size_and_type.second == 'B') + { + size_and_type.second = 'U'; + } + + key = "_ArrayData_"; + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) + { + return false; + } + + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + + return (sax->end_array() && sax->end_object()); + } + + // If BJData type marker is 'B' decode as binary + if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B') + { + binary_t result; + return get_binary(input_format, size_and_type.first, result) && sax->binary(result); + } + + if (size_and_type.first != npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) + { + return false; + } + + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) + { + return false; + } + get_ignore_noop(); + } + } + + return sax->end_array(); + } + + /*! + @return whether object creation completed + */ + bool get_ubjson_object() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + // do not accept ND-array size in objects in BJData + if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); + } + + string_t key; + if (size_and_type.first != npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + key.clear(); + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + key.clear(); + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) + { + return false; + } + + while (current != '}') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + get_ignore_noop(); + key.clear(); + } + } + + return sax->end_object(); + } + + // Note, no reader for UBJSON binary types is implemented because they do + // not exist + + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + bool no_ndarray = true; + auto res = get_ubjson_size_value(size, no_ndarray); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + using ia_type = decltype(detail::input_adapter(number_vector)); + auto number_lexer = detail::lexer(detail::input_adapter(number_vector), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) + { + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + case token_type::uninitialized: + case token_type::literal_true: + case token_type::literal_false: + case token_type::literal_null: + case token_type::value_string: + case token_type::begin_array: + case token_type::begin_object: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::parse_error: + case token_type::end_of_input: + case token_type::literal_or_value: + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + } + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `char_traits::eof()` in that case. + + @return character read from the input + */ + char_int_type get() + { + ++chars_read; + return current = ia.get_character(); + } + + /*! + @brief get_to read into a primitive type + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns false instead + + @return bool, whether the read was successful + */ + template + bool get_to(T& dest, const input_format_t format, const char* context) + { + auto new_chars_read = ia.get_elements(&dest); + chars_read += new_chars_read; + if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T))) + { + // in case of failure, advance position by 1 to report failing location + ++chars_read; + sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + return false; + } + return true; + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + char_int_type get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + template + static void byte_swap(NumberType& number) + { + constexpr std::size_t sz = sizeof(number); +#ifdef __cpp_lib_byteswap + if constexpr (sz == 1) + { + return; + } + if constexpr(std::is_integral_v) + { + number = std::byteswap(number); + return; + } +#endif + auto* ptr = reinterpret_cast(&number); + for (std::size_t i = 0; i < sz / 2; ++i) + { + std::swap(ptr[i], ptr[sz - i - 1]); + } + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[out] result number of type @a NumberType + + @return whether conversion completed + + @note This function needs to respect the system's endianness, because + bytes in CBOR, MessagePack, and UBJSON are stored in network order + (big endian) and therefore need reordering on little endian systems. + On the other hand, BSON and BJData use little endian and should reorder + on big endian systems. + */ + template + bool get_number(const input_format_t format, NumberType& result) + { + // read in the original format + + if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number"))) + { + return false; + } + if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + { + byte_swap(result); + } + return true; + } + + /*! + @brief create a string by reading characters from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of characters to read + @param[out] result string created by reading @a len bytes + + @return whether string creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + */ + template + bool get_string(const input_format_t format, + const NumberType len, + string_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @brief create a byte array by reading bytes from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of bytes to read + @param[out] result byte array created by reading @a len bytes + + @return whether byte array creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of memory. + */ + template + bool get_binary(const input_format_t format, + const NumberType len, + binary_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) + @return whether the last read character is not EOF + */ + JSON_HEDLEY_NON_NULL(3) + bool unexpect_eof(const input_format_t format, const char* context) const + { + if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) + { + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + } + return true; + } + + /*! + @return a string representation of the last read byte + */ + std::string get_token_string() const + { + std::array cr{{}}; + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + return std::string{cr.data()}; + } + + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further context information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + case input_format_t::bjdata: + error_msg += "BJData"; + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + return concat(error_msg, ' ', context, ": ", detail); + } + + private: + static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size(); + + /// input adapter + InputAdapterType ia; + + /// the current character + char_int_type current = char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianness + const bool is_little_endian = little_endianness(); + + /// input format + const input_format_t input_format = input_format_t::json; + + /// the SAX parser + json_sax_t* sax = nullptr; + + // excluded markers in bjdata optimized type +#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \ + make_array('F', 'H', 'N', 'S', 'T', 'Z', '[', '{') + +#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ + make_array( \ + bjd_type{'B', "byte"}, \ + bjd_type{'C', "char"}, \ + bjd_type{'D', "double"}, \ + bjd_type{'I', "int16"}, \ + bjd_type{'L', "int64"}, \ + bjd_type{'M', "uint64"}, \ + bjd_type{'U', "uint8"}, \ + bjd_type{'d', "single"}, \ + bjd_type{'i', "int8"}, \ + bjd_type{'l', "int32"}, \ + bjd_type{'m', "uint32"}, \ + bjd_type{'u', "uint16"}) + + JSON_PRIVATE_UNLESS_TESTED: + // lookup tables + // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers = + JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_; + + using bjd_type = std::pair; + // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map = + JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_; + +#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ +#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr std::size_t binary_reader::npos; +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +//////////// +// parser // +//////////// + +enum class parse_event_t : std::uint8_t +{ + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value +}; + +template +using parser_callback_t = + std::function; + +/*! +@brief syntax analysis + +This class implements a recursive descent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + /// a parser reading from an input adapter + explicit parser(InputAdapterType&& adapter, + parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(std::move(cb)) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) + { + // read first token + get_token(); + } + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + if (callback) + { + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions, &m_lexer); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"), nullptr)); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + else + { + json_sax_dom_parser sdp(result, allow_exceptions, &m_lexer); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + } + + result.assert_invariant(); + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + json_sax_acceptor sax_acceptor; + return sax_parse(&sax_acceptor, strict); + } + + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse(SAX* sax, const bool strict = true) + { + (void)detail::is_sax_static_asserts {}; + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result && strict && (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); + } + + return result; + } + + private: + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse_internal(SAX* sax) + { + // stack to remember the hierarchy of structured values we are parsing + // true = array; false = object + std::vector states; + // value to avoid a goto (see comment where set to true) + bool skip_to_state_evaluation = false; + + while (true) + { + if (!skip_to_state_evaluation) + { + // invariant: get_token() was called before each iteration + switch (last_token) + { + case token_type::begin_object: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) + { + return false; + } + + // closing } -> we are done + if (get_token() == token_type::end_object) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + break; + } + + // parse key + if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); + } + + // remember we are now inside an object + states.push_back(false); + + // parse values + get_token(); + continue; + } + + case token_type::begin_array: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) + { + return false; + } + + // closing ] -> we are done + if (get_token() == token_type::end_array) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + break; + } + + // remember we are now inside an array + states.push_back(true); + + // parse values (no need to call get_token) + continue; + } + + case token_type::value_float: + { + const auto res = m_lexer.get_number_float(); + + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) + { + return false; + } + + break; + } + + case token_type::literal_false: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) + { + return false; + } + break; + } + + case token_type::literal_null: + { + if (JSON_HEDLEY_UNLIKELY(!sax->null())) + { + return false; + } + break; + } + + case token_type::literal_true: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) + { + return false; + } + break; + } + + case token_type::value_integer: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) + { + return false; + } + break; + } + + case token_type::value_string: + { + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) + { + return false; + } + break; + } + + case token_type::value_unsigned: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) + { + return false; + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr)); + } + case token_type::end_of_input: + { + if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); + } + case token_type::uninitialized: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::literal_or_value: + default: // the last token was unexpected + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); + } + } + } + else + { + skip_to_state_evaluation = false; + } + + // we reached this line after we successfully parsed a value + if (states.empty()) + { + // empty stack: we reached the end of the hierarchy: done + return true; + } + + if (states.back()) // array + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse a new value + get_token(); + continue; + } + + // closing ] + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + + // We are done with this array. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr)); + } + + // states.back() is false -> object + + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); + } + + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr)); + } + } + + /// get next token from lexer + token_type get_token() + { + return last_token = m_lexer.scan(); + } + + std::string exception_message(const token_type expected, const std::string& context) + { + std::string error_msg = "syntax error "; + + if (!context.empty()) + { + error_msg += concat("while parsing ", context, ' '); + } + + error_msg += "- "; + + if (last_token == token_type::parse_error) + { + error_msg += concat(m_lexer.get_error_message(), "; last read: '", + m_lexer.get_token_string(), '\''); + } + else + { + error_msg += concat("unexpected ", lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += concat("; expected ", lexer_t::token_type_name(expected)); + } + + return error_msg; + } + + private: + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // ptrdiff_t +#include // numeric_limits + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + JSON_PRIVATE_UNLESS_TESTED: + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + ++m_it; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + --m_it; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// forward declare, to be able to friend it later on +template class iteration_proxy; +template class iteration_proxy_value; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) +{ + /// the iterator with BasicJsonType of different const-ness + using other_iter_impl = iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + /// allow basic_json to access private members + friend other_iter_impl; + friend BasicJsonType; + friend iteration_proxy; + friend iteration_proxy_value; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + // superficial check for the LegacyBidirectionalIterator named requirement + static_assert(std::is_base_of::value + && std::is_base_of::iterator_category>::value, + "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); + + public: + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + iter_impl() = default; + ~iter_impl() = default; + iter_impl(iter_impl&&) noexcept = default; + iter_impl& operator=(iter_impl&&) noexcept = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief const copy constructor + @param[in] other const iterator to copy from + @note This copy constructor had to be defined explicitly to circumvent a bug + occurring on msvc v19.0 compiler (VS 2015) debug build. For more + information refer to: https://github.com/nlohmann/json/issues/1608 + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl& other) noexcept + { + if (&other != this) + { + m_object = other.m_object; + m_it = other.m_it; + } + return *this; + } + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept // NOLINT(cert-oop54-cpp) + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_data.m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_data.m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_data.m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_data.m_value.array->end(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); + return &*m_it.array_iterator; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator==(const IterImpl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + } + + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + return true; + } + + switch (m_object->m_data.m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator!=(const IterImpl& other) const + { + return !operator==(other); + } + + /*! + @brief comparison: smaller + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + } + + // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 + if (m_object == nullptr) + { + // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false + return false; + } + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. + */ + bool operator<=(const iter_impl& other) const + { + return !other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized. + */ + bool operator>(const iter_impl& other) const + { + return !operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized. + */ + bool operator>=(const iter_impl& other) const + { + return !operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + const typename object_t::key_type& key() const + { + JSON_ASSERT(m_object != nullptr); + + if (JSON_HEDLEY_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + JSON_PRIVATE_UNLESS_TESTED: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it {}; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // conditional, is_same + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief Default base class of the @ref basic_json class. + +So that the correct implementations of the copy / move ctors / assign operators +of @ref basic_json do not require complex case distinctions +(no base class / custom base class used as customization point), +@ref basic_json always has a base class. +By default, this class is used because it is empty and thus has no effect +on the behavior of @ref basic_json. +*/ +struct json_default_base {}; + +template +using json_base_class = typename std::conditional < + std::is_same::value, + json_default_base, + T + >::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // all_of +#include // isdigit +#include // errno, ERANGE +#include // strtoull +#ifndef JSON_NO_IO + #include // ostream +#endif // JSON_NO_IO +#include // max +#include // accumulate +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document +/// @sa https://json.nlohmann.me/api/json_pointer/ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + template + friend class json_pointer; + + template + struct string_t_helper + { + using type = T; + }; + + NLOHMANN_BASIC_JSON_TPL_DECLARATION + struct string_t_helper + { + using type = StringType; + }; + + public: + // for backwards compatibility accept BasicJsonType + using string_t = typename string_t_helper::type; + + /// @brief create JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ + explicit json_pointer(const string_t& s = "") + : reference_tokens(split(s)) + {} + + /// @brief return a string representation of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ + string_t to_string() const + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + string_t{}, + [](const string_t& a, const string_t& b) + { + return detail::concat(a, '/', detail::escape(b)); + }); + } + + /// @brief return a string representation of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) + operator string_t() const + { + return to_string(); + } + +#ifndef JSON_NO_IO + /// @brief write string representation of the JSON pointer to stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ + friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) + { + o << ptr.to_string(); + return o; + } +#endif + + /// @brief append another JSON pointer at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), + ptr.reference_tokens.begin(), + ptr.reference_tokens.end()); + return *this; + } + + /// @brief append an unescaped reference token at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(string_t token) + { + push_back(std::move(token)); + return *this; + } + + /// @brief append an array index at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(std::size_t array_idx) + { + return *this /= std::to_string(array_idx); + } + + /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, + const json_pointer& rhs) + { + return json_pointer(lhs) /= rhs; + } + + /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) + { + return json_pointer(lhs) /= std::move(token); + } + + /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) + { + return json_pointer(lhs) /= array_idx; + } + + /// @brief returns the parent of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ + json_pointer parent_pointer() const + { + if (empty()) + { + return *this; + } + + json_pointer res = *this; + res.pop_back(); + return res; + } + + /// @brief remove last reference token + /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ + void pop_back() + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + reference_tokens.pop_back(); + } + + /// @brief return last reference token + /// @sa https://json.nlohmann.me/api/json_pointer/back/ + const string_t& back() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + return reference_tokens.back(); + } + + /// @brief append an unescaped token at the end of the reference pointer + /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ + void push_back(const string_t& token) + { + reference_tokens.push_back(token); + } + + /// @brief append an unescaped token at the end of the reference pointer + /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ + void push_back(string_t&& token) + { + reference_tokens.push_back(std::move(token)); + } + + /// @brief return whether pointer points to the root document + /// @sa https://json.nlohmann.me/api/json_pointer/empty/ + bool empty() const noexcept + { + return reference_tokens.empty(); + } + + private: + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit + @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type + */ + template + static typename BasicJsonType::size_type array_index(const string_t& s) + { + using size_type = typename BasicJsonType::size_type; + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); + } + + const char* p = s.c_str(); + char* p_end = nullptr; // NOLINT(misc-const-correctness) + errno = 0; // strtoull doesn't reset errno + const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) + if (p == p_end // invalid input or empty string + || errno == ERANGE // out of range + || JSON_HEDLEY_UNLIKELY(static_cast(p_end - p) != s.size())) // incomplete read + { + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); + } + + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) + { + JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE + } + + return static_cast(res); + } + + JSON_PRIVATE_UNLESS_TESTED: + json_pointer top() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + private: + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + template + BasicJsonType& get_and_create(BasicJsonType& j) const + { + auto* result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->type()) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + result = &result->operator[](array_index(reference_token)); + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->is_null()) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const unsigned char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums || reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_data.m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](array_index(reference_token)); + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, detail::concat( + "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + ") is out of range"), ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); + } + + // use unchecked array access + ptr = &ptr->operator[](array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, detail::concat( + "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + ") is out of range"), ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + */ + template + bool contains(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + if (!ptr->contains(reference_token)) + { + // we did not find the key in the object + return false; + } + + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) + { + // invalid char + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) + { + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) + { + // first char should be between '1' and '9' + return false; + } + for (std::size_t i = 1; i < reference_token.size(); i++) + { + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) + { + // other char should be between '0' and '9' + return false; + } + } + } + + const auto idx = array_index(reference_token); + if (idx >= ptr->size()) + { + // index out of range + return false; + } + + ptr = &ptr->operator[](idx); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // we do not expect primitive values if there is still a + // reference token to process + return false; + } + } + } + + // no reference token left means we found a primitive value + return true; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const string_t& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == 0 (if slash == string_t::npos) + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == string_t::npos) + start = (slash == string_t::npos) ? 0 : slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != string_t::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + JSON_ASSERT(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); + } + } + + // finally, store the reference token + detail::unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + private: + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + template + static void flatten(const string_t& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.type()) + { + case detail::value_t::array: + { + if (value.m_data.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) + { + flatten(detail::concat(reference_string, '/', std::to_string(i)), + value.m_data.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_data.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_data.m_value.object) + { + flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); + } + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + template + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_data.m_value.object) + { + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + // can't use conversion operator because of ambiguity + json_pointer convert() const& + { + json_pointer result; + result.reference_tokens = reference_tokens; + return result; + } + + json_pointer convert()&& + { + json_pointer result; + result.reference_tokens = std::move(reference_tokens); + return result; + } + + public: +#if JSON_HAS_THREE_WAY_COMPARISON + /// @brief compares two JSON pointers for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + bool operator==(const json_pointer& rhs) const noexcept + { + return reference_tokens == rhs.reference_tokens; + } + + /// @brief compares JSON pointer and string for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) + bool operator==(const string_t& rhs) const + { + return *this == json_pointer(rhs); + } + + /// @brief 3-way compares two JSON pointers + template + std::strong_ordering operator<=>(const json_pointer& rhs) const noexcept // *NOPAD* + { + return reference_tokens <=> rhs.reference_tokens; // *NOPAD* + } +#else + /// @brief compares two JSON pointers for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const json_pointer& lhs, + const json_pointer& rhs) noexcept; + + /// @brief compares JSON pointer and string for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const json_pointer& lhs, + const StringType& rhs); + + /// @brief compares string and JSON pointer for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const StringType& lhs, + const json_pointer& rhs); + + /// @brief compares two JSON pointers for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const json_pointer& lhs, + const json_pointer& rhs) noexcept; + + /// @brief compares JSON pointer and string for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const json_pointer& lhs, + const StringType& rhs); + + /// @brief compares string and JSON pointer for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const StringType& lhs, + const json_pointer& rhs); + + /// @brief compares two JSON pointer for less-than + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator<(const json_pointer& lhs, + const json_pointer& rhs) noexcept; +#endif + + private: + /// the reference tokens + std::vector reference_tokens; +}; + +#if !JSON_HAS_THREE_WAY_COMPARISON +// functions cannot be defined inside class due to ODR violations +template +inline bool operator==(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return lhs.reference_tokens == rhs.reference_tokens; +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) +inline bool operator==(const json_pointer& lhs, + const StringType& rhs) +{ + return lhs == json_pointer(rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) +inline bool operator==(const StringType& lhs, + const json_pointer& rhs) +{ + return json_pointer(lhs) == rhs; +} + +template +inline bool operator!=(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return !(lhs == rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) +inline bool operator!=(const json_pointer& lhs, + const StringType& rhs) +{ + return !(lhs == rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) +inline bool operator!=(const StringType& lhs, + const json_pointer& rhs) +{ + return !(lhs == rhs); +} + +template +inline bool operator<(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return lhs.reference_tokens < rhs.reference_tokens; +} +#endif + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include +#include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)) + {} + + json_ref(const value_type& value) + : value_ref(&value) + {} + + json_ref(std::initializer_list init) + : owned_value(init) + {} + + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...) + {} + + // class should be movable only + json_ref(json_ref&&) noexcept = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; + + value_type moved_or_copied() const + { + if (value_ref == nullptr) + { + return std::move(owned_value); + } + return *value_ref; + } + + value_type const& operator*() const + { + return value_ref ? *value_ref : owned_value; + } + + value_type const* operator->() const + { + return &** this; + } + + private: + mutable value_type owned_value = nullptr; + value_type const* value_ref = nullptr; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // reverse +#include // array +#include // map +#include // isnan, isinf +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // copy +#include // size_t +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_string +#include // vector + +#ifndef JSON_NO_IO + #include // streamsize + #include // basic_ostream +#endif // JSON_NO_IO + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; + + output_adapter_protocol() = default; + output_adapter_protocol(const output_adapter_protocol&) = default; + output_adapter_protocol(output_adapter_protocol&&) noexcept = default; + output_adapter_protocol& operator=(const output_adapter_protocol&) = default; + output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template> +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) noexcept + : v(vec) + {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + v.insert(v.end(), s, s + length); + } + + private: + std::vector& v; +}; + +#ifndef JSON_NO_IO +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) noexcept + : stream(s) + {} + + void write_character(CharType c) override + { + stream.put(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; +#endif // JSON_NO_IO + +/// output adapter for basic_string +template> +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(StringType& s) noexcept + : str(s) + {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + StringType& str; +}; + +template> +class output_adapter +{ + public: + template> + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + +#ifndef JSON_NO_IO + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} +#endif // JSON_NO_IO + + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// how to encode BJData +enum class bjdata_version_t +{ + draft2, + draft3, +}; + +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(std::move(adapter)) + { + JSON_ASSERT(oa); + } + + /*! + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + void write_bson(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + { + write_bson_object(*j.m_data.m_value.object); + break; + } + + case value_t::null: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); + } + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(to_char_type(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_data.m_value.boolean + ? to_char_type(0xF5) + : to_char_type(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_data.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_data.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_data.m_value.number_integer; + if (j.m_data.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(to_char_type(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_data.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_data.m_value.number_unsigned)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_data.m_value.number_unsigned)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_data.m_value.number_unsigned)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_data.m_value.number_unsigned)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_data.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: + { + if (std::isnan(j.m_data.m_value.number_float)) + { + // NaN is 0xf97e00 in CBOR + oa->write_character(to_char_type(0xF9)); + oa->write_character(to_char_type(0x7E)); + oa->write_character(to_char_type(0x00)); + } + else if (std::isinf(j.m_data.m_value.number_float)) + { + // Infinity is 0xf97c00, -Infinity is 0xf9fc00 + oa->write_character(to_char_type(0xf9)); + oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); + oa->write_character(to_char_type(0x00)); + } + else + { + write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor); + } + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_data.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x78)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x79)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_data.m_value.string->c_str()), + j.m_data.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_data.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x98)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x99)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_data.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::binary: + { + if (j.m_data.m_value.binary->has_subtype()) + { + if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd8)); + write_number(static_cast(j.m_data.m_value.binary->subtype())); + } + else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd9)); + write_number(static_cast(j.m_data.m_value.binary->subtype())); + } + else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xda)); + write_number(static_cast(j.m_data.m_value.binary->subtype())); + } + else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xdb)); + write_number(static_cast(j.m_data.m_value.binary->subtype())); + } + } + + // step 1: write control byte and the binary array size + const auto N = j.m_data.m_value.binary->size(); + if (N <= 0x17) + { + write_number(static_cast(0x40 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x58)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x59)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + oa->write_characters( + reinterpret_cast(j.m_data.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_data.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB8)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_data.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + case value_t::discarded: + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(to_char_type(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_data.m_value.boolean + ? to_char_type(0xC3) + : to_char_type(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_data.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_data.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + } + else + { + if (j.m_data.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(to_char_type(0xD0)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(to_char_type(0xD1)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(to_char_type(0xD2)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(to_char_type(0xD3)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_data.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_data.m_value.number_integer)); + } + break; + } + + case value_t::number_float: + { + write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_data.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 8 + oa->write_character(to_char_type(0xD9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 16 + oa->write_character(to_char_type(0xDA)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 32 + oa->write_character(to_char_type(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_data.m_value.string->c_str()), + j.m_data.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_data.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 16 + oa->write_character(to_char_type(0xDC)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 32 + oa->write_character(to_char_type(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_data.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::binary: + { + // step 0: determine if the binary type has a set subtype to + // determine whether to use the ext or fixext types + const bool use_ext = j.m_data.m_value.binary->has_subtype(); + + // step 1: write control byte and the byte string length + const auto N = j.m_data.m_value.binary->size(); + if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type{}; + bool fixed = true; + if (use_ext) + { + switch (N) + { + case 1: + output_type = 0xD4; // fixext 1 + break; + case 2: + output_type = 0xD5; // fixext 2 + break; + case 4: + output_type = 0xD6; // fixext 4 + break; + case 8: + output_type = 0xD7; // fixext 8 + break; + case 16: + output_type = 0xD8; // fixext 16 + break; + default: + output_type = 0xC7; // ext 8 + fixed = false; + break; + } + + } + else + { + output_type = 0xC4; // bin 8 + fixed = false; + } + + oa->write_character(to_char_type(output_type)); + if (!fixed) + { + write_number(static_cast(N)); + } + } + else if (N <= (std::numeric_limits::max)()) + { + const std::uint8_t output_type = use_ext + ? 0xC8 // ext 16 + : 0xC5; // bin 16 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + const std::uint8_t output_type = use_ext + ? 0xC9 // ext 32 + : 0xC6; // bin 32 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + + // step 1.5: if this is an ext type, write the subtype + if (use_ext) + { + write_number(static_cast(j.m_data.m_value.binary->subtype())); + } + + // step 2: write the byte string + oa->write_characters( + reinterpret_cast(j.m_data.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_data.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 16 + oa->write_character(to_char_type(0xDE)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 32 + oa->write_character(to_char_type(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_data.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + case value_t::discarded: + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + @param[in] use_bjdata whether write in BJData format, default is false + @param[in] bjdata_version which BJData version to use, default is draft2 + */ + void write_ubjson(const BasicJsonType& j, const bool use_count, + const bool use_type, const bool add_prefix = true, + const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2) + { + const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3; + + switch (j.type()) + { + case value_t::null: + { + if (add_prefix) + { + oa->write_character(to_char_type('Z')); + } + break; + } + + case value_t::boolean: + { + if (add_prefix) + { + oa->write_character(j.m_data.m_value.boolean + ? to_char_type('T') + : to_char_type('F')); + } + break; + } + + case value_t::number_integer: + { + write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata); + break; + } + + case value_t::number_unsigned: + { + write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata); + break; + } + + case value_t::number_float: + { + write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata); + break; + } + + case value_t::string: + { + if (add_prefix) + { + oa->write_character(to_char_type('S')); + } + write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata); + oa->write_characters( + reinterpret_cast(j.m_data.m_value.string->c_str()), + j.m_data.m_value.string->size()); + break; + } + + case value_t::array: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + bool prefix_required = true; + if (use_type && !j.m_data.m_value.array->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix, use_bjdata](const BasicJsonType & v) + { + return ubjson_prefix(v, use_bjdata) == first_prefix; + }); + + std::vector bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type + + if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata); + } + + for (const auto& el : *j.m_data.m_value.array) + { + write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version); + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::binary: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty())) + { + JSON_ASSERT(use_count); + oa->write_character(to_char_type('$')); + oa->write_character(bjdata_draft3 ? 'B' : 'U'); + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata); + } + + if (use_type) + { + oa->write_characters( + reinterpret_cast(j.m_data.m_value.binary->data()), + j.m_data.m_value.binary->size()); + } + else + { + for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i) + { + oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U')); + oa->write_character(j.m_data.m_value.binary->data()[i]); + } + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::object: + { + if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end()) + { + if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) + { + break; + } + } + + if (add_prefix) + { + oa->write_character(to_char_type('{')); + } + + bool prefix_required = true; + if (use_type && !j.m_data.m_value.object->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix, use_bjdata](const BasicJsonType & v) + { + return ubjson_prefix(v, use_bjdata) == first_prefix; + }); + + std::vector bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type + + if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata); + } + + for (const auto& el : *j.m_data.m_value.object) + { + write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata); + oa->write_characters( + reinterpret_cast(el.first.c_str()), + el.first.size()); + write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version); + } + + if (!use_count) + { + oa->write_character(to_char_type('}')); + } + + break; + } + + case value_t::discarded: + default: + break; + } + } + + private: + ////////// + // BSON // + ////////// + + /*! + @return The size of a BSON document entry header, including the id marker + and the entry name size (and its null-terminator). + */ + static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) + { + const auto it = name.find(static_cast(0)); + if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) + { + JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); + static_cast(j); + } + + return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; + } + + /*! + @brief Writes the given @a element_type and @a name to the output adapter + */ + void write_bson_entry_header(const string_t& name, + const std::uint8_t element_type) + { + oa->write_character(to_char_type(element_type)); // boolean + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + } + + /*! + @brief Writes a BSON element with key @a name and boolean value @a value + */ + void write_bson_boolean(const string_t& name, + const bool value) + { + write_bson_entry_header(name, 0x08); + oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and double value @a value + */ + void write_bson_double(const string_t& name, + const double value) + { + write_bson_entry_header(name, 0x01); + write_number(value, true); + } + + /*! + @return The size of the BSON-encoded string in @a value + */ + static std::size_t calc_bson_string_size(const string_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and string value @a value + */ + void write_bson_string(const string_t& name, + const string_t& value) + { + write_bson_entry_header(name, 0x02); + + write_number(static_cast(value.size() + 1ul), true); + oa->write_characters( + reinterpret_cast(value.c_str()), + value.size() + 1); + } + + /*! + @brief Writes a BSON element with key @a name and null value + */ + void write_bson_null(const string_t& name) + { + write_bson_entry_header(name, 0x0A); + } + + /*! + @return The size of the BSON-encoded integer @a value + */ + static std::size_t calc_bson_integer_size(const std::int64_t value) + { + return (std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)() + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and integer @a value + */ + void write_bson_integer(const string_t& name, + const std::int64_t value) + { + if ((std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)()) + { + write_bson_entry_header(name, 0x10); // int32 + write_number(static_cast(value), true); + } + else + { + write_bson_entry_header(name, 0x12); // int64 + write_number(static_cast(value), true); + } + } + + /*! + @return The size of the BSON-encoded unsigned integer in @a j + */ + static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept + { + return (value <= static_cast((std::numeric_limits::max)())) + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and unsigned @a value + */ + void write_bson_unsigned(const string_t& name, + const BasicJsonType& j) + { + if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x10 /* int32 */); + write_number(static_cast(j.m_data.m_value.number_unsigned), true); + } + else if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x12 /* int64 */); + write_number(static_cast(j.m_data.m_value.number_unsigned), true); + } + else + { + write_bson_entry_header(name, 0x11 /* uint64 */); + write_number(static_cast(j.m_data.m_value.number_unsigned), true); + } + } + + /*! + @brief Writes a BSON element with key @a name and object @a value + */ + void write_bson_object_entry(const string_t& name, + const typename BasicJsonType::object_t& value) + { + write_bson_entry_header(name, 0x03); // object + write_bson_object(value); + } + + /*! + @return The size of the BSON-encoded array @a value + */ + static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) + { + std::size_t array_index = 0ul; + + const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) + { + return result + calc_bson_element_size(std::to_string(array_index++), el); + }); + + return sizeof(std::int32_t) + embedded_document_size + 1ul; + } + + /*! + @return The size of the BSON-encoded binary array @a value + */ + static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and array @a value + */ + void write_bson_array(const string_t& name, + const typename BasicJsonType::array_t& value) + { + write_bson_entry_header(name, 0x04); // array + write_number(static_cast(calc_bson_array_size(value)), true); + + std::size_t array_index = 0ul; + + for (const auto& el : value) + { + write_bson_element(std::to_string(array_index++), el); + } + + oa->write_character(to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and binary value @a value + */ + void write_bson_binary(const string_t& name, + const binary_t& value) + { + write_bson_entry_header(name, 0x05); + + write_number(static_cast(value.size()), true); + write_number(value.has_subtype() ? static_cast(value.subtype()) : static_cast(0x00)); + + oa->write_characters(reinterpret_cast(value.data()), value.size()); + } + + /*! + @brief Calculates the size necessary to serialize the JSON value @a j with its @a name + @return The calculated size for the BSON document entry for @a j with the given @a name. + */ + static std::size_t calc_bson_element_size(const string_t& name, + const BasicJsonType& j) + { + const auto header_size = calc_bson_entry_header_size(name, j); + switch (j.type()) + { + case value_t::object: + return header_size + calc_bson_object_size(*j.m_data.m_value.object); + + case value_t::array: + return header_size + calc_bson_array_size(*j.m_data.m_value.array); + + case value_t::binary: + return header_size + calc_bson_binary_size(*j.m_data.m_value.binary); + + case value_t::boolean: + return header_size + 1ul; + + case value_t::number_float: + return header_size + 8ul; + + case value_t::number_integer: + return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer); + + case value_t::number_unsigned: + return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned); + + case value_t::string: + return header_size + calc_bson_string_size(*j.m_data.m_value.string); + + case value_t::null: + return header_size + 0ul; + + // LCOV_EXCL_START + case value_t::discarded: + default: + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) + return 0ul; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Serializes the JSON value @a j to BSON and associates it with the + key @a name. + @param name The name to associate with the JSON entity @a j within the + current BSON document + */ + void write_bson_element(const string_t& name, + const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + return write_bson_object_entry(name, *j.m_data.m_value.object); + + case value_t::array: + return write_bson_array(name, *j.m_data.m_value.array); + + case value_t::binary: + return write_bson_binary(name, *j.m_data.m_value.binary); + + case value_t::boolean: + return write_bson_boolean(name, j.m_data.m_value.boolean); + + case value_t::number_float: + return write_bson_double(name, j.m_data.m_value.number_float); + + case value_t::number_integer: + return write_bson_integer(name, j.m_data.m_value.number_integer); + + case value_t::number_unsigned: + return write_bson_unsigned(name, j); + + case value_t::string: + return write_bson_string(name, *j.m_data.m_value.string); + + case value_t::null: + return write_bson_null(name); + + // LCOV_EXCL_START + case value_t::discarded: + default: + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) + return; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Calculates the size of the BSON serialization of the given + JSON-object @a j. + @param[in] value JSON value to serialize + @pre value.type() == value_t::object + */ + static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) + { + const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast(0), + [](size_t result, const typename BasicJsonType::object_t::value_type & el) + { + return result += calc_bson_element_size(el.first, el.second); + }); + + return sizeof(std::int32_t) + document_size + 1ul; + } + + /*! + @param[in] value JSON value to serialize + @pre value.type() == value_t::object + */ + void write_bson_object(const typename BasicJsonType::object_t& value) + { + write_number(static_cast(calc_bson_object_size(value)), true); + + for (const auto& el : value) + { + write_bson_element(el.first, el.second); + } + + oa->write_character(to_char_type(0x00)); + } + + ////////// + // CBOR // + ////////// + + static constexpr CharType get_cbor_float_prefix(float /*unused*/) + { + return to_char_type(0xFA); // Single-Precision Float + } + + static constexpr CharType get_cbor_float_prefix(double /*unused*/) + { + return to_char_type(0xFB); // Double-Precision Float + } + + ///////////// + // MsgPack // + ///////////// + + static constexpr CharType get_msgpack_float_prefix(float /*unused*/) + { + return to_char_type(0xCA); // float 32 + } + + static constexpr CharType get_msgpack_float_prefix(double /*unused*/) + { + return to_char_type(0xCB); // float 64 + } + + //////////// + // UBJSON // + //////////// + + // UBJSON: write number (floating point) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix, + const bool use_bjdata) + { + if (add_prefix) + { + oa->write_character(get_ubjson_float_prefix(n)); + } + write_number(n, use_bjdata); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix, + const bool use_bjdata) + { + if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n), use_bjdata); + } + else if (n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n), use_bjdata); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n), use_bjdata); + } + else if (use_bjdata && n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('u')); // uint16 - bjdata only + } + write_number(static_cast(n), use_bjdata); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n), use_bjdata); + } + else if (use_bjdata && n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('m')); // uint32 - bjdata only + } + write_number(static_cast(n), use_bjdata); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n), use_bjdata); + } + else if (use_bjdata && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('M')); // uint64 - bjdata only + } + write_number(static_cast(n), use_bjdata); + } + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true, use_bjdata); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + } + + // UBJSON: write number (signed integer) + template < typename NumberType, typename std::enable_if < + std::is_signed::value&& + !std::is_floating_point::value, int >::type = 0 > + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix, + const bool use_bjdata) + { + if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n), use_bjdata); + } + else if (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n), use_bjdata); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n), use_bjdata); + } + else if (use_bjdata && (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)()))) + { + if (add_prefix) + { + oa->write_character(to_char_type('u')); // uint16 - bjdata only + } + write_number(static_cast(n), use_bjdata); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n), use_bjdata); + } + else if (use_bjdata && (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)()))) + { + if (add_prefix) + { + oa->write_character(to_char_type('m')); // uint32 - bjdata only + } + write_number(static_cast(n), use_bjdata); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n), use_bjdata); + } + // LCOV_EXCL_START + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true, use_bjdata); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + // LCOV_EXCL_STOP + } + + /*! + @brief determine the type prefix of container values + */ + CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept + { + switch (j.type()) + { + case value_t::null: + return 'Z'; + + case value_t::boolean: + return j.m_data.m_value.boolean ? 'T' : 'F'; + + case value_t::number_integer: + { + if ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'i'; + } + if ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'U'; + } + if ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'I'; + } + if (use_bjdata && ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)())) + { + return 'u'; + } + if ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'l'; + } + if (use_bjdata && ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)())) + { + return 'm'; + } + if ((std::numeric_limits::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_unsigned: + { + if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'i'; + } + if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'U'; + } + if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'I'; + } + if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'u'; + } + if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'l'; + } + if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'm'; + } + if (j.m_data.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'L'; + } + if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'M'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_float: + return get_ubjson_float_prefix(j.m_data.m_value.number_float); + + case value_t::string: + return 'S'; + + case value_t::array: // fallthrough + case value_t::binary: + return '['; + + case value_t::object: + return '{'; + + case value_t::discarded: + default: // discarded values + return 'N'; + } + } + + static constexpr CharType get_ubjson_float_prefix(float /*unused*/) + { + return 'd'; // float 32 + } + + static constexpr CharType get_ubjson_float_prefix(double /*unused*/) + { + return 'D'; // float 64 + } + + /*! + @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid + */ + bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type, const bjdata_version_t bjdata_version) + { + std::map bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, + {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, + {"char", 'C'}, {"byte", 'B'} + }; + + string_t key = "_ArrayType_"; + auto it = bjdtype.find(static_cast(value.at(key))); + if (it == bjdtype.end()) + { + return true; + } + CharType dtype = it->second; + + key = "_ArraySize_"; + std::size_t len = (value.at(key).empty() ? 0 : 1); + for (const auto& el : value.at(key)) + { + len *= static_cast(el.m_data.m_value.number_unsigned); + } + + key = "_ArrayData_"; + if (value.at(key).size() != len) + { + return true; + } + + oa->write_character('['); + oa->write_character('$'); + oa->write_character(dtype); + oa->write_character('#'); + + key = "_ArraySize_"; + write_ubjson(value.at(key), use_count, use_type, true, true, bjdata_version); + + key = "_ArrayData_"; + if (dtype == 'U' || dtype == 'C' || dtype == 'B') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_unsigned), true); + } + } + else if (dtype == 'i') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_integer), true); + } + } + else if (dtype == 'u') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_unsigned), true); + } + } + else if (dtype == 'I') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_integer), true); + } + } + else if (dtype == 'm') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_unsigned), true); + } + } + else if (dtype == 'l') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_integer), true); + } + } + else if (dtype == 'M') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_unsigned), true); + } + } + else if (dtype == 'L') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_integer), true); + } + } + else if (dtype == 'd') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_float), true); + } + } + else if (dtype == 'D') + { + for (const auto& el : value.at(key)) + { + write_number(static_cast(el.m_data.m_value.number_float), true); + } + } + return false; + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /* + @brief write a number to output input + @param[in] n number of type @a NumberType + @param[in] OutputIsLittleEndian Set to true if output data is + required to be little endian + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianness, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + On the other hand, BSON and BJData use little endian and should reorder + on big endian systems. + */ + template + void write_number(const NumberType n, const bool OutputIsLittleEndian = false) + { + // step 1: write number to array of length NumberType + std::array vec{}; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian != OutputIsLittleEndian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + void write_compact_float(const number_float_t n, detail::input_format_t format) + { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && + static_cast(n) <= static_cast((std::numeric_limits::max)()) && + static_cast(static_cast(n)) == static_cast(n)) + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(static_cast(n)) + : get_msgpack_float_prefix(static_cast(n))); + write_number(static_cast(n)); + } + else + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(n) + : get_msgpack_float_prefix(n)); + write_number(n); + } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } + + public: + // The following to_char_type functions are implement the conversion + // between uint8_t and CharType. In case CharType is not unsigned, + // such a conversion is required to allow values greater than 128. + // See for a discussion. + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_signed::value > * = nullptr > + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return *reinterpret_cast(&x); + } + + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > + static CharType to_char_type(std::uint8_t x) noexcept + { + static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); + static_assert(std::is_trivial::value, "CharType must be trivial"); + CharType result; + std::memcpy(&result, &x, sizeof(x)); + return result; + } + + template::value>* = nullptr> + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return x; + } + + template < typename InputCharType, typename C = CharType, + enable_if_t < + std::is_signed::value && + std::is_signed::value && + std::is_same::type>::value + > * = nullptr > + static constexpr CharType to_char_type(InputCharType x) noexcept + { + return x; + } + + private: + /// whether we can assume little endianness + const bool is_little_endian = little_endianness(); + + /// the output + output_adapter_t oa = nullptr; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2008 - 2009 Björn Hoehrmann +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // numeric_limits +#include // string, char_traits +#include // setfill, setw +#include // is_same +#include // move + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2009 Florian Loitsch +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove +#include // numeric_limits +#include // conditional + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + std::uint64_t f = 0; + int e = 0; + + constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); + + return {x.f - y.f, x.e}; + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; + const std::uint64_t u_hi = x.f >> 32u; + const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; + const std::uint64_t v_hi = y.f >> 32u; + + const std::uint64_t p0 = u_lo * v_lo; + const std::uint64_t p1 = u_lo * v_hi; + const std::uint64_t p2 = u_hi * v_lo; + const std::uint64_t p3 = u_hi * v_hi; + + const std::uint64_t p0_hi = p0 >> 32u; + const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; + const std::uint64_t p1_hi = p1 >> 32u; + const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; + const std::uint64_t p2_hi = p2 >> 32u; + + std::uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up + + const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); + + return {h, x.e + y.e + 64}; + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + JSON_ASSERT(x.f != 0); + + while ((x.f >> 63u) == 0) + { + x.f <<= 1u; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); + + return {x.f << delta, target_exponent}; + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional::type; + + const auto bits = static_cast(reinterpret_bits(value)); + const std::uint64_t E = bits >> (kPrecision - 1); + const std::uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = E == 0; + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = F == 0 && E > 1; + const diyfp m_plus = diyfp((2 * v.f) + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp((4 * v.f) - 1, v.e - 2) // (B) + : diyfp((2 * v.f) - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + std::uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exact power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr std::array kCachedPowers = + { + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + } + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); + const int f = kAlpha - e - 1; + const int k = ((f * 78913) / (1 << 18)) + static_cast(f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); + + const cached_power cached = kCachedPowers[static_cast(index)]; + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + if (n >= 100000) + { + pow10 = 100000; + return 6; + } + if (n >= 10000) + { + pow10 = 10000; + return 5; + } + if (n >= 1000) + { + pow10 = 1000; + return 4; + } + if (n >= 100) + { + pow10 = 100; + return 3; + } + if (n >= 10) + { + pow10 = 10; + return 2; + } + + pow10 = 1; + return 1; +} + +inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, + std::uint64_t rest, std::uint64_t ten_k) +{ + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) + { + JSON_ASSERT(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); + + std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); + + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + JSON_ASSERT(p1 > 0); + + std::uint32_t pow10{}; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + JSON_ASSERT(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); + p2 *= 10; + const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const std::uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +JSON_HEDLEY_NON_NULL(1) +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +JSON_HEDLEY_NON_NULL(1) +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* append_exponent(char* buf, int e) +{ + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + auto k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + (k / 10)); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + (k / 100)); + k %= 100; + *buf++ = static_cast('0' + (k / 10)); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n && n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n) - static_cast(k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (static_cast(n) + 2); + } + + if (0 < n && n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + JSON_ASSERT(k > n); + + std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); + buf[n] = '.'; + return buf + (static_cast(k) + 1U); + } + + if (min_exp < n && n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2U + static_cast(-n) + static_cast(k)); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k) - 1); + buf[1] = '.'; + buf += 1 + static_cast(k); + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +JSON_HEDLEY_NON_NULL(1, 2) +JSON_HEDLEY_RETURNS_NON_NULL +char* to_chars(char* first, const char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + JSON_ASSERT(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + JSON_ASSERT(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////// +// serialization // +/////////////////// + +/// how to treat decoding errors +enum class error_handler_t +{ + strict, ///< throw a type_error exception in case of invalid UTF-8 + replace, ///< replace invalid UTF-8 sequences with U+FFFD + ignore ///< ignore invalid UTF-8 sequences +}; + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using binary_char_t = typename BasicJsonType::binary_t::value_type; + static constexpr std::uint8_t UTF8_ACCEPT = 0; + static constexpr std::uint8_t UTF8_REJECT = 1; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + @param[in] error_handler_ how to react on decoding errors + */ + serializer(output_adapter_t s, const char ichar, + error_handler_t error_handler_ = error_handler_t::strict) + : o(std::move(s)) + , loc(std::localeconv()) + , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) + , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) + , indent_char(ichar) + , indent_string(512, indent_char) + , error_handler(error_handler_) + {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + serializer(serializer&&) = delete; + serializer& operator=(serializer&&) = delete; + ~serializer() = default; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + - binary values are serialized as objects containing the subtype and the + byte array + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, + const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_data.m_type) + { + case value_t::object: + { + if (val.m_data.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_data.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(i != val.m_data.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_data.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(i != val.m_data.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_data.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_data.m_value.array->cbegin(); + i != val.m_data.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(!val.m_data.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_data.m_value.array->cbegin(); + i != val.m_data.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(!val.m_data.m_value.array->empty()); + dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_data.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::binary: + { + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"bytes\": [", 10); + + if (!val.m_data.m_value.binary->empty()) + { + for (auto i = val.m_data.m_value.binary->cbegin(); + i != val.m_data.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_characters(", ", 2); + } + dump_integer(val.m_data.m_value.binary->back()); + } + + o->write_characters("],\n", 3); + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"subtype\": ", 11); + if (val.m_data.m_value.binary->has_subtype()) + { + dump_integer(val.m_data.m_value.binary->subtype()); + } + else + { + o->write_characters("null", 4); + } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_characters("{\"bytes\":[", 10); + + if (!val.m_data.m_value.binary->empty()) + { + for (auto i = val.m_data.m_value.binary->cbegin(); + i != val.m_data.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_character(','); + } + dump_integer(val.m_data.m_value.binary->back()); + } + + o->write_characters("],\"subtype\":", 12); + if (val.m_data.m_value.binary->has_subtype()) + { + dump_integer(val.m_data.m_value.binary->subtype()); + o->write_character('}'); + } + else + { + o->write_characters("null}", 5); + } + } + return; + } + + case value_t::boolean: + { + if (val.m_data.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_data.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_data.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_data.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + } + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) + { + std::uint32_t codepoint{}; + std::uint8_t state = UTF8_ACCEPT; + std::size_t bytes = 0; // number of bytes written to string_buffer + + // number of bytes written at the point of the last valid byte + std::size_t bytes_after_last_accept = 0; + std::size_t undumped_chars = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto byte = static_cast(s[i]); + + switch (decode(state, codepoint, byte)) + { + case UTF8_ACCEPT: // decode found a new code point + { + switch (codepoint) + { + case 0x08: // backspace + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'b'; + break; + } + + case 0x09: // horizontal tab + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 't'; + break; + } + + case 0x0A: // newline + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'n'; + break; + } + + case 0x0C: // formfeed + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'f'; + break; + } + + case 0x0D: // carriage return + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'r'; + break; + } + + case 0x22: // quotation mark + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\"'; + break; + } + + case 0x5C: // reverse solidus + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\\'; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) + { + if (codepoint <= 0xFFFF) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint))); + bytes += 6; + } + else + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0u + (codepoint >> 10u)), + static_cast(0xDC00u + (codepoint & 0x3FFu)))); + bytes += 12; + } + } + else + { + // copy byte to buffer (all previous bytes + // been copied have in default case above) + string_buffer[bytes++] = s[i]; + } + break; + } + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + // remember the byte position of this accept + bytes_after_last_accept = bytes; + undumped_chars = 0; + break; + } + + case UTF8_REJECT: // decode found invalid UTF-8 byte + { + switch (error_handler) + { + case error_handler_t::strict: + { + JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr)); + } + + case error_handler_t::ignore: + case error_handler_t::replace: + { + // in case we saw this character the first time, we + // would like to read it again, because the byte + // may be OK for itself, but just not OK for the + // previous sequence + if (undumped_chars > 0) + { + --i; + } + + // reset length buffer to the last accepted index; + // thus removing/ignoring the invalid characters + bytes = bytes_after_last_accept; + + if (error_handler == error_handler_t::replace) + { + // add a replacement character + if (ensure_ascii) + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'u'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'd'; + } + else + { + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xEF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + bytes_after_last_accept = bytes; + } + + undumped_chars = 0; + + // continue processing the string + state = UTF8_ACCEPT; + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + break; + } + + default: // decode found yet incomplete multi-byte code point + { + if (!ensure_ascii) + { + // code point will not be escaped - copy byte to buffer + string_buffer[bytes++] = s[i]; + } + ++undumped_chars; + break; + } + } + } + + // we finished processing the string + if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) + { + // write buffer + if (bytes > 0) + { + o->write_characters(string_buffer.data(), bytes); + } + } + else + { + // we finish reading, but do not accept: string was incomplete + switch (error_handler) + { + case error_handler_t::strict: + { + JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast(s.back() | 0))), nullptr)); + } + + case error_handler_t::ignore: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + break; + } + + case error_handler_t::replace: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + // add a replacement character + if (ensure_ascii) + { + o->write_characters("\\ufffd", 6); + } + else + { + o->write_characters("\xEF\xBF\xBD", 3); + } + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + } + } + + private: + /*! + @brief count digits + + Count the number of decimal (base 10) digits for an input unsigned integer. + + @param[in] x unsigned integer number to count its digits + @return number of decimal digits + */ + unsigned int count_digits(number_unsigned_t x) noexcept + { + unsigned int n_digits = 1; + for (;;) + { + if (x < 10) + { + return n_digits; + } + if (x < 100) + { + return n_digits + 1; + } + if (x < 1000) + { + return n_digits + 2; + } + if (x < 10000) + { + return n_digits + 3; + } + x = x / 10000u; + n_digits += 4; + } + } + + /*! + * @brief convert a byte to a uppercase hex representation + * @param[in] byte byte to represent + * @return representation ("00".."FF") + */ + static std::string hex_bytes(std::uint8_t byte) + { + std::string result = "FF"; + constexpr const char* nibble_to_hex = "0123456789ABCDEF"; + result[0] = nibble_to_hex[byte / 16]; + result[1] = nibble_to_hex[byte % 16]; + return result; + } + + // templates to avoid warnings about useless casts + template ::value, int> = 0> + bool is_negative_number(NumberType x) + { + return x < 0; + } + + template < typename NumberType, enable_if_t ::value, int > = 0 > + bool is_negative_number(NumberType /*unused*/) + { + return false; + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template < typename NumberType, detail::enable_if_t < + std::is_integral::value || + std::is_same::value || + std::is_same::value || + std::is_same::value, + int > = 0 > + void dump_integer(NumberType x) + { + static constexpr std::array, 100> digits_to_99 + { + { + {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, + {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, + {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, + {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, + {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, + {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, + {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, + {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, + {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, + {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, + } + }; + + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + // use a pointer to fill the buffer + auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) + + number_unsigned_t abs_value; + + unsigned int n_chars{}; + + if (is_negative_number(x)) + { + *buffer_ptr = '-'; + abs_value = remove_sign(static_cast(x)); + + // account one more byte for the minus sign + n_chars = 1 + count_digits(abs_value); + } + else + { + abs_value = static_cast(x); + n_chars = count_digits(abs_value); + } + + // spare 1 byte for '\0' + JSON_ASSERT(n_chars < number_buffer.size() - 1); + + // jump to the end to generate the string from backward, + // so we later avoid reversing the result + buffer_ptr += n_chars; + + // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu + // See: https://www.youtube.com/watch?v=o4-CwDo2zpg + while (abs_value >= 100) + { + const auto digits_index = static_cast((abs_value % 100)); + abs_value /= 100; + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + + if (abs_value >= 10) + { + const auto digits_index = static_cast(abs_value); + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + else + { + *(--buffer_ptr) = static_cast('0' + abs_value); + } + + o->write_characters(number_buffer.data(), n_chars); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (!std::isfinite(x)) + { + o->write_characters("null", 4); + return; + } + + // If number_float_t is an IEEE-754 single or double precision number, + // use the Grisu2 algorithm to produce short numbers which are + // guaranteed to round-trip, using strtof and strtod, resp. + // + // NB: The test below works if == . + static constexpr bool is_ieee_single_or_double + = (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) || + (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024); + + dump_float(x, std::integral_constant()); + } + + void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) + { + auto* begin = number_buffer.data(); + auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + + o->write_characters(begin, static_cast(end - begin)); + } + + void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) + { + // get number of digits for a float -> text -> float round-trip + static constexpr auto d = std::numeric_limits::max_digits10; + + // the actual conversion + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + JSON_ASSERT(len > 0); + // check if buffer was large enough + JSON_ASSERT(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 + const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + JSON_ASSERT((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' && decimal_point != '.') + { + // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if we need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return c == '.' || c == 'e'; + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + JSON_ASSERT(byte < utf8d.size()); + const std::uint8_t type = utf8d[byte]; + + codep = (state != UTF8_ACCEPT) + ? (byte & 0x3fu) | (codep << 6u) + : (0xFFu >> type) & (byte); + + const std::size_t index = 256u + (static_cast(state) * 16u) + static_cast(type); + JSON_ASSERT(index < utf8d.size()); + state = utf8d[index]; + return state; + } + + /* + * Overload to make the compiler happy while it is instantiating + * dump_integer for number_unsigned_t. + * Must never be called. + */ + number_unsigned_t remove_sign(number_unsigned_t x) + { + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return x; // LCOV_EXCL_LINE + } + + /* + * Helper function for dump_integer + * + * This function takes a negative signed integer and returns its absolute + * value as unsigned integer. The plus/minus shuffling is necessary as we can + * not directly remove the sign of an arbitrary signed integer as the + * absolute values of INT_MIN and INT_MAX are usually not the same. See + * #1708 for details. + */ + number_unsigned_t remove_sign(number_integer_t x) noexcept + { + JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); // NOLINT(misc-redundant-expression) + return static_cast(-(x + 1)) + 1; + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// string buffer + std::array string_buffer{{}}; + + /// the indentation character + const char indent_char; + /// the indentation string + string_t indent_string; + + /// error_handler how to react on decoding errors + const error_handler_t error_handler; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // equal_to, less +#include // initializer_list +#include // input_iterator_tag, iterator_traits +#include // allocator +#include // for out_of_range +#include // enable_if, is_convertible +#include // pair +#include // vector + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template , + class Allocator = std::allocator>> + struct ordered_map : std::vector, Allocator> +{ + using key_type = Key; + using mapped_type = T; + using Container = std::vector, Allocator>; + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + using size_type = typename Container::size_type; + using value_type = typename Container::value_type; +#ifdef JSON_HAS_CPP_14 + using key_compare = std::equal_to<>; +#else + using key_compare = std::equal_to; +#endif + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) + ordered_map() noexcept(noexcept(Container())) : Container{} {} + explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} + + std::pair emplace(const key_type& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return {it, false}; + } + } + Container::emplace_back(key, std::forward(t)); + return {std::prev(this->end()), true}; + } + + template::value, int> = 0> + std::pair emplace(KeyType && key, T && t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return {it, false}; + } + } + Container::emplace_back(std::forward(key), std::forward(t)); + return {std::prev(this->end()), true}; + } + + T& operator[](const key_type& key) + { + return emplace(key, T{}).first->second; + } + + template::value, int> = 0> + T & operator[](KeyType && key) + { + return emplace(std::forward(key), T{}).first->second; + } + + const T& operator[](const key_type& key) const + { + return at(key); + } + + template::value, int> = 0> + const T & operator[](KeyType && key) const + { + return at(std::forward(key)); + } + + T& at(const key_type& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + template::value, int> = 0> + T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + const T& at(const key_type& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + template::value, int> = 0> + const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + size_type erase(const key_type& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + template::value, int> = 0> + size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + iterator erase(iterator pos) + { + return erase(pos, std::next(pos)); + } + + iterator erase(iterator first, iterator last) + { + if (first == last) + { + return first; + } + + const auto elements_affected = std::distance(first, last); + const auto offset = std::distance(Container::begin(), first); + + // This is the start situation. We need to delete elements_affected + // elements (3 in this example: e, f, g), and need to return an + // iterator past the last deleted element (h in this example). + // Note that offset is the distance from the start of the vector + // to first. We will need this later. + + // [ a, b, c, d, e, f, g, h, i, j ] + // ^ ^ + // first last + + // Since we cannot move const Keys, we re-construct them in place. + // We start at first and re-construct (viz. copy) the elements from + // the back of the vector. Example for first iteration: + + // ,--------. + // v | destroy e and re-construct with h + // [ a, b, c, d, e, f, g, h, i, j ] + // ^ ^ + // it it + elements_affected + + for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) + { + it->~value_type(); // destroy but keep allocation + new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it + } + + // [ a, b, c, d, h, i, j, h, i, j ] + // ^ ^ + // first last + + // remove the unneeded elements at the end of the vector + Container::resize(this->size() - static_cast(elements_affected)); + + // [ a, b, c, d, h, i, j ] + // ^ ^ + // first last + + // first is now pointing past the last deleted element, but we cannot + // use this iterator, because it may have been invalidated by the + // resize call. Instead, we can return begin() + offset. + return Container::begin() + offset; + } + + size_type count(const key_type& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return 1; + } + } + return 0; + } + + template::value, int> = 0> + size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return 1; + } + } + return 0; + } + + iterator find(const key_type& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it; + } + } + return Container::end(); + } + + template::value, int> = 0> + iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it; + } + } + return Container::end(); + } + + const_iterator find(const key_type& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it; + } + } + return Container::end(); + } + + std::pair insert( value_type&& value ) + { + return emplace(value.first, std::move(value.second)); + } + + std::pair insert( const value_type& value ) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, value.first)) + { + return {it, false}; + } + } + Container::push_back(value); + return {--this->end(), true}; + } + + template + using require_input_iter = typename std::enable_if::iterator_category, + std::input_iterator_tag>::value>::type; + + template> + void insert(InputIt first, InputIt last) + { + for (auto it = first; it != last; ++it) + { + insert(*it); + } + } + +private: + JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare(); +}; + +NLOHMANN_JSON_NAMESPACE_END + + +#if defined(JSON_HAS_CPP_17) + #if JSON_HAS_STATIC_RTTI + #include + #endif + #include +#endif + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +NLOHMANN_JSON_NAMESPACE_BEGIN + +/*! +@brief a class to store JSON values + +@internal +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@note ObjectType trick from https://stackoverflow.com/a/9860911 +@endinternal + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + : public ::nlohmann::detail::json_base_class +{ + private: + template friend struct detail::external_constructor; + + template + friend class ::nlohmann::json_pointer; + // can be restored when json_pointer backwards compatibility is removed + // friend ::nlohmann::json_pointer; + + template + friend class ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + template + friend class ::nlohmann::detail::json_sax_dom_parser; + template + friend class ::nlohmann::detail::json_sax_dom_callback_parser; + friend class ::nlohmann::detail::exception; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + using json_base_class_t = ::nlohmann::detail::json_base_class; + + JSON_PRIVATE_UNLESS_TESTED: + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer_base; + + template + static ::nlohmann::detail::parser parser( + InputAdapterType adapter, + detail::parser_callback_tcb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false + ) + { + return ::nlohmann::detail::parser(std::move(adapter), + std::move(cb), allow_exceptions, ignore_comments); + } + + private: + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + template + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + JSON_PRIVATE_UNLESS_TESTED: + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// JSON Pointer, see @ref nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// how to treat decoding errors + using error_handler_t = detail::error_handler_t; + /// how to treat CBOR tags + using cbor_tag_handler_t = detail::cbor_tag_handler_t; + /// how to encode BJData + using bjdata_version_t = detail::bjdata_version_t; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + using input_format_t = detail::input_format_t; + /// SAX interface type, see @ref nlohmann::json_sax + using json_sax_t = json_sax; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + using exception = detail::exception; + using parse_error = detail::parse_error; + using invalid_iterator = detail::invalid_iterator; + using type_error = detail::type_error; + using out_of_range = detail::out_of_range; + using other_error = detail::other_error; + + /// @} + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + /// @brief returns the allocator associated with the container + /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /// @brief returns version information on the library + /// @sa https://json.nlohmann.me/api/basic_json/meta/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2025 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"]["string"] = + detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.', + std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.', + std::to_string(NLOHMANN_JSON_VERSION_PATCH)); + result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; + result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; + result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", detail::concat( + std::to_string(__GNUC__), '.', + std::to_string(__GNUC_MINOR__), '.', + std::to_string(__GNUC_PATCHLEVEL__)) + } + }; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#if defined(_MSVC_LANG) + result["compiler"]["c++"] = std::to_string(_MSVC_LANG); +#elif defined(__cplusplus) + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + + /// @brief default object key comparator type + /// The actual object key comparator type (@ref object_comparator_t) may be + /// different. + /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/ +#if defined(JSON_HAS_CPP_14) + // use of transparent comparator avoids unnecessary repeated construction of temporaries + // in functions involving lookup by key with types other than object_t::key_type (aka. StringType) + using default_object_comparator_t = std::less<>; +#else + using default_object_comparator_t = std::less; +#endif + + /// @brief a type for an object + /// @sa https://json.nlohmann.me/api/basic_json/object_t/ + using object_t = ObjectType>>; + + /// @brief a type for an array + /// @sa https://json.nlohmann.me/api/basic_json/array_t/ + using array_t = ArrayType>; + + /// @brief a type for a string + /// @sa https://json.nlohmann.me/api/basic_json/string_t/ + using string_t = StringType; + + /// @brief a type for a boolean + /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/ + using boolean_t = BooleanType; + + /// @brief a type for a number (integer) + /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/ + using number_integer_t = NumberIntegerType; + + /// @brief a type for a number (unsigned) + /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/ + using number_unsigned_t = NumberUnsignedType; + + /// @brief a type for a number (floating-point) + /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/ + using number_float_t = NumberFloatType; + + /// @brief a type for a packed binary type + /// @sa https://json.nlohmann.me/api/basic_json/binary_t/ + using binary_t = nlohmann::byte_container_with_subtype; + + /// @brief object key comparator type + /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/ + using object_comparator_t = detail::actual_object_comparator_t; + + /// @} + + private: + + /// helper for exception-safe object creation + template + JSON_HEDLEY_RETURNS_NON_NULL + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * obj) + { + AllocatorTraits::deallocate(alloc, obj, 1); + }; + std::unique_ptr obj(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, obj.get(), std::forward(args)...); + JSON_ASSERT(obj != nullptr); + return obj.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + binary | binary | pointer to @ref binary_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// binary (stored with pointer to save storage) + binary_t* binary; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::binary: + { + binary = create(); + break; + } + + case value_t::boolean: + { + boolean = static_cast(false); + break; + } + + case value_t::number_integer: + { + number_integer = static_cast(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = static_cast(0); + break; + } + + case value_t::number_float: + { + number_float = static_cast(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + case value_t::discarded: + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) : string(create(value)) {} + + /// constructor for rvalue strings + json_value(string_t&& value) : string(create(std::move(value))) {} + + /// constructor for objects + json_value(const object_t& value) : object(create(value)) {} + + /// constructor for rvalue objects + json_value(object_t&& value) : object(create(std::move(value))) {} + + /// constructor for arrays + json_value(const array_t& value) : array(create(value)) {} + + /// constructor for rvalue arrays + json_value(array_t&& value) : array(create(std::move(value))) {} + + /// constructor for binary arrays + json_value(const typename binary_t::container_type& value) : binary(create(value)) {} + + /// constructor for rvalue binary arrays + json_value(typename binary_t::container_type&& value) : binary(create(std::move(value))) {} + + /// constructor for binary arrays (internal type) + json_value(const binary_t& value) : binary(create(value)) {} + + /// constructor for rvalue binary arrays (internal type) + json_value(binary_t&& value) : binary(create(std::move(value))) {} + + void destroy(value_t t) + { + if ( + (t == value_t::object && object == nullptr) || + (t == value_t::array && array == nullptr) || + (t == value_t::string && string == nullptr) || + (t == value_t::binary && binary == nullptr) + ) + { + //not initialized (e.g. due to exception in the ctor) + return; + } + if (t == value_t::array || t == value_t::object) + { + // flatten the current json_value to a heap-allocated stack + std::vector stack; + + // move the top-level items to stack + if (t == value_t::array) + { + stack.reserve(array->size()); + std::move(array->begin(), array->end(), std::back_inserter(stack)); + } + else + { + stack.reserve(object->size()); + for (auto&& it : *object) + { + stack.push_back(std::move(it.second)); + } + } + + while (!stack.empty()) + { + // move the last item to local variable to be processed + basic_json current_item(std::move(stack.back())); + stack.pop_back(); + + // if current_item is array/object, move + // its children to the stack to be processed later + if (current_item.is_array()) + { + std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack)); + + current_item.m_data.m_value.array->clear(); + } + else if (current_item.is_object()) + { + for (auto&& it : *current_item.m_data.m_value.object) + { + stack.push_back(std::move(it.second)); + } + + current_item.m_data.m_value.object->clear(); + } + + // it's now safe that current_item get destructed + // since it doesn't have any children + } + } + + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + case value_t::binary: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, binary); + std::allocator_traits::deallocate(alloc, binary, 1); + break; + } + + case value_t::null: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::discarded: + default: + { + break; + } + } + } + }; + + private: + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + + Furthermore, the parent relation is checked for arrays and objects: If + @a check_parents true and the value is an array or object, then the + container's elements must have the current value as parent. + + @param[in] check_parents whether the parent relation should be checked. + The value is true by default and should only be set to false + during destruction of objects when the invariant does not + need to hold. + */ + void assert_invariant(bool check_parents = true) const noexcept + { + JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr); + JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr); + JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr); + JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr); + +#if JSON_DIAGNOSTICS + JSON_TRY + { + // cppcheck-suppress assertWithSideEffect + JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) + { + return j.m_parent == this; + })); + } + JSON_CATCH(...) {} // LCOV_EXCL_LINE +#endif + static_cast(check_parents); + } + + void set_parents() + { +#if JSON_DIAGNOSTICS + switch (m_data.m_type) + { + case value_t::array: + { + for (auto& element : *m_data.m_value.array) + { + element.m_parent = this; + } + break; + } + + case value_t::object: + { + for (auto& element : *m_data.m_value.object) + { + element.second.m_parent = this; + } + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + break; + } +#endif + } + + iterator set_parents(iterator it, typename iterator::difference_type count_set_parents) + { +#if JSON_DIAGNOSTICS + for (typename iterator::difference_type i = 0; i < count_set_parents; ++i) + { + (it + i)->m_parent = this; + } +#else + static_cast(count_set_parents); +#endif + return it; + } + + reference set_parent(reference j, std::size_t old_capacity = detail::unknown_size()) + { +#if JSON_DIAGNOSTICS + if (old_capacity != detail::unknown_size()) + { + // see https://github.com/nlohmann/json/issues/2838 + JSON_ASSERT(type() == value_t::array); + if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + return j; + } + } + + // ordered_json uses a vector internally, so pointers could have + // been invalidated; see https://github.com/nlohmann/json/issues/2962 +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(push ) +#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr +#endif + if (detail::is_ordered_map::value) + { + set_parents(); + return j; + } +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning( pop ) +#endif + + j.m_parent = this; +#else + static_cast(j); + static_cast(old_capacity); +#endif + return j; + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /// @brief parser event types + /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/ + using parse_event_t = detail::parse_event_t; + + /// @brief per-element parser callback type + /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/ + using parser_callback_t = detail::parser_callback_t; + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /// @brief create an empty value with a given type + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + basic_json(const value_t v) + : m_data(v) + { + assert_invariant(); + } + + /// @brief create a null object + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape) + : basic_json(value_t::null) + { + assert_invariant(); + } + + /// @brief create a JSON value from compatible types + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + template < typename CompatibleType, + typename U = detail::uncvref_t, + detail::enable_if_t < + !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > + basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) + JSONSerializer::to_json(std::declval(), + std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + set_parents(); + assert_invariant(); + } + + /// @brief create a JSON value from an existing one + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value&& !std::is_same::value, int > = 0 > + basic_json(const BasicJsonType& val) +#if JSON_DIAGNOSTIC_POSITIONS + : start_position(val.start_pos()), + end_position(val.end_pos()) +#endif + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + using other_binary_t = typename BasicJsonType::binary_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::binary: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_data.m_type = value_t::discarded; + break; + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + JSON_ASSERT(m_data.m_type == val.type()); + + set_parents(); + assert_invariant(); + } + + /// @brief create a container (array or object) from an initializer list + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int; + // (many string types can be constructed from 0 via its null-pointer guise, so we get a + // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows) + return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast(0)].is_string(); + }); + + // adjust type if type deduction is not wanted + if (!type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr)); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_data.m_type = value_t::object; + m_data.m_value = value_t::object; + + for (auto& element_ref : init) + { + auto element = element_ref.moved_or_copied(); + m_data.m_value.object->emplace( + std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)), + std::move((*element.m_data.m_value.array)[1])); + } + } + else + { + // the initializer list describes an array -> create array + m_data.m_type = value_t::array; + m_data.m_value.array = create(init.begin(), init.end()); + } + + set_parents(); + assert_invariant(); + } + + /// @brief explicitly create a binary array (without subtype) + /// @sa https://json.nlohmann.me/api/basic_json/binary/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init) + { + auto res = basic_json(); + res.m_data.m_type = value_t::binary; + res.m_data.m_value = init; + return res; + } + + /// @brief explicitly create a binary array (with subtype) + /// @sa https://json.nlohmann.me/api/basic_json/binary/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) + { + auto res = basic_json(); + res.m_data.m_type = value_t::binary; + res.m_data.m_value = binary_t(init, subtype); + return res; + } + + /// @brief explicitly create a binary array + /// @sa https://json.nlohmann.me/api/basic_json/binary/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init) + { + auto res = basic_json(); + res.m_data.m_type = value_t::binary; + res.m_data.m_value = std::move(init); + return res; + } + + /// @brief explicitly create a binary array (with subtype) + /// @sa https://json.nlohmann.me/api/basic_json/binary/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) + { + auto res = basic_json(); + res.m_data.m_type = value_t::binary; + res.m_data.m_value = binary_t(std::move(init), subtype); + return res; + } + + /// @brief explicitly create an array from an initializer list + /// @sa https://json.nlohmann.me/api/basic_json/array/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /// @brief explicitly create an object from an initializer list + /// @sa https://json.nlohmann.me/api/basic_json/object/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /// @brief construct an array with count copies of given value + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + basic_json(size_type cnt, const basic_json& val): + m_data{cnt, val} + { + set_parents(); + assert_invariant(); + } + + /// @brief construct a JSON container given an iterator range + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + template < class InputIT, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type = 0 > + basic_json(InputIT first, InputIT last) // NOLINT(performance-unnecessary-value-param) + { + JSON_ASSERT(first.m_object != nullptr); + JSON_ASSERT(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr)); + } + + // copy type from first iterator + m_data.m_type = first.m_object->m_data.m_type; + + // check if iterator range is complete for primitive values + switch (m_data.m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object)); + } + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::binary: + case value_t::discarded: + default: + break; + } + + switch (m_data.m_type) + { + case value_t::number_integer: + { + m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_data.m_value.number_float = first.m_object->m_data.m_value.number_float; + break; + } + + case value_t::boolean: + { + m_data.m_value.boolean = first.m_object->m_data.m_value.boolean; + break; + } + + case value_t::string: + { + m_data.m_value = *first.m_object->m_data.m_value.string; + break; + } + + case value_t::object: + { + m_data.m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_data.m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + case value_t::binary: + { + m_data.m_value = *first.m_object->m_data.m_value.binary; + break; + } + + case value_t::null: + case value_t::discarded: + default: + JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); + } + + set_parents(); + assert_invariant(); + } + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + template, + std::is_same>::value, int> = 0 > + basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} + + /// @brief copy constructor + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + basic_json(const basic_json& other) + : json_base_class_t(other) +#if JSON_DIAGNOSTIC_POSITIONS + , start_position(other.start_position) + , end_position(other.end_position) +#endif + { + m_data.m_type = other.m_data.m_type; + // check of passed value is valid + other.assert_invariant(); + + switch (m_data.m_type) + { + case value_t::object: + { + m_data.m_value = *other.m_data.m_value.object; + break; + } + + case value_t::array: + { + m_data.m_value = *other.m_data.m_value.array; + break; + } + + case value_t::string: + { + m_data.m_value = *other.m_data.m_value.string; + break; + } + + case value_t::boolean: + { + m_data.m_value = other.m_data.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_data.m_value = other.m_data.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_data.m_value = other.m_data.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_data.m_value = other.m_data.m_value.number_float; + break; + } + + case value_t::binary: + { + m_data.m_value = *other.m_data.m_value.binary; + break; + } + + case value_t::null: + case value_t::discarded: + default: + break; + } + + set_parents(); + assert_invariant(); + } + + /// @brief move constructor + /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ + basic_json(basic_json&& other) noexcept + : json_base_class_t(std::forward(other)), + m_data(std::move(other.m_data)) // cppcheck-suppress[accessForwarded] TODO check +#if JSON_DIAGNOSTIC_POSITIONS + , start_position(other.start_position) // cppcheck-suppress[accessForwarded] TODO check + , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check +#endif + { + // check that passed value is valid + other.assert_invariant(false); // cppcheck-suppress[accessForwarded] + + // invalidate payload + other.m_data.m_type = value_t::null; + other.m_data.m_value = {}; + +#if JSON_DIAGNOSTIC_POSITIONS + other.start_position = std::string::npos; + other.end_position = std::string::npos; +#endif + + set_parents(); + assert_invariant(); + } + + /// @brief copy assignment + /// @sa https://json.nlohmann.me/api/basic_json/operator=/ + basic_json& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_data.m_type, other.m_data.m_type); + swap(m_data.m_value, other.m_data.m_value); + +#if JSON_DIAGNOSTIC_POSITIONS + swap(start_position, other.start_position); + swap(end_position, other.end_position); +#endif + + json_base_class_t::operator=(std::move(other)); + + set_parents(); + assert_invariant(); + return *this; + } + + /// @brief destructor + /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/ + ~basic_json() noexcept + { + assert_invariant(false); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /// @brief serialization + /// @sa https://json.nlohmann.me/api/basic_json/dump/ + string_t dump(const int indent = -1, + const char indent_char = ' ', + const bool ensure_ascii = false, + const error_handler_t error_handler = error_handler_t::strict) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char, error_handler); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /// @brief return the type of the JSON value (explicit) + /// @sa https://json.nlohmann.me/api/basic_json/type/ + constexpr value_t type() const noexcept + { + return m_data.m_type; + } + + /// @brief return whether type is primitive + /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ + constexpr bool is_primitive() const noexcept + { + return is_null() || is_string() || is_boolean() || is_number() || is_binary(); + } + + /// @brief return whether type is structured + /// @sa https://json.nlohmann.me/api/basic_json/is_structured/ + constexpr bool is_structured() const noexcept + { + return is_array() || is_object(); + } + + /// @brief return whether value is null + /// @sa https://json.nlohmann.me/api/basic_json/is_null/ + constexpr bool is_null() const noexcept + { + return m_data.m_type == value_t::null; + } + + /// @brief return whether value is a boolean + /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ + constexpr bool is_boolean() const noexcept + { + return m_data.m_type == value_t::boolean; + } + + /// @brief return whether value is a number + /// @sa https://json.nlohmann.me/api/basic_json/is_number/ + constexpr bool is_number() const noexcept + { + return is_number_integer() || is_number_float(); + } + + /// @brief return whether value is an integer number + /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ + constexpr bool is_number_integer() const noexcept + { + return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned; + } + + /// @brief return whether value is an unsigned integer number + /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ + constexpr bool is_number_unsigned() const noexcept + { + return m_data.m_type == value_t::number_unsigned; + } + + /// @brief return whether value is a floating-point number + /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ + constexpr bool is_number_float() const noexcept + { + return m_data.m_type == value_t::number_float; + } + + /// @brief return whether value is an object + /// @sa https://json.nlohmann.me/api/basic_json/is_object/ + constexpr bool is_object() const noexcept + { + return m_data.m_type == value_t::object; + } + + /// @brief return whether value is an array + /// @sa https://json.nlohmann.me/api/basic_json/is_array/ + constexpr bool is_array() const noexcept + { + return m_data.m_type == value_t::array; + } + + /// @brief return whether value is a string + /// @sa https://json.nlohmann.me/api/basic_json/is_string/ + constexpr bool is_string() const noexcept + { + return m_data.m_type == value_t::string; + } + + /// @brief return whether value is a binary array + /// @sa https://json.nlohmann.me/api/basic_json/is_binary/ + constexpr bool is_binary() const noexcept + { + return m_data.m_type == value_t::binary; + } + + /// @brief return whether value is discarded + /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ + constexpr bool is_discarded() const noexcept + { + return m_data.m_type == value_t::discarded; + } + + /// @brief return the type of the JSON value (implicit) + /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/ + constexpr operator value_t() const noexcept + { + return m_data.m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_HEDLEY_LIKELY(is_boolean())) + { + return m_data.m_value.boolean; + } + + JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this)); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_data.m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_data.m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_data.m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_data.m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_data.m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_data.m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_data.m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_data.m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_data.m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_data.m_value.number_float : nullptr; + } + + /// get a pointer to the value (binary) + binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept + { + return is_binary() ? m_data.m_value.binary : nullptr; + } + + /// get a pointer to the value (binary) + constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept + { + return is_binary() ? m_data.m_value.binary : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto* ptr = obj.template get_ptr::type>(); + + if (JSON_HEDLEY_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /// @brief get a pointer value (implicit) + /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ + template::value, int>::type = 0> + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /// @brief get a pointer value (implicit) + /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ + template < typename PointerType, typename std::enable_if < + std::is_pointer::value&& + std::is_const::type>::value, int >::type = 0 > + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + private: + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template < typename ValueType, + detail::enable_if_t < + detail::is_default_constructible::value&& + detail::has_from_json::value, + int > = 0 > + ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + auto ret = ValueType(); + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template < typename ValueType, + detail::enable_if_t < + detail::has_non_default_from_json::value, + int > = 0 > + ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + return JSONSerializer::from_json(*this); + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @a BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.2.0 + */ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value, + int > = 0 > + BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::value, + int> = 0> + basic_json get_impl(detail::priority_tag<3> /*unused*/) const + { + return *this; + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, + int> = 0> + constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept + -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + public: + /*! + @brief get a (pointer) value (explicit) + + Performs explicit type conversion between the JSON value and a compatible value if required. + + - If the requested type is a pointer to the internally stored JSON value that pointer is returned. + No copies are made. + + - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible + from the current @ref basic_json. + + - Otherwise the value is converted by calling the @ref json_serializer `from_json()` + method. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @tparam ValueType if necessary + + @throw what @ref json_serializer `from_json()` method throws if conversion is required + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t> +#if defined(JSON_HAS_CPP_14) + constexpr +#endif + auto get() const noexcept( + noexcept(std::declval().template get_impl(detail::priority_tag<4> {}))) + -> decltype(std::declval().template get_impl(detail::priority_tag<4> {})) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(!std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return get_impl(detail::priority_tag<4> {}); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa see @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /// @brief get a value (explicit) + /// @sa https://json.nlohmann.me/api/basic_json/get_to/ + template < typename ValueType, + detail::enable_if_t < + !detail::is_basic_json::value&& + detail::has_from_json::value, + int > = 0 > + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + // specialization to allow calling get_to with a basic_json value + // see https://github.com/nlohmann/json/issues/2175 + template::value, + int> = 0> + ValueType & get_to(ValueType& v) const + { + v = *this; + return v; + } + + template < + typename T, std::size_t N, + typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + detail::enable_if_t < + detail::has_from_json::value, int > = 0 > + Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + noexcept(noexcept(JSONSerializer::from_json( + std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + /// @brief get a reference value (implicit) + /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /// @brief get a reference value (implicit) + /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ + template < typename ReferenceType, typename std::enable_if < + std::is_reference::value&& + std::is_const::type>::value, int >::type = 0 > + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + detail::conjunction < + detail::negation>, + detail::negation>, + detail::negation>>, + detail::negation>, + detail::negation>, + detail::negation>>, +#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) + detail::negation>, +#endif +#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI + detail::negation>, +#endif + detail::is_detected_lazy + >::value, int >::type = 0 > + JSON_EXPLICIT operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @brief get a binary value + /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ + binary_t& get_binary() + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this)); + } + + return *get_ptr(); + } + + /// @brief get a binary value + /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ + const binary_t& get_binary() const + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this)); + } + + return *get_ptr(); + } + + /// @} + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /// @brief access specified array element with bounds checking + /// @sa https://json.nlohmann.me/api/basic_json/at/ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return set_parent(m_data.m_value.array->at(idx)); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + } // cppcheck-suppress[missingReturn] + } + else + { + JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); + } + } + + /// @brief access specified array element with bounds checking + /// @sa https://json.nlohmann.me/api/basic_json/at/ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return m_data.m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + } // cppcheck-suppress[missingReturn] + } + else + { + JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); + } + } + + /// @brief access specified object element with bounds checking + /// @sa https://json.nlohmann.me/api/basic_json/at/ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); + } + + auto it = m_data.m_value.object->find(key); + if (it == m_data.m_value.object->end()) + { + JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this)); + } + return set_parent(it->second); + } + + /// @brief access specified object element with bounds checking + /// @sa https://json.nlohmann.me/api/basic_json/at/ + template::value, int> = 0> + reference at(KeyType && key) + { + // at only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); + } + + auto it = m_data.m_value.object->find(std::forward(key)); + if (it == m_data.m_value.object->end()) + { + JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward(key)), "' not found"), this)); + } + return set_parent(it->second); + } + + /// @brief access specified object element with bounds checking + /// @sa https://json.nlohmann.me/api/basic_json/at/ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); + } + + auto it = m_data.m_value.object->find(key); + if (it == m_data.m_value.object->end()) + { + JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this)); + } + return it->second; + } + + /// @brief access specified object element with bounds checking + /// @sa https://json.nlohmann.me/api/basic_json/at/ + template::value, int> = 0> + const_reference at(KeyType && key) const + { + // at only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); + } + + auto it = m_data.m_value.object->find(std::forward(key)); + if (it == m_data.m_value.object->end()) + { + JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward(key)), "' not found"), this)); + } + return it->second; + } + + /// @brief access specified array element + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_data.m_type = value_t::array; + m_data.m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_data.m_value.array->size()) + { +#if JSON_DIAGNOSTICS + // remember array size & capacity before resizing + const auto old_size = m_data.m_value.array->size(); + const auto old_capacity = m_data.m_value.array->capacity(); +#endif + m_data.m_value.array->resize(idx + 1); + +#if JSON_DIAGNOSTICS + if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + } + else + { + // set parent for values added above + set_parents(begin() + static_cast(old_size), static_cast(idx + 1 - old_size)); + } +#endif + assert_invariant(); + } + + return m_data.m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this)); + } + + /// @brief access specified array element + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + return m_data.m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this)); + } + + /// @brief access specified object element + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_data.m_type = value_t::object; + m_data.m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + auto result = m_data.m_value.object->emplace(std::move(key), nullptr); + return set_parent(result.first->second); + } + + JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); + } + + /// @brief access specified object element + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + auto it = m_data.m_value.object->find(key); + JSON_ASSERT(it != m_data.m_value.object->end()); + return it->second; + } + + JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); + } + + // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC + // (they seemingly cannot be constrained to resolve the ambiguity) + template + reference operator[](T* key) + { + return operator[](typename object_t::key_type(key)); + } + + template + const_reference operator[](T* key) const + { + return operator[](typename object_t::key_type(key)); + } + + /// @brief access specified object element + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + template::value, int > = 0 > + reference operator[](KeyType && key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_data.m_type = value_t::object; + m_data.m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + auto result = m_data.m_value.object->emplace(std::forward(key), nullptr); + return set_parent(result.first->second); + } + + JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); + } + + /// @brief access specified object element + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + template::value, int > = 0 > + const_reference operator[](KeyType && key) const + { + // const operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + auto it = m_data.m_value.object->find(std::forward(key)); + JSON_ASSERT(it != m_data.m_value.object->end()); + return it->second; + } + + JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); + } + + private: + template + using is_comparable_with_object_key = detail::is_comparable < + object_comparator_t, const typename object_t::key_type&, KeyType >; + + template + using value_return_type = std::conditional < + detail::is_c_string_uncvref::value, + string_t, typename std::decay::type >; + + public: + /// @brief access specified object element with default value + /// @sa https://json.nlohmann.me/api/basic_json/value/ + template < class ValueType, detail::enable_if_t < + !detail::is_transparent::value + && detail::is_getable::value + && !std::is_same>::value, int > = 0 > + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // value only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return it->template get(); + } + + return default_value; + } + + JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); + } + + /// @brief access specified object element with default value + /// @sa https://json.nlohmann.me/api/basic_json/value/ + template < class ValueType, class ReturnType = typename value_return_type::type, + detail::enable_if_t < + !detail::is_transparent::value + && detail::is_getable::value + && !std::is_same>::value, int > = 0 > + ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const + { + // value only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return it->template get(); + } + + return std::forward(default_value); + } + + JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); + } + + /// @brief access specified object element with default value + /// @sa https://json.nlohmann.me/api/basic_json/value/ + template < class ValueType, class KeyType, detail::enable_if_t < + detail::is_transparent::value + && !detail::is_json_pointer::value + && is_comparable_with_object_key::value + && detail::is_getable::value + && !std::is_same>::value, int > = 0 > + ValueType value(KeyType && key, const ValueType& default_value) const + { + // value only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(std::forward(key)); + if (it != end()) + { + return it->template get(); + } + + return default_value; + } + + JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); + } + + /// @brief access specified object element via JSON Pointer with default value + /// @sa https://json.nlohmann.me/api/basic_json/value/ + template < class ValueType, class KeyType, class ReturnType = typename value_return_type::type, + detail::enable_if_t < + detail::is_transparent::value + && !detail::is_json_pointer::value + && is_comparable_with_object_key::value + && detail::is_getable::value + && !std::is_same>::value, int > = 0 > + ReturnType value(KeyType && key, ValueType && default_value) const + { + // value only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(std::forward(key)); + if (it != end()) + { + return it->template get(); + } + + return std::forward(default_value); + } + + JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); + } + + /// @brief access specified object element via JSON Pointer with default value + /// @sa https://json.nlohmann.me/api/basic_json/value/ + template < class ValueType, detail::enable_if_t < + detail::is_getable::value + && !std::is_same>::value, int > = 0 > + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // value only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this).template get(); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); + } + + /// @brief access specified object element via JSON Pointer with default value + /// @sa https://json.nlohmann.me/api/basic_json/value/ + template < class ValueType, class ReturnType = typename value_return_type::type, + detail::enable_if_t < + detail::is_getable::value + && !std::is_same>::value, int > = 0 > + ReturnType value(const json_pointer& ptr, ValueType && default_value) const + { + // value only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this).template get(); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + return std::forward(default_value); + } + } + + JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); + } + + template < class ValueType, class BasicJsonType, detail::enable_if_t < + detail::is_basic_json::value + && detail::is_getable::value + && !std::is_same>::value, int > = 0 > + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + ValueType value(const ::nlohmann::json_pointer& ptr, const ValueType& default_value) const + { + return value(ptr.convert(), default_value); + } + + template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type::type, + detail::enable_if_t < + detail::is_basic_json::value + && detail::is_getable::value + && !std::is_same>::value, int > = 0 > + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + ReturnType value(const ::nlohmann::json_pointer& ptr, ValueType && default_value) const + { + return value(ptr.convert(), std::forward(default_value)); + } + + /// @brief access the first element + /// @sa https://json.nlohmann.me/api/basic_json/front/ + reference front() + { + return *begin(); + } + + /// @brief access the first element + /// @sa https://json.nlohmann.me/api/basic_json/front/ + const_reference front() const + { + return *cbegin(); + } + + /// @brief access the last element + /// @sa https://json.nlohmann.me/api/basic_json/back/ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /// @brief access the last element + /// @sa https://json.nlohmann.me/api/basic_json/back/ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /// @brief remove element given an iterator + /// @sa https://json.nlohmann.me/api/basic_json/erase/ + template < class IteratorType, detail::enable_if_t < + std::is_same::value || + std::is_same::value, int > = 0 > + IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + } + + IteratorType result = end(); + + switch (m_data.m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range", this)); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_data.m_value.string); + std::allocator_traits::deallocate(alloc, m_data.m_value.string, 1); + m_data.m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_data.m_value.binary); + std::allocator_traits::deallocate(alloc, m_data.m_value.binary, 1); + m_data.m_value.binary = nullptr; + } + + m_data.m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator); + break; + } + + case value_t::null: + case value_t::discarded: + default: + JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); + } + + return result; + } + + /// @brief remove elements given an iterator range + /// @sa https://json.nlohmann.me/api/basic_json/erase/ + template < class IteratorType, detail::enable_if_t < + std::is_same::value || + std::is_same::value, int > = 0 > + IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this)); + } + + IteratorType result = end(); + + switch (m_data.m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range", this)); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_data.m_value.string); + std::allocator_traits::deallocate(alloc, m_data.m_value.string, 1); + m_data.m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_data.m_value.binary); + std::allocator_traits::deallocate(alloc, m_data.m_value.binary, 1); + m_data.m_value.binary = nullptr; + } + + m_data.m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + case value_t::null: + case value_t::discarded: + default: + JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); + } + + return result; + } + + private: + template < typename KeyType, detail::enable_if_t < + detail::has_erase_with_key_type::value, int > = 0 > + size_type erase_internal(KeyType && key) + { + // this erase only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); + } + + return m_data.m_value.object->erase(std::forward(key)); + } + + template < typename KeyType, detail::enable_if_t < + !detail::has_erase_with_key_type::value, int > = 0 > + size_type erase_internal(KeyType && key) + { + // this erase only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); + } + + const auto it = m_data.m_value.object->find(std::forward(key)); + if (it != m_data.m_value.object->end()) + { + m_data.m_value.object->erase(it); + return 1; + } + return 0; + } + + public: + + /// @brief remove element from a JSON object given a key + /// @sa https://json.nlohmann.me/api/basic_json/erase/ + size_type erase(const typename object_t::key_type& key) + { + // the indirection via erase_internal() is added to avoid making this + // function a template and thus de-rank it during overload resolution + return erase_internal(key); + } + + /// @brief remove element from a JSON object given a key + /// @sa https://json.nlohmann.me/api/basic_json/erase/ + template::value, int> = 0> + size_type erase(KeyType && key) + { + return erase_internal(std::forward(key)); + } + + /// @brief remove element from a JSON array given an index + /// @sa https://json.nlohmann.me/api/basic_json/erase/ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + if (JSON_HEDLEY_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + } + + m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); + } + } + + /// @} + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /// @brief find an element in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/find/ + iterator find(const typename object_t::key_type& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_data.m_value.object->find(key); + } + + return result; + } + + /// @brief find an element in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/find/ + const_iterator find(const typename object_t::key_type& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_data.m_value.object->find(key); + } + + return result; + } + + /// @brief find an element in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/find/ + template::value, int> = 0> + iterator find(KeyType && key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_data.m_value.object->find(std::forward(key)); + } + + return result; + } + + /// @brief find an element in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/find/ + template::value, int> = 0> + const_iterator find(KeyType && key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_data.m_value.object->find(std::forward(key)); + } + + return result; + } + + /// @brief returns the number of occurrences of a key in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/count/ + size_type count(const typename object_t::key_type& key) const + { + // return 0 for all nonobject types + return is_object() ? m_data.m_value.object->count(key) : 0; + } + + /// @brief returns the number of occurrences of a key in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/count/ + template::value, int> = 0> + size_type count(KeyType && key) const + { + // return 0 for all nonobject types + return is_object() ? m_data.m_value.object->count(std::forward(key)) : 0; + } + + /// @brief check the existence of an element in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/contains/ + bool contains(const typename object_t::key_type& key) const + { + return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end(); + } + + /// @brief check the existence of an element in a JSON object + /// @sa https://json.nlohmann.me/api/basic_json/contains/ + template::value, int> = 0> + bool contains(KeyType && key) const + { + return is_object() && m_data.m_value.object->find(std::forward(key)) != m_data.m_value.object->end(); + } + + /// @brief check the existence of an element in a JSON object given a JSON pointer + /// @sa https://json.nlohmann.me/api/basic_json/contains/ + bool contains(const json_pointer& ptr) const + { + return ptr.contains(this); + } + + template::value, int> = 0> + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + bool contains(const typename ::nlohmann::json_pointer& ptr) const + { + return ptr.contains(this); + } + + /// @} + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /// @brief returns an iterator to the first element + /// @sa https://json.nlohmann.me/api/basic_json/begin/ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /// @brief returns an iterator to the first element + /// @sa https://json.nlohmann.me/api/basic_json/begin/ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /// @brief returns a const iterator to the first element + /// @sa https://json.nlohmann.me/api/basic_json/cbegin/ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /// @brief returns an iterator to one past the last element + /// @sa https://json.nlohmann.me/api/basic_json/end/ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /// @brief returns an iterator to one past the last element + /// @sa https://json.nlohmann.me/api/basic_json/end/ + const_iterator end() const noexcept + { + return cend(); + } + + /// @brief returns an iterator to one past the last element + /// @sa https://json.nlohmann.me/api/basic_json/cend/ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /// @brief returns an iterator to the reverse-beginning + /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /// @brief returns an iterator to the reverse-beginning + /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /// @brief returns an iterator to the reverse-end + /// @sa https://json.nlohmann.me/api/basic_json/rend/ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /// @brief returns an iterator to the reverse-end + /// @sa https://json.nlohmann.me/api/basic_json/rend/ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /// @brief returns a const reverse iterator to the last element + /// @sa https://json.nlohmann.me/api/basic_json/crbegin/ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /// @brief returns a const reverse iterator to one before the first + /// @sa https://json.nlohmann.me/api/basic_json/crend/ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /// @brief wrapper to access iterator member functions in range-based for + /// @sa https://json.nlohmann.me/api/basic_json/items/ + /// @deprecated This function is deprecated since 3.1.0 and will be removed in + /// version 4.0.0 of the library. Please use @ref items() instead; + /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(reference ref) noexcept + { + return ref.items(); + } + + /// @brief wrapper to access iterator member functions in range-based for + /// @sa https://json.nlohmann.me/api/basic_json/items/ + /// @deprecated This function is deprecated since 3.1.0 and will be removed in + /// version 4.0.0 of the library. Please use @ref items() instead; + /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(const_reference ref) noexcept + { + return ref.items(); + } + + /// @brief helper to access iterator member functions in range-based for + /// @sa https://json.nlohmann.me/api/basic_json/items/ + iteration_proxy items() noexcept + { + return iteration_proxy(*this); + } + + /// @brief helper to access iterator member functions in range-based for + /// @sa https://json.nlohmann.me/api/basic_json/items/ + iteration_proxy items() const noexcept + { + return iteration_proxy(*this); + } + + /// @} + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /// @brief checks whether the container is empty. + /// @sa https://json.nlohmann.me/api/basic_json/empty/ + bool empty() const noexcept + { + switch (m_data.m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_data.m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_data.m_value.object->empty(); + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // all other types are nonempty + return false; + } + } + } + + /// @brief returns the number of elements + /// @sa https://json.nlohmann.me/api/basic_json/size/ + size_type size() const noexcept + { + switch (m_data.m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_data.m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_data.m_value.object->size(); + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // all other types have size 1 + return 1; + } + } + } + + /// @brief returns the maximum possible number of elements + /// @sa https://json.nlohmann.me/api/basic_json/max_size/ + size_type max_size() const noexcept + { + switch (m_data.m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_data.m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_data.m_value.object->max_size(); + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /// @brief clears the contents + /// @sa https://json.nlohmann.me/api/basic_json/clear/ + void clear() noexcept + { + switch (m_data.m_type) + { + case value_t::number_integer: + { + m_data.m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_data.m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_data.m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_data.m_value.boolean = false; + break; + } + + case value_t::string: + { + m_data.m_value.string->clear(); + break; + } + + case value_t::binary: + { + m_data.m_value.binary->clear(); + break; + } + + case value_t::array: + { + m_data.m_value.array->clear(); + break; + } + + case value_t::object: + { + m_data.m_value.object->clear(); + break; + } + + case value_t::null: + case value_t::discarded: + default: + break; + } + } + + /// @brief add an object to an array + /// @sa https://json.nlohmann.me/api/basic_json/push_back/ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); + } + + // transform null object into an array + if (is_null()) + { + m_data.m_type = value_t::array; + m_data.m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + const auto old_capacity = m_data.m_value.array->capacity(); + m_data.m_value.array->push_back(std::move(val)); + set_parent(m_data.m_value.array->back(), old_capacity); + // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor + } + + /// @brief add an object to an array + /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /// @brief add an object to an array + /// @sa https://json.nlohmann.me/api/basic_json/push_back/ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); + } + + // transform null object into an array + if (is_null()) + { + m_data.m_type = value_t::array; + m_data.m_value = value_t::array; + assert_invariant(); + } + + // add element to array + const auto old_capacity = m_data.m_value.array->capacity(); + m_data.m_value.array->push_back(val); + set_parent(m_data.m_value.array->back(), old_capacity); + } + + /// @brief add an object to an array + /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /// @brief add an object to an object + /// @sa https://json.nlohmann.me/api/basic_json/push_back/ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); + } + + // transform null object into an object + if (is_null()) + { + m_data.m_type = value_t::object; + m_data.m_value = value_t::object; + assert_invariant(); + } + + // add element to object + auto res = m_data.m_value.object->insert(val); + set_parent(res.first->second); + } + + /// @brief add an object to an object + /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /// @brief add an object to an object + /// @sa https://json.nlohmann.me/api/basic_json/push_back/ + void push_back(initializer_list_t init) + { + if (is_object() && init.size() == 2 && (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /// @brief add an object to an object + /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /// @brief add an object to an array + /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/ + template + reference emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this)); + } + + // transform null object into an array + if (is_null()) + { + m_data.m_type = value_t::array; + m_data.m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + const auto old_capacity = m_data.m_value.array->capacity(); + m_data.m_value.array->emplace_back(std::forward(args)...); + return set_parent(m_data.m_value.array->back(), old_capacity); + } + + /// @brief add an object to an object if key does not exist + /// @sa https://json.nlohmann.me/api/basic_json/emplace/ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this)); + } + + // transform null object into an object + if (is_null()) + { + m_data.m_type = value_t::object; + m_data.m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_data.m_value.object->emplace(std::forward(args)...); + set_parent(res.first->second); + + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template + iterator insert_iterator(const_iterator pos, Args&& ... args) // NOLINT(performance-unnecessary-value-param) + { + iterator result(this); + JSON_ASSERT(m_data.m_value.array != nullptr); + + auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator); + m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + set_parents(); + return result; + } + + /// @brief inserts element into array + /// @sa https://json.nlohmann.me/api/basic_json/insert/ + iterator insert(const_iterator pos, const basic_json& val) // NOLINT(performance-unnecessary-value-param) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + } + + // insert to array and return iterator + return insert_iterator(pos, val); + } + + JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); + } + + /// @brief inserts element into array + /// @sa https://json.nlohmann.me/api/basic_json/insert/ + iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param) + { + return insert(pos, val); + } + + /// @brief inserts copies of element into array + /// @sa https://json.nlohmann.me/api/basic_json/insert/ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) // NOLINT(performance-unnecessary-value-param) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + } + + // insert to array and return iterator + return insert_iterator(pos, cnt, val); + } + + JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); + } + + /// @brief inserts range of elements into array + /// @sa https://json.nlohmann.me/api/basic_json/insert/ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + } + + if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this)); + } + + // insert to array and return iterator + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); + } + + /// @brief inserts elements from initializer list into array + /// @sa https://json.nlohmann.me/api/basic_json/insert/ + iterator insert(const_iterator pos, initializer_list_t ilist) // NOLINT(performance-unnecessary-value-param) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + } + + // insert to array and return iterator + return insert_iterator(pos, ilist.begin(), ilist.end()); + } + + /// @brief inserts range of elements into object + /// @sa https://json.nlohmann.me/api/basic_json/insert/ + void insert(const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param) + { + // insert only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this)); + } + + m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + set_parents(); + } + + /// @brief updates a JSON object from another object, overwriting existing keys + /// @sa https://json.nlohmann.me/api/basic_json/update/ + void update(const_reference j, bool merge_objects = false) + { + update(j.begin(), j.end(), merge_objects); + } + + /// @brief updates a JSON object from another object, overwriting existing keys + /// @sa https://json.nlohmann.me/api/basic_json/update/ + void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_data.m_type = value_t::object; + m_data.m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this)); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) + { + JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object)); + } + + for (auto it = first; it != last; ++it) + { + if (merge_objects && it.value().is_object()) + { + auto it2 = m_data.m_value.object->find(it.key()); + if (it2 != m_data.m_value.object->end()) + { + it2->second.update(it.value(), true); + continue; + } + } + m_data.m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_data.m_value.object->operator[](it.key()).m_parent = this; +#endif + } + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_data.m_type, other.m_data.m_type); + std::swap(m_data.m_value, other.m_data.m_value); + + set_parents(); + other.set_parents(); + assert_invariant(); + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + friend void swap(reference left, reference right) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + std::is_nothrow_move_assignable::value + ) + { + left.swap(right); + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + { + // swap only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + using std::swap; + swap(*(m_data.m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this)); + } + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + { + // swap only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + using std::swap; + swap(*(m_data.m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this)); + } + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_string())) + { + using std::swap; + swap(*(m_data.m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this)); + } + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + using std::swap; + swap(*(m_data.m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this)); + } + } + + /// @brief exchanges the values + /// @sa https://json.nlohmann.me/api/basic_json/swap/ + void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + using std::swap; + swap(*(m_data.m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this)); + } + } + + /// @} + + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + // note parentheses around operands are necessary; see + // https://github.com/nlohmann/json/issues/1530 +#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \ + const auto lhs_type = lhs.type(); \ + const auto rhs_type = rhs.type(); \ + \ + if (lhs_type == rhs_type) /* NOLINT(readability/braces) */ \ + { \ + switch (lhs_type) \ + { \ + case value_t::array: \ + return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array); \ + \ + case value_t::object: \ + return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \ + \ + case value_t::null: \ + return (null_result); \ + \ + case value_t::string: \ + return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \ + \ + case value_t::boolean: \ + return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean); \ + \ + case value_t::number_integer: \ + return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer); \ + \ + case value_t::number_unsigned: \ + return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned); \ + \ + case value_t::number_float: \ + return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float); \ + \ + case value_t::binary: \ + return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary); \ + \ + case value_t::discarded: \ + default: \ + return (unordered_result); \ + } \ + } \ + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \ + { \ + return static_cast(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \ + } \ + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \ + { \ + return lhs.m_data.m_value.number_float op static_cast(rhs.m_data.m_value.number_integer); \ + } \ + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \ + { \ + return static_cast(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \ + } \ + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \ + { \ + return lhs.m_data.m_value.number_float op static_cast(rhs.m_data.m_value.number_unsigned); \ + } \ + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \ + { \ + return static_cast(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \ + } \ + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \ + { \ + return lhs.m_data.m_value.number_integer op static_cast(rhs.m_data.m_value.number_unsigned); \ + } \ + else if(compares_unordered(lhs, rhs))\ + {\ + return (unordered_result);\ + }\ + \ + return (default_result); + + JSON_PRIVATE_UNLESS_TESTED: + // returns true if: + // - any operand is NaN and the other operand is of number type + // - any operand is discarded + // in legacy mode, discarded values are considered ordered if + // an operation is computed as an odd number of inverses of others + static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept + { + if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number()) + || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number())) + { + return true; + } +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + return (lhs.is_discarded() || rhs.is_discarded()) && !inverse; +#else + static_cast(inverse); + return lhs.is_discarded() || rhs.is_discarded(); +#endif + } + + private: + bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept + { + return compares_unordered(*this, rhs, inverse); + } + + public: +#if JSON_HAS_THREE_WAY_COMPARISON + /// @brief comparison: equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ + bool operator==(const_reference rhs) const noexcept + { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + const_reference lhs = *this; + JSON_IMPLEMENT_OPERATOR( ==, true, false, false) +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } + + /// @brief comparison: equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ + template + requires std::is_scalar_v + bool operator==(ScalarType rhs) const noexcept + { + return *this == basic_json(rhs); + } + + /// @brief comparison: not equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ + bool operator!=(const_reference rhs) const noexcept + { + if (compares_unordered(rhs, true)) + { + return false; + } + return !operator==(rhs); + } + + /// @brief comparison: 3-way + /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ + std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD* + { + const_reference lhs = *this; + // default_result is used if we cannot compare values. In that case, + // we compare types. + JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD* + std::partial_ordering::equivalent, + std::partial_ordering::unordered, + lhs_type <=> rhs_type) // *NOPAD* + } + + /// @brief comparison: 3-way + /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ + template + requires std::is_scalar_v + std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD* + { + return *this <=> basic_json(rhs); // *NOPAD* + } + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + // all operators that are computed as an odd number of inverses of others + // need to be overloaded to emulate the legacy comparison behavior + + /// @brief comparison: less than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) + bool operator<=(const_reference rhs) const noexcept + { + if (compares_unordered(rhs, true)) + { + return false; + } + return !(rhs < *this); + } + + /// @brief comparison: less than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ + template + requires std::is_scalar_v + bool operator<=(ScalarType rhs) const noexcept + { + return *this <= basic_json(rhs); + } + + /// @brief comparison: greater than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) + bool operator>=(const_reference rhs) const noexcept + { + if (compares_unordered(rhs, true)) + { + return false; + } + return !(*this < rhs); + } + + /// @brief comparison: greater than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ + template + requires std::is_scalar_v + bool operator>=(ScalarType rhs) const noexcept + { + return *this >= basic_json(rhs); + } +#endif +#else + /// @brief comparison: equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + JSON_IMPLEMENT_OPERATOR( ==, true, false, false) +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } + + /// @brief comparison: equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, ScalarType rhs) noexcept + { + return lhs == basic_json(rhs); + } + + /// @brief comparison: equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ + template::value, int>::type = 0> + friend bool operator==(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) == rhs; + } + + /// @brief comparison: not equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + if (compares_unordered(lhs, rhs, true)) + { + return false; + } + return !(lhs == rhs); + } + + /// @brief comparison: not equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept + { + return lhs != basic_json(rhs); + } + + /// @brief comparison: not equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ + template::value, int>::type = 0> + friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) != rhs; + } + + /// @brief comparison: less than + /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + // default_result is used if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type)) + } + + /// @brief comparison: less than + /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, ScalarType rhs) noexcept + { + return lhs < basic_json(rhs); + } + + /// @brief comparison: less than + /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ + template::value, int>::type = 0> + friend bool operator<(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) < rhs; + } + + /// @brief comparison: less than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + if (compares_unordered(lhs, rhs, true)) + { + return false; + } + return !(rhs < lhs); + } + + /// @brief comparison: less than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept + { + return lhs <= basic_json(rhs); + } + + /// @brief comparison: less than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ + template::value, int>::type = 0> + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) <= rhs; + } + + /// @brief comparison: greater than + /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + // double inverse + if (compares_unordered(lhs, rhs)) + { + return false; + } + return !(lhs <= rhs); + } + + /// @brief comparison: greater than + /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, ScalarType rhs) noexcept + { + return lhs > basic_json(rhs); + } + + /// @brief comparison: greater than + /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ + template::value, int>::type = 0> + friend bool operator>(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) > rhs; + } + + /// @brief comparison: greater than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + if (compares_unordered(lhs, rhs, true)) + { + return false; + } + return !(lhs < rhs); + } + + /// @brief comparison: greater than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept + { + return lhs >= basic_json(rhs); + } + + /// @brief comparison: greater than or equal + /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ + template::value, int>::type = 0> + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) >= rhs; + } +#endif + +#undef JSON_IMPLEMENT_OPERATOR + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ +#ifndef JSON_NO_IO + /// @brief serialize to stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = o.width() > 0; + const auto indentation = pretty_print ? o.width() : 0; + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /// @brief serialize to stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ + /// @deprecated This function is deprecated since 3.0.0 and will be removed in + /// version 4.0.0 of the library. Please use + /// operator<<(std::ostream&, const basic_json&) instead; that is, + /// replace calls like `j >> o;` with `o << j;`. + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } +#endif // JSON_NO_IO + /// @} + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /// @brief deserialize from a compatible input + /// @sa https://json.nlohmann.me/api/basic_json/parse/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(InputType&& i, + parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::forward(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded] + return result; + } + + /// @brief deserialize from a pair of character iterators + /// @sa https://json.nlohmann.me/api/basic_json/parse/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(IteratorType first, + IteratorType last, + parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] + return result; + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) + static basic_json parse(detail::span_input_adapter&& i, + parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved] + return result; + } + + /// @brief check if the input is valid JSON + /// @sa https://json.nlohmann.me/api/basic_json/accept/ + template + static bool accept(InputType&& i, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); + } + + /// @brief check if the input is valid JSON + /// @sa https://json.nlohmann.me/api/basic_json/accept/ + template + static bool accept(IteratorType first, IteratorType last, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) + static bool accept(detail::span_input_adapter&& i, + const bool ignore_comments = false) + { + return parser(i.get(), nullptr, false, ignore_comments).accept(true); + } + + /// @brief generate SAX events + /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ + template + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(InputType&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::forward(i)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); + } + + /// @brief generate SAX events + /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ + template + JSON_HEDLEY_NON_NULL(3) + static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::move(first), std::move(last)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); + } + + /// @brief generate SAX events + /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ + /// @deprecated This function is deprecated since 3.8.0 and will be removed in + /// version 4.0.0 of the library. Please use + /// sax_parse(ptr, ptr + len) instead. + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = i.get(); + return format == input_format_t::json + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + : detail::binary_reader(std::move(ia), format).sax_parse(format, sax, strict); + } +#ifndef JSON_NO_IO + /// @brief deserialize from stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ + /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in + /// version 4.0.0 of the library. Please use + /// operator>>(std::istream&, basic_json&) instead; that is, + /// replace calls like `j << i;` with `i >> j;`. + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /// @brief deserialize from stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } +#endif // JSON_NO_IO + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /// @brief return the type as string + /// @sa https://json.nlohmann.me/api/basic_json/type_name/ + JSON_HEDLEY_RETURNS_NON_NULL + const char* type_name() const noexcept + { + switch (m_data.m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::binary: + return "binary"; + case value_t::discarded: + return "discarded"; + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + default: + return "number"; + } + } + + JSON_PRIVATE_UNLESS_TESTED: + ////////////////////// + // member variables // + ////////////////////// + + struct data + { + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + data(const value_t v) + : m_type(v), m_value(v) + { + } + + data(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + } + + data() noexcept = default; + data(data&&) noexcept = default; + data(const data&) noexcept = delete; + data& operator=(data&&) noexcept = delete; + data& operator=(const data&) noexcept = delete; + + ~data() noexcept + { + m_value.destroy(m_type); + } + }; + + data m_data = {}; + +#if JSON_DIAGNOSTICS + /// a pointer to a parent value (for debugging purposes) + basic_json* m_parent = nullptr; +#endif + +#if JSON_DIAGNOSTIC_POSITIONS + /// the start position of the value + std::size_t start_position = std::string::npos; + /// the end position of the value + std::size_t end_position = std::string::npos; + public: + constexpr std::size_t start_pos() const noexcept + { + return start_position; + } + + constexpr std::size_t end_pos() const noexcept + { + return end_position; + } +#endif + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /// @brief create a CBOR serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + /// @brief create a CBOR serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /// @brief create a CBOR serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /// @brief create a MessagePack serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + /// @brief create a MessagePack serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /// @brief create a MessagePack serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /// @brief create a UBJSON serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) + { + std::vector result; + to_ubjson(j, result, use_size, use_type); + return result; + } + + /// @brief create a UBJSON serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + /// @brief create a UBJSON serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + /// @brief create a BJData serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ + static std::vector to_bjdata(const basic_json& j, + const bool use_size = false, + const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) + { + std::vector result; + to_bjdata(j, result, use_size, use_type, version); + return result; + } + + /// @brief create a BJData serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ + static void to_bjdata(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) + { + binary_writer(o).write_ubjson(j, use_size, use_type, true, true, version); + } + + /// @brief create a BJData serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ + static void to_bjdata(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false, + const bjdata_version_t version = bjdata_version_t::draft2) + { + binary_writer(o).write_ubjson(j, use_size, use_type, true, true, version); + } + + /// @brief create a BSON serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ + static std::vector to_bson(const basic_json& j) + { + std::vector result; + to_bson(j, result); + return result; + } + + /// @brief create a BSON serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + /// @brief create a BSON serialization of a given JSON value + /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + /// @brief create a JSON value from an input in CBOR format + /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + auto ia = detail::input_adapter(std::forward(i)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in CBOR format + /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + auto ia = detail::input_adapter(std::move(first), std::move(last)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in MessagePack format + /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::forward(i)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in MessagePack format + /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::move(first), std::move(last)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_msgpack(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in UBJSON format + /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::forward(i)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in UBJSON format + /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::move(first), std::move(last)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_ubjson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in BJData format + /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bjdata(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::forward(i)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in BJData format + /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bjdata(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::move(first), std::move(last)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in BSON format + /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::forward(i)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + /// @brief create a JSON value from an input in BSON format + /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = detail::input_adapter(std::move(first), std::move(last)); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + auto ia = i.get(); + detail::json_sax_dom_parser sdp(result, allow_exceptions); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] + return res ? result : basic_json(value_t::discarded); + } + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /// @brief access specified element via JSON Pointer + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + template::value, int> = 0> + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + reference operator[](const ::nlohmann::json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /// @brief access specified element via JSON Pointer + /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + template::value, int> = 0> + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + const_reference operator[](const ::nlohmann::json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /// @brief access specified element via JSON Pointer + /// @sa https://json.nlohmann.me/api/basic_json/at/ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + template::value, int> = 0> + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + reference at(const ::nlohmann::json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /// @brief access specified element via JSON Pointer + /// @sa https://json.nlohmann.me/api/basic_json/at/ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + template::value, int> = 0> + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) + const_reference at(const ::nlohmann::json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /// @brief return flattened JSON value + /// @sa https://json.nlohmann.me/api/basic_json/flatten/ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /// @brief unflatten a previously flattened JSON value + /// @sa https://json.nlohmann.me/api/basic_json/unflatten/ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /// @brief applies a JSON patch in-place without copying the object + /// @sa https://json.nlohmann.me/api/basic_json/patch/ + void patch_inplace(const basic_json& json_patch) + { + basic_json& result = *this; + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const string_t& op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, const basic_json & val) + { + // adding to the root of the target document means replacing it + if (ptr.empty()) + { + result = val; + return; + } + + // make sure the top element of the pointer exists + json_pointer const top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + // parent must exist when performing patch add per RFC6902 specs + basic_json& parent = result.at(ptr); + + switch (parent.m_data.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::template array_index(last_path); + if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); + } + + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + break; + } + + // if there exists a parent it cannot be primitive + case value_t::string: // LCOV_EXCL_LINE + case value_t::boolean: // LCOV_EXCL_LINE + case value_t::number_integer: // LCOV_EXCL_LINE + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [this, & result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_HEDLEY_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this)); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(json_pointer::template array_index(last_path)); + } + }; + + // type check: top level value must be an array + if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch)); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const string_t& op, + const string_t& member, + bool string_type) -> basic_json & + { + // find value + auto it = val.m_data.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable) + + // check if desired value is present + if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) + { + // NOLINTNEXTLINE(performance-inefficient-string-concatenation) + JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); + } + + // check if result is of type string + if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) + { + // NOLINTNEXTLINE(performance-inefficient-string-concatenation) + JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_HEDLEY_UNLIKELY(!val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val)); + } + + // collect mandatory members + const auto op = get_value("op", "op", true).template get(); + const auto path = get_value(op, "path", true).template get(); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const auto from_path = get_value("move", "from", true).template get(); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json const v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const auto from_path = get_value("copy", "from", true).template get(); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json const v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_HEDLEY_UNLIKELY(!success)) + { + JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); + } + + break; + } + + case patch_operations::invalid: + default: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val)); + } + } + } + } + + /// @brief applies a JSON patch to a copy of the current object + /// @sa https://json.nlohmann.me/api/basic_json/patch/ + basic_json patch(const basic_json& json_patch) const + { + basic_json result = *this; + result.patch_inplace(json_patch); + return result; + } + + /// @brief creates a diff as a JSON patch + /// @sa https://json.nlohmann.me/api/basic_json/diff/ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json diff(const basic_json& source, const basic_json& target, + const string_t& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + return result; + } + + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() && i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', detail::to_string(i))); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // We now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", detail::concat(path, '/', detail::to_string(i))} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", detail::concat(path, "/-")}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto path_key = detail::concat(path, '/', detail::escape(it.key())); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path_key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path_key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto path_key = detail::concat(path, '/', detail::escape(it.key())); + result.push_back( + { + {"op", "add"}, {"path", path_key}, + {"value", it.value()} + }); + } + } + + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + + return result; + } + /// @} + + //////////////////////////////// + // JSON Merge Patch functions // + //////////////////////////////// + + /// @name JSON Merge Patch functions + /// @{ + + /// @brief applies a JSON Merge Patch + /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/ + void merge_patch(const basic_json& apply_patch) + { + if (apply_patch.is_object()) + { + if (!is_object()) + { + *this = object(); + } + for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) + { + if (it.value().is_null()) + { + erase(it.key()); + } + else + { + operator[](it.key()).merge_patch(it.value()); + } + } + } + else + { + *this = apply_patch; + } + } + + /// @} +}; + +/// @brief user-defined to_string function for JSON values +/// @sa https://json.nlohmann.me/api/basic_json/to_string/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) +{ + return j.dump(); +} + +inline namespace literals +{ +inline namespace json_literals +{ + +/// @brief user-defined string literal for JSON values +/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ +JSON_HEDLEY_NON_NULL(1) +#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + inline nlohmann::json operator ""_json(const char* s, std::size_t n) +#else + inline nlohmann::json operator "" _json(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::parse(s, s + n); +} + +/// @brief user-defined string literal for JSON pointer +/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ +JSON_HEDLEY_NON_NULL(1) +#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n) +#else + inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +#endif +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +} // namespace json_literals +} // namespace literals +NLOHMANN_JSON_NAMESPACE_END + +/////////////////////// +// nonmember support // +/////////////////////// + +namespace std // NOLINT(cert-dcl58-cpp) +{ + +/// @brief hash value for JSON objects +/// @sa https://json.nlohmann.me/api/basic_json/std_hash/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct hash // NOLINT(cert-dcl58-cpp) +{ + std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const + { + return nlohmann::detail::hash(j); + } +}; + +// specialization for std::less +template<> +struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679 +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(::nlohmann::detail::value_t lhs, + ::nlohmann::detail::value_t rhs) const noexcept + { +#if JSON_HAS_THREE_WAY_COMPARISON + return std::is_lt(lhs <=> rhs); // *NOPAD* +#else + return ::nlohmann::detail::operator<(lhs, rhs); +#endif + } +}; + +// C++20 prohibit function specialization in the std namespace. +#ifndef JSON_HAS_CPP_20 + +/// @brief exchanges the values of two JSON objects +/// @sa https://json.nlohmann.me/api/basic_json/std_swap/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) + is_nothrow_move_constructible::value&& // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + is_nothrow_move_assignable::value) +{ + j1.swap(j2); +} + +#endif + +} // namespace std + +#if JSON_USE_GLOBAL_UDLS + #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #else + using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) + using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) + #endif +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// restore clang diagnostic settings +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +// clean up +#undef JSON_ASSERT +#undef JSON_INTERNAL_CATCH +#undef JSON_THROW +#undef JSON_PRIVATE_UNLESS_TESTED +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT +#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL +#undef JSON_INLINE_VARIABLE +#undef JSON_NO_UNIQUE_ADDRESS +#undef JSON_DISABLE_ENUM_SERIALIZATION +#undef JSON_USE_GLOBAL_UDLS + +#ifndef JSON_TEST_KEEP_MACROS + #undef JSON_CATCH + #undef JSON_TRY + #undef JSON_HAS_CPP_11 + #undef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_17 + #undef JSON_HAS_CPP_20 + #undef JSON_HAS_CPP_23 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #undef JSON_HAS_THREE_WAY_COMPARISON + #undef JSON_HAS_RANGES + #undef JSON_HAS_STATIC_RTTI + #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#undef JSON_HEDLEY_ALWAYS_INLINE +#undef JSON_HEDLEY_ARM_VERSION +#undef JSON_HEDLEY_ARM_VERSION_CHECK +#undef JSON_HEDLEY_ARRAY_PARAM +#undef JSON_HEDLEY_ASSUME +#undef JSON_HEDLEY_BEGIN_C_DECLS +#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#undef JSON_HEDLEY_CLANG_HAS_FEATURE +#undef JSON_HEDLEY_CLANG_HAS_WARNING +#undef JSON_HEDLEY_COMPCERT_VERSION +#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#undef JSON_HEDLEY_CONCAT +#undef JSON_HEDLEY_CONCAT3 +#undef JSON_HEDLEY_CONCAT3_EX +#undef JSON_HEDLEY_CONCAT_EX +#undef JSON_HEDLEY_CONST +#undef JSON_HEDLEY_CONSTEXPR +#undef JSON_HEDLEY_CONST_CAST +#undef JSON_HEDLEY_CPP_CAST +#undef JSON_HEDLEY_CRAY_VERSION +#undef JSON_HEDLEY_CRAY_VERSION_CHECK +#undef JSON_HEDLEY_C_DECL +#undef JSON_HEDLEY_DEPRECATED +#undef JSON_HEDLEY_DEPRECATED_FOR +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#undef JSON_HEDLEY_DIAGNOSTIC_POP +#undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#undef JSON_HEDLEY_DMC_VERSION +#undef JSON_HEDLEY_DMC_VERSION_CHECK +#undef JSON_HEDLEY_EMPTY_BASES +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef JSON_HEDLEY_END_C_DECLS +#undef JSON_HEDLEY_FLAGS +#undef JSON_HEDLEY_FLAGS_CAST +#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_BUILTIN +#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_EXTENSION +#undef JSON_HEDLEY_GCC_HAS_FEATURE +#undef JSON_HEDLEY_GCC_HAS_WARNING +#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef JSON_HEDLEY_GCC_VERSION +#undef JSON_HEDLEY_GCC_VERSION_CHECK +#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#undef JSON_HEDLEY_GNUC_HAS_FEATURE +#undef JSON_HEDLEY_GNUC_HAS_WARNING +#undef JSON_HEDLEY_GNUC_VERSION +#undef JSON_HEDLEY_GNUC_VERSION_CHECK +#undef JSON_HEDLEY_HAS_ATTRIBUTE +#undef JSON_HEDLEY_HAS_BUILTIN +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_HAS_EXTENSION +#undef JSON_HEDLEY_HAS_FEATURE +#undef JSON_HEDLEY_HAS_WARNING +#undef JSON_HEDLEY_IAR_VERSION +#undef JSON_HEDLEY_IAR_VERSION_CHECK +#undef JSON_HEDLEY_IBM_VERSION +#undef JSON_HEDLEY_IBM_VERSION_CHECK +#undef JSON_HEDLEY_IMPORT +#undef JSON_HEDLEY_INLINE +#undef JSON_HEDLEY_INTEL_CL_VERSION +#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#undef JSON_HEDLEY_INTEL_VERSION +#undef JSON_HEDLEY_INTEL_VERSION_CHECK +#undef JSON_HEDLEY_IS_CONSTANT +#undef JSON_HEDLEY_IS_CONSTEXPR_ +#undef JSON_HEDLEY_LIKELY +#undef JSON_HEDLEY_MALLOC +#undef JSON_HEDLEY_MCST_LCC_VERSION +#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#undef JSON_HEDLEY_MESSAGE +#undef JSON_HEDLEY_MSVC_VERSION +#undef JSON_HEDLEY_MSVC_VERSION_CHECK +#undef JSON_HEDLEY_NEVER_INLINE +#undef JSON_HEDLEY_NON_NULL +#undef JSON_HEDLEY_NO_ESCAPE +#undef JSON_HEDLEY_NO_RETURN +#undef JSON_HEDLEY_NO_THROW +#undef JSON_HEDLEY_NULL +#undef JSON_HEDLEY_PELLES_VERSION +#undef JSON_HEDLEY_PELLES_VERSION_CHECK +#undef JSON_HEDLEY_PGI_VERSION +#undef JSON_HEDLEY_PGI_VERSION_CHECK +#undef JSON_HEDLEY_PREDICT +#undef JSON_HEDLEY_PRINTF_FORMAT +#undef JSON_HEDLEY_PRIVATE +#undef JSON_HEDLEY_PUBLIC +#undef JSON_HEDLEY_PURE +#undef JSON_HEDLEY_REINTERPRET_CAST +#undef JSON_HEDLEY_REQUIRE +#undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#undef JSON_HEDLEY_REQUIRE_MSG +#undef JSON_HEDLEY_RESTRICT +#undef JSON_HEDLEY_RETURNS_NON_NULL +#undef JSON_HEDLEY_SENTINEL +#undef JSON_HEDLEY_STATIC_ASSERT +#undef JSON_HEDLEY_STATIC_CAST +#undef JSON_HEDLEY_STRINGIFY +#undef JSON_HEDLEY_STRINGIFY_EX +#undef JSON_HEDLEY_SUNPRO_VERSION +#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#undef JSON_HEDLEY_TINYC_VERSION +#undef JSON_HEDLEY_TINYC_VERSION_CHECK +#undef JSON_HEDLEY_TI_ARMCL_VERSION +#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL2000_VERSION +#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL430_VERSION +#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL6X_VERSION +#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL7X_VERSION +#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CLPRU_VERSION +#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#undef JSON_HEDLEY_TI_VERSION +#undef JSON_HEDLEY_TI_VERSION_CHECK +#undef JSON_HEDLEY_UNAVAILABLE +#undef JSON_HEDLEY_UNLIKELY +#undef JSON_HEDLEY_UNPREDICTABLE +#undef JSON_HEDLEY_UNREACHABLE +#undef JSON_HEDLEY_UNREACHABLE_RETURN +#undef JSON_HEDLEY_VERSION +#undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#undef JSON_HEDLEY_VERSION_DECODE_MINOR +#undef JSON_HEDLEY_VERSION_DECODE_REVISION +#undef JSON_HEDLEY_VERSION_ENCODE +#undef JSON_HEDLEY_WARNING +#undef JSON_HEDLEY_WARN_UNUSED_RESULT +#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#undef JSON_HEDLEY_FALL_THROUGH + + + +#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/checkers/legality_h.cpp b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/checkers/legality_h.cpp new file mode 100644 index 0000000000..cb1233c7e9 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/checkers/legality_h.cpp @@ -0,0 +1,13 @@ +// Generalization (Dylan Crow, with Anthropic Claude assistance): the copied-centre count is the macro NCOPY, defaulting to +// HDIM, so the unmodified PR #346/#352 build (no -DNCOPY) is exactly the original checker. The E8 bit word has 9 +// retained totals at h = 8 (-DNCOPY=9). +#ifndef NCOPY +#define NCOPY HDIM +#endif +#include +#include "json.hpp" +#include +using namespace std;using nlohmann::json;struct Ev{int k,a,b,c,f,z;};struct F{int d;vector>B,A;};json ld(string p){json j;ifstream(p)>>j;return j;}int main(int ac,char**av){if(ac!=4)return 2;string in=av[1],out=av[2];auto st=ld(in+"/249-states.json"),fj=ld(in+"/frames.json"),nf=ld(out+"/COHORT249-FRAMES.json"),ii=ld(out+"/COHORT249-INITIAL.json"),sel=ld(out+"/COHORT249-SELECTION.json"),own=ld(in+"/249-DONOR-OWNERSHIP.json");int n=st["n"],v=st["v"],zero=st["ZERO"];mapfs;long long maxabs=0;int oldmax=0;for(auto it=fj["frames"].begin();it!=fj["frames"].end();++it){int k=stoi(it.key());oldmax=max(oldmax,k);F f{it.value()["dim"],it.value()["B"],it.value()["A"]};for(auto M:{f.B,f.A})for(auto r:M)for(auto x:r)maxabs=max(maxabs,llabs(x));fs[k]=f;}for(auto it=nf.begin();it!=nf.end();++it){int k=stoi(it.key());if(fs.count(k))throw runtime_error("new frame collides");fs[k]={it.value()["dim"],it.value()["B"],it.value()["A"]};}map,bool>cache;long long contain=0;auto sub=[&](int a,int b){if(!fs.count(a)||!fs.count(b))throw runtime_error("unknown frame");auto k=make_pair(a,b);if(cache.count(k))return cache[k];contain++;bool ok=fs[a].d<=fs[b].d;for(auto r:fs[a].B)for(auto s:fs[b].A){boost::multiprecision::cpp_int d=0;for(int i=0;iowners,donors,chosen;for(auto x:st["source_owned_roles"])owners.insert(x.get());for(auto x:own["donor_keys"])donors.insert(x.get());setpivots,partners;for(auto s:sel){int p=s["a"];if(!pivots.insert(p).second)throw runtime_error("repeated pivot");for(int r:s["partners"])partners.insert(r);}for(int p:pivots)if(partners.count(p))throw runtime_error("basis support is not square zero");for(auto s:sel){vectormembers=s["partners"].get>();members.push_back(s["a"]);for(int p:members){if(p<2*v||p>=n)throw runtime_error("invalid or overlapping helper");chosen.insert(p);int role=st["regs"][p-2*v];if(owners.count(role)||donors.count(role))throw runtime_error("source owner or donor selected");}int id=s["new_frame_id"];auto f=fs.at(id);if(f.d!=s["E_dimension"]||f.B.size()!=f.d||f.A.size()!=HDIM-f.d)throw runtime_error("wrong new rank");for(auto r:f.A)for(auto b:f.B){boost::multiprecision::cpp_int d=0;for(int k=0;kstate(n+1,zero);for(auto it=ii.begin();it!=ii.end();++it)state[stoi(it.key())]=it.value();bool copied=false;int copySource=-1;long long mov=0,adds=0,cop=0,era=0,mass=0;maphist;Ev e;ifstream f(out+"/COHORT249-RECORDS.bin",ios::binary);long long records=0;while(f.read((char*)&e,sizeof e)){records++;if(e.a<0||e.a>n||(e.k!=0&&(e.b<0||e.b>n)))throw runtime_error("bad role id");if(e.k==0){if(e.a==n&&!copied)throw runtime_error("move inactive temporary");if(state[e.a]!=e.b||!sub(e.b,e.c)||fs[e.c].d-fs[e.b].d!=e.f)throw runtime_error("illegal or mispriced MOVE");state[e.a]=e.c;if(e.f){hist[e.f]++;mass+=e.f;}mov++;}else if(e.k==1){if(state[e.a]!=e.f||state[e.b]!=e.f)throw runtime_error("ADD not in common frame");if((e.a==n||e.b==n)&&!copied)throw runtime_error("ADD inactive temporary");if(e.a==e.b)throw runtime_error("self ADD");if(copied&&(e.a==copySource||e.a==n))throw runtime_error("copied source or temporary mutated inside COPY window");adds++;}else if(e.k==2){if(copied||e.b!=n||state[e.a]!=e.c)throw runtime_error("invalid COPY lifecycle");if(e.z!=fs[e.c].d)throw runtime_error("COPY rank");copied=true;copySource=e.a;state[n]=e.f;hist[e.z]++;mass+=e.z;cop++;}else if(e.k==3){if(!copied||e.b!=n||e.a!=copySource||state[e.a]!=e.c||state[n]!=e.f)throw runtime_error("invalid ERASE lifecycle");copied=false;era++;}else throw runtime_error("unknown event");}if(copied||cop!=NCOPY||era!=NCOPY)throw runtime_error("unclosed COPY");for(int s=0;s left[f]: continue + rest = dict(left); rest[f] -= q*b + t + found = search(i + 1, rest, out + ([(tuple([w]*a + [f]*b), q)] if q else []) + ([(tuple([w]*r + [f]*t), 1)] if r else [])) + if found is not None: return found + return None + out = search(0, {w: n for w, n in blocks.items() if not m % w}, []) + assert out is not None, ('no exact zero-padding tiling', blocks, m) + used = Counter() + for widths, count in out: + assert sum(widths) == m and count > 0 + for x in widths: used[x] += count + assert used == Counter(blocks), 'every block used exactly once' + return tuple(out) +d = sys.argv[1]; h = int(sys.argv[2]) if len(sys.argv) > 2 else 20; m = 5*h; replicas = int(sys.argv[3]) if len(sys.argv) > 3 else 60 +s = json.load(open(d + '/249-states.json')); fr = json.load(open(d + '/frames.json')) +dim = {int(k): len(v['B']) for k, v in fr['frames'].items()}; v = s['v']; n = s['n'] +res = Counter(h - dim[s['initial'][str(r)]] for r in range(2*v, n)) +pat = tile({r: replicas*c for r, c in res.items() if r > 0}, m) +print('residual census', dict(sorted(res.items())), '| freed roles (r = 0) are deleted, not banked') +print('PASS exact width-%d tiling with %d replicas:' % (m, replicas), pat) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/export_records.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/export_records.py new file mode 100644 index 0000000000..3632d37048 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/export_records.py @@ -0,0 +1,72 @@ +"""Export a bitE8/1 word to the PR249 record format read by PR #266's official cohort checkers and PR #315's engines. +usage: python3 export_records.py word.json[.gz] OUTDIR -> OUTDIR/{249-records.bin,249-states.json,frames.json} +Records are int32 six-tuples: MOVE(0,role,old,new,rank,0), ADD(1,dst,src,1,frame,phase), COPY(2,centre,temp,frame,ZERO,rank), +ERASE(3,centre,temp,frame,ZERO,0). A multi-source gate becomes one ADD per source, preceded by the MOVEs of every +register of the gate to the gate frame. Frames: integer basis rows B (label vectors of the frame's root lines in the +word's coordinates, a rational basis) and integer annihilator rows A (standard dot product), as PR #266 expects. +Dylan Crow, with Anthropic Claude assistance; Apache-2.0.""" +import sys, json, gzip, struct, os +from fractions import Fraction as Fr +from math import gcd +def load(p): + with (gzip.open(p,'rt') if p.endswith('.gz') else open(p)) as f: return json.load(f) +c=load(sys.argv[1]); out=sys.argv[2]; os.makedirs(out,exist_ok=True) +v,R,h=c['v'],c['R'],c['h']; n=2*v+R; lines=c['lines'] +def basis(idx): + rows=[]; piv=[]; B=[] + for i in idx: + x=[Fr(a) for a in lines[i]] + for p,r in zip(piv,rows): + if x[p]: f=x[p]/r[p]; x=[a-f*b for a,b in zip(x,r)] + nz=[k for k in range(h) if x[k]] + if nz: rows.append(x); piv.append(nz[0]); B.append(list(lines[i])) + return B,rows,piv +def annihilator(rows,piv): + # rows in echelon (pivot columns piv); free columns give the null space of the row space under the dot product + # reduce to RREF + R_=[r[:] for r in rows] + for i,(p,r) in enumerate(zip(piv,R_)): + R_[i]=[a/r[p] for a in r] + for i,p in enumerate(piv): + for j in range(len(R_)): + if j!=i and R_[j][p]: f=R_[j][p]; R_[j]=[a-f*b for a,b in zip(R_[j],R_[i])] + free=[k for k in range(h) if k not in piv]; A=[] + for f in free: + a=[Fr(0)]*h; a[f]=Fr(1) + for i,p in enumerate(piv): a[p]=-R_[i][f] + L=1 + for x in a: L=L*x.denominator//gcd(L,x.denominator) + ai=[int(x*L) for x in a]; g=0 + for x in ai: g=gcd(g,abs(x)) + A.append([x//g for x in ai]) + return A +frames={} +for k,idx in enumerate(c['frames']): + B,rows,piv=basis(idx); A=annihilator(rows,piv) if B else [[int(i==j) for j in range(h)] for i in range(h)] + assert all(sum(a*b for a,b in zip(x,y))==0 for x in A for y in B) and len(A)+len(B)==h + frames[str(k)]=dict(dim=len(B),B=B,A=A) +dim=[frames[str(k)]['dim'] for k in range(len(c['frames']))] +ZERO=[k for k in range(len(dim)) if dim[k]==0]; assert len(ZERO)==1; ZERO=ZERO[0] +cur=list(c['start']); rec=[] +def move(r,f): + if cur[r]!=f: rec.append((0,r,cur[r],f,dim[f]-dim[cur[r]],0)); cur[r]=f +def run(gates,ph): + for f,d,srcs in gates: + for r in [d]+srcs: move(r,f) + for s in srcs: rec.append((1,d,s,1,f,ph)) +run(c['D'],1); run(c['A'],2) +temp=n +for k,q in enumerate(c['ret']): + fq=cur[q]; rec.append((2,q,temp,fq,ZERO,dim[fq])) + for t,row in enumerate(c['scatter']): + if k in row: rec.append((1,v+t,temp,1,ZERO,3)) + rec.append((3,q,temp,fq,ZERO,0)) +run(c['B'],4); run(c['C'],5) +for r in range(n): move(r,c['final'][r]) +with open(out+'/249-records.bin','wb') as f: + for e in rec: f.write(struct.pack('<6i',*e)) +st=dict(n=n,v=v,h=h,R=R,ZERO=ZERO,initial={str(r):c['start'][r] for r in range(n)},final={str(r):c['final'][r] for r in range(n)}, + retained_totals=c['ret'],source_owned_roles=[],regs=[]) +json.dump(st,open(out+'/249-states.json','w'),sort_keys=True,separators=(',',':')) +json.dump(dict(frames=frames),open(out+'/frames.json','w'),sort_keys=True,separators=(',',':')) +print('exported',len(rec),'records,',len(frames),'frames, n',n,'ZERO',ZERO) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/independent/centres_sat.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/independent/centres_sat.py new file mode 100644 index 0000000000..efbcef69dd --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/independent/centres_sat.py @@ -0,0 +1,34 @@ +"""Dylan Crow, with Anthropic Claude assistance, Apache-2.0. usage: centres_sat.py k seconds (k = 8: INFEASIBLE, k = 9: feasible) +Is there an F2 decoder of rank k (k centres) for the bit-E8 labels? Need w_S, u_t in F2^k with +=1 and =0 for every neighbour S (||=1). CP-SAT.""" +import sys, time +import os; sys.path.insert(0,os.path.join(os.path.dirname(os.path.abspath(__file__)),'..','producer')); os.environ.pop('E8COORD',None) +import e8lib as E +from ortools.sat.python import cp_model +V=E.V; k=int(sys.argv[1]); tl=float(sys.argv[2]) +clique=[0, 2, 6, 8, 56, 57, 64, 65] +assert all(abs(E.G[a][b])==1 for a in clique for b in clique if a!=b), 'clique of pairwise neighbours' +# WLOG normalization: A restricted to a neighbour clique is the identity, so w and u of the clique are dual bases; +# GL(k, 2) acts on (w, u) preserving every , so they may be taken to be the standard basis. +m=cp_model.CpModel() +w=[[m.NewBoolVar('w%d_%d'%(s,i)) for i in range(k)] for s in range(V)] +u=[[m.NewBoolVar('u%d_%d'%(s,i)) for i in range(k)] for s in range(V)] +for j,c in enumerate(clique[:k]): + for i in range(k): + m.Add(w[c][i]==(1 if i==j else 0)); m.Add(u[c][i]==(1 if i==j else 0)) +for t in range(V): + for S in [t]+E.NEIGH[t]: + ps=[] + for i in range(k): + p=m.NewBoolVar('') + m.AddBoolAnd([u[t][i],w[S][i]]).OnlyEnforceIf(p) + m.AddBoolOr([u[t][i].Not(),w[S][i].Not()]).OnlyEnforceIf(p.Not()) + ps.append(p) + if S==t: m.AddBoolXOr(ps) # odd + else: m.AddBoolXOr(ps+[m.NewConstant(1)]) # even +sol=cp_model.CpSolver(); sol.parameters.max_time_in_seconds=tl; sol.parameters.num_workers=2 +t0=time.time(); r=sol.Solve(m) +print('k',k,'status',sol.StatusName(r),'%.0fs'%(time.time()-t0)) +if r in (cp_model.OPTIMAL,cp_model.FEASIBLE): + W=[[sol.Value(w[s][i]) for i in range(k)] for s in range(V)] + U=[[sol.Value(u[s][i]) for i in range(k)] for s in range(V)] diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/independent/checkword.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/independent/checkword.py new file mode 100644 index 0000000000..da4e0fe050 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/independent/checkword.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +"""Dylan Crow, with Anthropic Claude assistance; Apache-2.0. +usage: checkword.py WORD.json.gz PRICING_DIR +Independent checker for 'bitE8/1' bit words (no import of the design/compile code). +Checks: (1) labels are the 120 root lines of an even unimodular rank-8 lattice (E8); +(2) frame legality: every register's frames nested (exact rational ranks), every gate at one common frame, + retained totals present and y at frame 0 at the scatter, start/final frames as required; +(3) exact F2 semantics on all 2v+R columns (x, y, helper dirt): y_t += x_t, x and helpers restored; +(4) Gram determinants of every frame basis (nondegeneracy) and their prime factors; +(5) five-stage price: histogram, deficit, exact moment root (repo's moment.certify, with and without + the inherited 1e-16 bad envelope).""" +import sys, json, gzip, math +from fractions import Fraction as Fr +from collections import Counter +def load(p): + with (gzip.open(p,'rt') if p.endswith('.gz') else open(p)) as f: return json.load(f) +c=load(sys.argv[1]) +v,h,R=c['v'],c['h'],c['R']; nreg=2*v+R +lines=[tuple(x) for x in c['lines']] +den=2 if c['form']=='/2' else 4 +def ip(a,b): + s=sum(x*y for x,y in zip(a,b)); assert s%den==0; return s//den +# (1) labels +assert len(lines)==v==120 and h==8 +assert all(ip(a,a)==2 for a in lines) +assert all(abs(ip(lines[i],lines[j]))<=1 for i in range(v) for j in range(i+1,v)), 'not distinct root lines' +def rank(vecs): + rows=[[Fr(x) for x in r] for r in vecs]; rk=0; n=len(rows[0]) if rows else 0 + for col in range(n): + p=next((i for i in range(rk,len(rows)) if rows[i][col]!=0),None) + if p is None: continue + rows[rk],rows[p]=rows[p],rows[rk] + for i in range(len(rows)): + if i!=rk and rows[i][col]!=0: + f=rows[i][col]/rows[rk][col]; rows[i]=[a-f*b for a,b in zip(rows[i],rows[rk])] + rk+=1 + return rk +def basis(idx): + B=[] + for i in idx: + if rank([lines[j] for j in B]+[lines[i]])>len(B): B.append(i) + return B +def det(M): + M=[[Fr(x) for x in r] for r in M]; n=len(M); d=Fr(1) + for col in range(n): + p=next((i for i in range(col,n) if M[i][col]!=0),None) + if p is None: return Fr(0) + if p!=col: M[col],M[p]=M[p],M[col]; d=-d + d*=M[col][col] + for i in range(col+1,n): + f=M[i][col]/M[col][col]; M[i]=[a-f*b for a,b in zip(M[i],M[col])] + return d +full=basis(range(v)); assert len(full)==8 +G8=det([[ip(lines[a],lines[b]) for b in full] for a in full]) +# lattice generated by roots: unimodular check via a Z-basis is heavier; we check det of Gram of an integral basis +# found greedily among roots whose Gram has det 1 (exists for E8) +import itertools +print('labels: 120 distinct lines of norm 2 (pairwise |ip| <= 1), spanning rank 8') +# (2) frames +fr=c['frames'] +fb=[basis(f) for f in fr] +fdim=[len(b) for b in fb] +assert fdim[c['start'][v]]==0 +FULLID=[i for i,d in enumerate(fdim) if d==8] +def inside(a,b): + if fdim[a]>fdim[b]: return False + return rank([lines[j] for j in fb[a]+fb[b]])==fdim[b] +cache={} +def nested(a,b): + k=(a,b) + if k not in cache: cache[k]=inside(a,b) + return cache[k] +cur=list(c['start']); steps=[[] for _ in range(nreg)] +for r in range(v): assert fdim[cur[r]]==1 and rank([lines[r]]+[lines[j] for j in fb[cur[r]]])==1, 'x start is its line' +for r in range(v,nreg): assert fdim[cur[r]]==0 +def climb(r,f): + if cur[r]==f: return + assert nested(cur[r],f) and fdim[cur[r]]=v for x in [d]), ('x register written',tag,k) # x registers are never destinations + for x in regs: climb(x,f) + for s in srcs: val[d]^=val[s] +run(c['D'],'D') +assert all(fdim[cur[r]]==0 for r in range(v,nreg)),'dirt compensation must be at frame 0' +run(c['A'],'A') +# scatter +ret=c['ret']; cent_rank=[] +for q in ret: assert q>=2*v; cent_rank.append(fdim[cur[q]]) +assert all(fdim[cur[v+t]]==0 for t in range(v)),'y left frame 0 before the scatter' +copies=[val[q] for q in ret] +for t,row in enumerate(c['scatter']): + for k in row: val[v+t]^=copies[k] +run(c['B'],'B') +run(c['C'],'C') +for r in range(nreg): climb(r,c['final'][r]) +for r in range(v): assert fdim[c['final'][r]]==8 +for t in range(v): + f=c['final'][v+t]; assert fdim[f]==7 + assert all(ip(lines[t],lines[j])==0 for j in fb[f]),'y final frame is the cap of its label' +for r in range(2*v,nreg): assert fdim[c['final'][r]]==8 +# (3) F2 semantics +for s in range(v): assert val[s]==1<1: out[n]+=1 + return out +for f in used: + if fdim[f]==0: continue + B=fb[f]; d=det([[ip(lines[a],lines[b]) for b in B] for a in B]) + assert d>0 + dets[f]=d + for p in factor(d.numerator): primes[p]+=1 +print('nondegeneracy: %d used frames, all Gram dets > 0 (positive-definite form); primes in dets:'%len(dets),sorted(primes)) +# (5) price +H=Counter() +for r in range(nreg): + for s in steps[r]: H[s]+=5 +for rk in cent_rank: H[rk]+=5 +for rr in (2*h-2,h-1,2*h+2,4): H[rr]+=2*v +m=5*h; W=4*v+R +mass=sum(r*n for r,n in H.items()) +L=sum(cent_rank) +print('histogram',dict(sorted(H.items())),'m',m,'W',W,'mass',mass,'deficit',m*W-mass,'(4v-5L =',4*v-5*L,')','maxchild',max(H)) +assert m*W-mass==4*v-5*L and 2*max(H)3: + g[0]=c['start'][0]; break + return 'phase-A gate frame not nested' +for f in (m1,m2,m3,m4,m5,m6): + cc=copy.deepcopy(c); name=f(cc) + tmp=os.path.join(tempfile.mkdtemp(),'mut.json.gz') + with gzip.open(tmp,'wt') as fh: json.dump(cc,fh) + r=subprocess.run([sys.executable,'-B',os.path.join(HERE,'checkword.py'),tmp,sys.argv[2]],capture_output=True,text=True) + ok=r.returncode!=0 + assert ok, 'mutant accepted: '+name + print(('REJECTED ' if ok else 'ACCEPTED!! ')+name+' :: '+(r.stderr.strip().splitlines()[-1][:100] if ok else '')) +print('PASS all 6 word-level negative controls rejected') diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/mutate_records.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/mutate_records.py new file mode 100644 index 0000000000..6794516f66 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/mutate_records.py @@ -0,0 +1,34 @@ +"""Negative controls for the official checkers on the exported E8 records: every mutant must be rejected. +usage: mutate_records.py RECORDDIR COHORT_IN COHORT_OUT LEGALITY_BIN COLUMNS_BIN LEGALITY_NCOPY8_BIN""" +import sys, struct, shutil, subprocess, os +rd,cin,cout,leg,col,leg8=sys.argv[1:7] +rec=bytearray(open(rd+'/249-records.bin','rb').read()); n=len(rec)//24 +get=lambda i: list(struct.unpack_from('<6i',rec,24*i)) +def run(mut,which): + tmp=cout+'-mut'; shutil.rmtree(tmp,ignore_errors=True); shutil.copytree(cout,tmp) + open(tmp+'/COHORT249-RECORDS.bin','wb').write(bytes(mut)) + if which=='legality': r=subprocess.run([leg,cin,tmp,tmp+'/x.json'],capture_output=True,text=True) + elif which=='legality8': r=subprocess.run([leg8,cin,tmp,tmp+'/x.json'],capture_output=True,text=True) + else: r=subprocess.run([col,tmp+'/COHORT249-RECORDS.bin',tmp+'/x.json'],capture_output=True,text=True) + shutil.rmtree(tmp,ignore_errors=True) + return r.returncode!=0, (r.stderr.strip().splitlines() or ['?'])[-1][:70] +def mutate(pred,change): + m=bytearray(rec) + for i in range(n): + e=get(i) + if pred(e,i): + change(e); struct.pack_into('<6i',m,24*i,*e); return m + raise SystemExit('no mutation site') +B4=[i for i in range(n) if get(i)[0]==1 and get(i)[5]==4] +cases=[('drop a phase-B delivery ADD (columns: defining decoder)','columns',bytes(rec[:24*B4[len(B4)//2]]+rec[24*(B4[len(B4)//2]+1):])), + ('ADD at a frame its registers do not stand at','legality',mutate(lambda e,i:e[0]==1 and e[5]==4,lambda e:e.__setitem__(4,0))), + ('MOVE with a wrong rank','legality',mutate(lambda e,i:e[0]==0 and e[4]>1,lambda e:e.__setitem__(4,e[4]-1))), + ('COPY with a cheaper rank','legality',mutate(lambda e,i:e[0]==2,lambda e:e.__setitem__(5,7))), + ('drop a dirt-compensation ADD (columns)','columns',bytes(rec[:24*[i for i in range(n) if get(i)[0]==1 and get(i)[5]==1][0]]+rec[24*([i for i in range(n) if get(i)[0]==1 and get(i)[5]==1][0]+1):])), + ('unchanged word with the copy count pinned to h = 8 (NCOPY unset)','legality8',bytes(rec))] +ok=True +for name,which,m in cases: + rej,msg=run(m,which); ok&=rej + print((' REJECTED ' if rej else ' ACCEPTED!! ')+name+' ['+msg+']') +assert ok, 'a mutant was accepted' +print('PASS all %d record-level negative controls rejected'%len(cases)) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/compile.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/compile.py new file mode 100644 index 0000000000..86b12507ef --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/compile.py @@ -0,0 +1,201 @@ +"""Dylan Crow, with Anthropic Claude assistance; Apache-2.0. Compile a Re-Pair hierarchy into an explicit bit word (frames = root masks) and price it. +Registers: x 0..119, y 120..239, helpers 240.. . Gate: (phase, frame, dst, [srcs]) dst += sum(srcs) over F2.""" +import e8lib as E, frames as Fm, price as P +from collections import defaultdict, Counter +V=E.V +class Word: + def __init__(self): + self.nh=0; self.A=[]; self.B=[]; self.ret=[] + def helper(self): + r=2*V+self.nh; self.nh+=1; return r +def X(s): return s +def Y(t): return V+t +def compile_h(h, low=True, drop=frozenset(), centres=None): + need=h.need + needed=set(); todo=[u for t in range(V) for u in need[t]] + while todo: + u=todo.pop() + if u in needed: continue + needed.add(u) + if h.kids[u]: todo.extend(h.kids[u]) + rules=sorted((u for u in needed if h.kids[u]), key=lambda u:(h.dim[u],u)) + # low reads: longest nested chain of needed symbols per target + lowset=set() + if low: + for t in range(V): + it=sorted(need[t], key=lambda u:(h.dim[u],u)); best={} + for j,u in enumerate(it): + b=[u] + for i in range(j): + v=it[i] + if (h.dim[v]len(b): b=best[v]+[u] + best[u]=b + ch=max(best.values(),key=len) if best else [] + for u in ch: + if h.dim[u]<7 and (t,u) not in drop: lowset.add((t,u)) + uses=defaultdict(list) + for w in rules: + for c in h.kids[w]: uses[c].append((0,h.dim[w],h.frame[w],w)) + for t in range(V): + for u in need[t]: + if (t,u) in lowset: uses[u].append((1,h.dim[u],h.frame[u],t)) + else: uses[u].append((1,7,Fm.HYP[t],t)) + chains={}; chain_of={} + for u in needed: + ev=sorted(uses[u]); cl=[] + for e in ev: + best=None + for i,ch in enumerate(cl): + last=ch[-1] + if last[0]==1 and last[1]==7 and last[2]!=e[2]: continue + if last[2]==e[2] or (last[1]=2*V: host=(c,i); break + if host: + q=reg.pop(host); srcs=[reg[(c,i)] for c,i,_ in info if (c,i)!=host] + W.A.append((F,q,srcs,None)); inplace+=1 + else: + q=W.helper(); W.A.append((F,q,[reg[(c,i)] for c,i,_ in info],None)) + reg[(w,0)]=q + n=len(chains[w]) + if n>1: + qs=[W.helper() for _ in range(n-1)] + W.A.append((F,q,None,qs)) + for i,qq in enumerate(qs): reg[(w,i+1)]=qq + # totals + cent=centres or default_centres() + for sup in cent: + q=W.helper(); W.A.append((Fm.FULL,q,[X(s) for s in range(V) if sup>>s&1],None)); W.ret.append(q) + # phase B: deliveries sorted by frame dim + ev=[] + for t in range(V): + hyp=[] + for u in need[t]: + r=reg[(u,chain_of[(u,1,t)])] + if (t,u) in lowset: ev.append((h.dim[u],h.frame[u],Y(t),[r])) + else: hyp.append(r) + if hyp: ev.append((7,Fm.HYP[t],Y(t),hyp)) + ev.sort(key=lambda e:(e[0],e[2])) + for d,F,yt,srcs in ev: W.B.append((F,yt,srcs,None)) + W.stats=dict(R=W.nh,rules=len(rules),inplace=inplace,low=len(lowset),chains=sum(len(c) for c in chains.values())) + return W +_DC=None +def default_centres(): + """T0 = all lines; T_i = {S : B(a_i,S)=1} for a basis a_i of E8/2E8 given by 8 lines spanning it mod 2.""" + global _DC + if _DC: return _DC + # pick 8 lines whose images are independent mod 2 : use B-matrix rank + B=[[E.G[a][b]&1 for b in range(V)] for a in range(V)] + rows=[]; basis=[]; piv={} + for a in range(V): + m=sum(B[a][b]<=V: get(u) + return ph +def choose_low(h, needed, ph, drop=frozenset(), mode='longest'): + lowset=set() + for t in range(V): + it=sorted(h.need[t], key=lambda u:(h.dim[u],u)); best={} + for j,u in enumerate(it): + b=[u] + for i in range(j): + v=it[i] + if h.dim[v]len(b): b=best[v]+[u] + best[u]=b + ch=max(best.values(),key=len) if best else [] + for u in ch: + if h.dim[u]<7 and (t,u) not in drop: lowset.add((t,u)) + return lowset +def compile2(h, lowset=None, drop=frozenset(), centres=None): + needed=needed_symbols(h); ph=phases(h,needed) + if lowset is None: lowset=choose_low(h,needed,ph,drop) + # uses: (phaseorder, dim, kind, frame, who) phaseorder 0=A 1=B ; kind 0 rule-child 1 delivery + uses=defaultdict(list) + for w in needed: + if w=2*V) + inplace=[0]; ncopy=[0] + def form(w,lst): + F=h.frame[w]; info=[] + for c in h.kids[w]: + i=chain_of[(c,0,w)]; ch=chains[c][i] + info.append((c,i,ch[-1][2]==0 and ch[-1][4]==w)) + host=None + for c,i,end in info: + if end and reg[(c,i)]>=2*V: host=(c,i); break + if host: + q=reg.pop(host); lst.append((F,q,[reg[(c,i)] for c,i,_ in info if (c,i)!=host],None)); inplace[0]+=1 + else: + q=W.helper(); lst.append((F,q,[reg[(c,i)] for c,i,_ in info],None)) + reg[(w,0)]=q; n=len(chains[w]) + if n>1: + qs=[W.helper() for _ in range(n-1)]; ncopy[0]+=n-1 + lst.append((F,q,None,qs)) + for i,qq in enumerate(qs): reg[(w,i+1)]=qq + Arules=sorted((w for w in needed if w>=V and ph[w]=='A'),key=lambda w:(h.dim[w],w)) + for w in Arules: form(w,W.A) + cent=centres or C.default_centres() + for sup in cent: + q=W.helper(); W.A.append((Fm.FULL,q,[C.X(s) for s in range(V) if sup>>s&1],None)); W.ret.append(q) + # phase B events + ev=[] + for w in needed: + if w>=V and ph[w]=='B': ev.append((h.dim[w],0,w)) + lowby=defaultdict(list) + for (t,u) in lowset: lowby[u].append(t) + for u in lowby: ev.append((h.dim[u],1,u)) + for t in range(V): ev.append((7,2,t)) + ev.sort() + for d,k,a in ev: + if k==0: form(a,W.B) + elif k==1: + u=a + for t in sorted(lowby[u]): + W.B.append((h.frame[u],C.Y(t),[reg[(u,chain_of[(u,1,t)])]],None)) + else: + t=a; srcs=[reg[(u,chain_of[(u,1,t)])] for u in h.need[t] if (t,u) not in lowset] + if srcs: W.B.append((Fm.HYP[t],C.Y(t),srcs,None)) + W.stats=dict(R=W.nh,carriers=W.ncarrier,Arules=len(Arules),Brules=sum(1 for w in needed if w>=V and ph[w]=='B'), + inplace=inplace[0],copies=ncopy[0],low=len(lowset),chains=sum(len(c) for c in chains.values())) + return W +if __name__=='__main__': + import pickle,sys + from repair import Hier + import __main__; __main__.Hier=Hier + try: + import ham1; __main__.SH=ham1.SH + except Exception: pass + h=pickle.load(open(sys.argv[1],'rb')) + if len(sys.argv)>2: PHASEMODE[0]=sys.argv[2] + W=compile2(h) + print(W.stats) + print('f2 check bad targets/x:',[len(z) for z in C.f2_check(W)]) + s,deficit,D,steps=C.evaluate(W) + print('R',W.nh,'saving %.6e'%s,'deficit',deficit,'D %.0f'%D,sorted(steps.items())) + import diag; diag.diag(W) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/e8lib.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/e8lib.py new file mode 100644 index 0000000000..8464b956f6 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/e8lib.py @@ -0,0 +1,79 @@ +"""Dylan Crow, with Anthropic Claude assistance; Apache-2.0. E8 root lines in Q^8 (standard coordinates, doubled to integers), F2 images, basic linear algebra.""" +import itertools +from fractions import Fraction as Fr + +def roots2(): + """E8 roots times 2 (integer vectors): 2(±e_i±e_j) and (±1)^8 with even number of minus signs.""" + R=[] + for i,j in itertools.combinations(range(8),2): + for a in (2,-2): + for b in (2,-2): + v=[0]*8; v[i]=a; v[j]=b; R.append(tuple(v)) + for signs in itertools.product((1,-1),repeat=8): + if signs.count(-1)%2==0: R.append(tuple(signs)) + return R + +def ip(u,v): # true inner product of roots given doubled coordinates + return sum(a*b for a,b in zip(u,v))//4 + +import os +def roots_hamming(): + """E8 via Construction A from the [8,4,4] extended Hamming code: x in Z^8, x mod 2 in H8, |x|^2=4. + Inner product of roots = /2. Returned scaled so that ip() (which divides by 4) works: multiply by sqrt2? no: + we return 2*x/sqrt... -> use integer vectors y=x and a separate scale.""" + H=[] + for a in itertools.product((0,1),repeat=4): + g=[(1,1,1,1,0,0,0,0),(1,1,0,0,1,1,0,0),(1,0,1,0,1,0,1,0),(0,1,1,0,1,0,0,1)] + w=[sum(a[k]*g[k][i] for k in range(4))%2 for i in range(8)] + H.append(tuple(w)) + R=[] + for i in range(8): + for sg in (2,-2): + v=[0]*8; v[i]=sg; R.append(tuple(v)) + for w in H: + if sum(w)==4: + idx=[i for i in range(8) if w[i]] + for sg in itertools.product((1,-1),repeat=4): + v=[0]*8 + for i,s_ in zip(idx,sg): v[i]=s_ + R.append(tuple(v)) + return R +COORD=os.environ.get('E8COORD','std') +if COORD=='ham': + ALL=[tuple(a for a in r) for r in roots_hamming()] + def ip(u,v): return sum(a*b for a,b in zip(u,v))//2 +else: + ALL=roots2() +assert len(ALL)==240 +LINES=[] +seen=set() +for r in ALL: + if r in seen: continue + neg=tuple(-a for a in r); seen.add(r); seen.add(neg) + # canonical: first nonzero coordinate positive + LINES.append(r if [a for a in r if a][0]>0 else neg) +V=len(LINES); assert V==120 +G=[[ip(LINES[a],LINES[b]) for b in range(V)] for a in range(V)] +ORTH=[[b for b in range(V) if G[a][b]==0] for a in range(V)] +NEIGH=[[b for b in range(V) if abs(G[a][b])==1] for a in range(V)] +assert all(len(o)==63 and len(n)==56 for o,n in zip(ORTH,NEIGH)) + +def rank_q(vecs): + """rank over Q of integer vectors""" + rows=[list(map(Fr,v)) for v in vecs] + r=0; n=len(rows[0]) if rows else 0 + for c in range(n): + p=None + for i in range(r,len(rows)): + if rows[i][c]!=0: p=i;break + if p is None: continue + rows[r],rows[p]=rows[p],rows[r] + for i in range(len(rows)): + if i!=r and rows[i][c]!=0: + f=rows[i][c]/rows[r][c] + rows[i]=[x-f*y for x,y in zip(rows[i],rows[r])] + r+=1 + return r + +def span_dim(idx): + return rank_q([LINES[i] for i in idx]) if idx else 0 diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/frames.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/frames.py new file mode 100644 index 0000000000..b28c3b2413 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/frames.py @@ -0,0 +1,45 @@ +"""Dylan Crow, with Anthropic Claude assistance; Apache-2.0. Root-spanned rational subspaces of Q^8, represented by the bitmask of E8 root lines they contain.""" +import e8lib as E +from fractions import Fraction as Fr +V=E.V +L=E.LINES +_cache={} +def _basis(idx): + rows=[] + piv=[] + for i in idx: + v=[Fr(a) for a in L[i]] + for (p,b) in zip(piv,rows): + if v[p]!=0: + f=v[p]/b[p]; v=[x-f*y for x,y in zip(v,b)] + nz=[k for k in range(8) if v[k]!=0] + if nz: + rows.append(v); piv.append(nz[0]) + return rows,piv +def _inspan(v,rows,piv): + v=[Fr(a) for a in v] + for (p,b) in zip(piv,rows): + if v[p]!=0: + f=v[p]/b[p]; v=[x-f*y for x,y in zip(v,b)] + return all(x==0 for x in v) +def closure(mask): + """mask of all root lines in the rational span of the lines in mask; returns (closed_mask, dim)""" + r=_cache.get(mask) + if r is not None: return r + idx=[i for i in range(V) if mask>>i&1] + rows,piv=_basis(idx) + cm=0 + for i in range(V): + if mask>>i&1 or _inspan(L[i],rows,piv): cm|=1<=2*V: Cl.append([fid(Fm.FULL),d,srcs]) + fr=[None]*len(frames) + for mk,i in frames.items(): fr[i]=[s for s in range(V) if mk>>s&1] + start=[fid(Fm.LINE[s]) for s in range(V)]+[fid(0)]*V+[fid(0)]*W.nh + final=[fid(Fm.FULL)]*V+[fid(Fm.HYP[t]) for t in range(V)]+[fid(Fm.FULL)]*W.nh + return dict(format='bitE8/1',coords=E.COORD,h=8,v=V,R=W.nh,lines=[list(r) for r in E.LINES], + form='/2' if E.COORD=='ham' else '/4',frames=fr,start=start,final=final, + ret=list(W.ret),scatter=scat,D=D,A=A,B=B,C=Cl) +def save(cert,path): + data=json.dumps(cert,separators=(',',':'),sort_keys=True).encode() + if path.endswith('.gz'): + with open(path,'wb') as fh: + with gzip.GzipFile(filename='',mode='wb',fileobj=fh,mtime=0) as gz: gz.write(data) + else: open(path,'wb').write(data) +if __name__=='__main__': + import ast, ham2, compile2 as C2 + Pd={ast.literal_eval(k):v for k,v in json.load(open(sys.argv[1]))} if sys.argv[1]!='-' else {} + ham2.P.clear(); ham2.P.update(Pd) + h=ham2.build(0,True); W=C2.compile2(h) + cert=build(W); save(cert,sys.argv[2]) + print('R',W.nh,'gates D/A/B/C',len(cert['D']),len(cert['A']),len(cert['B']),len(cert['C']),'frames',len(cert['frames'])) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/ham1.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/ham1.py new file mode 100644 index 0000000000..8086649a5f --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/ham1.py @@ -0,0 +1,81 @@ +"""Dylan Crow, with Anthropic Claude assistance; Apache-2.0. Hand-structured bit-E8 hierarchy in Hamming coordinates (E8COORD=ham).""" +import os, sys, itertools, pickle +assert os.environ.get('E8COORD')=='ham' +import e8lib as E, frames as Fm +from collections import defaultdict +V=E.V +L=E.LINES +idx={} +for i,r in enumerate(L): idx[r]=i; idx[tuple(-a for a in r)]=i +frame_line=[idx[tuple(2 if k==i else 0 for k in range(8))] for i in range(8)] +blocks=sorted(set(tuple(k for k in range(8) if r[k]) for r in L if sum(1 for a in r if a)==4)) +assert len(blocks)==14 +def cw_lines(c): return [i for i,r in enumerate(L) if tuple(k for k in range(8) if r[k])==c] +class SH: + """hierarchy with XOR semantics""" + def __init__(self): + self.content=[1<0 else -1 + Lsym={}; Psym={} + for c in blocks: + ls=cw_lines(c) + for (i,j) in itertools.combinations(c,2): + for rho in (1,-1): + mem=[s for s in ls if rel(L[s],i,j)==rho] + assert len(mem)==4 + # split into two pairs: pair lines that agree on the remaining pair (k,l) relative sign + k,l=[q for q in c if q not in (i,j)] + a=[s for s in mem if rel(L[s],k,l)==1]; b=[s for s in mem if rel(L[s],k,l)==-1] + pa=h.sym(sorted(a)); pb=h.sym(sorted(b)) + Lsym[(c,i,j,rho)]=h.sym([pa,pb]) + Dsym={} + for c in blocks: + i,j=c[0],c[1] + Dsym[c]=h.sym([Lsym[(c,i,j,1)],Lsym[(c,i,j,-1)]]+[frame_line[q] for q in c]) + Msym={} + for c in blocks: + for (i,j) in itertools.combinations(c,2): + others=[c2 for c2 in blocks if c2!=c and i in c2 and j in c2] + assert len(others)==2 + for rho in (1,-1): + Msym[(c,i,j,rho)]=h.sym([Lsym[(others[0],i,j,rho)],Lsym[(others[1],i,j,rho)]]) + comp={c:[c2 for c2 in blocks if not set(c)&set(c2)][0] for c in blocks} + for c in blocks: + cb=comp[c] + for t in cw_lines(c): + r=L[t] + def rho(i,j): return -rel(r,i,j) + i,j,k,l=c # level-5 pair (i,j), level-6 triangle (i,j,k) + need=[Dsym[cb], Msym[(c,i,j,rho(i,j))], h.sym([Msym[(c,i,k,rho(i,k))],Msym[(c,j,k,rho(j,k))]]), + Msym[(c,i,l,rho(i,l))],Msym[(c,j,l,rho(j,l))],Msym[(c,k,l,rho(k,l))]] + need+=[s for s in cw_lines(c) if E.G[t][s]==0] + h.need[t]=set(need) + for m in range(8): + t=frame_line[m] + need=[Dsym[c] for c in blocks if m not in c]+[frame_line[q] for q in range(8) if q!=m] + h.need[t]=set(need) + # verify XOR + for t in range(V): + x=0 + for u in h.need[t]: x^=h.content[u] + assert x==Fm.HYP[t],(t,bin(x^Fm.HYP[t]).count('1')) + return h +if __name__=='__main__': + h=build() + pickle.dump(h,open('hier_ham1.pkl','wb')) + print('symbols',len(h.content)-V,'reads',sum(len(n) for n in h.need)) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/ham2.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/ham2.py new file mode 100644 index 0000000000..842f76b245 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/ham2.py @@ -0,0 +1,131 @@ +"""Dylan Crow, with Anthropic Claude assistance; Apache-2.0. Hamming-coordinate bit-E8 design with pi-coset pairing (E8COORD=ham).""" +import os, sys, itertools, pickle +assert os.environ.get('E8COORD')=='ham' +import e8lib as E, frames as Fm +from ham1 import SH, blocks, cw_lines, frame_line, idx +V=E.V; L=E.LINES +def proj_dir(S,c): + """projection of line S onto C_c as a normalized tuple (sign-canonical) or None if zero""" + v=[L[S][k] if k in c else 0 for k in range(8)] + if not any(v): return None + f=[a for a in v if a][0] + return tuple(a if f>0 else -a for a in v) +FRAMEOPT=[True,0,0] +P={} +LSKEYS=set() +def par(k,n): + return P.get(k,0)%n +def build(pairing=0, fold=True): + h=SH() + comp={c:[c2 for c2 in blocks if not set(c)&set(c2)][0] for c in blocks} + # L sets: lines of block c2 with projection onto C_c (c != c2, |c&c2|=2) along b-line p + Lsets={} + for c2 in blocks: + for c in blocks: + if len(set(c)&set(c2))!=2: continue + for S in cw_lines(c2): + p=proj_dir(S,c) + Lsets.setdefault((c2,p),set()).add(S) + Lsets={k:sorted(v) for k,v in Lsets.items()} + for k,v in Lsets.items(): assert len(v)==4,(k,v) + Lsym={} + for (c2,p),mem in Lsets.items(): + # split into two pairs by the relative sign on the other two coordinates of c2 + oth=[q for q in c2 if p[q]==0] + sp=par(('ls',c2,p),3); LSKEYS.add(('ls',c2,p)) + if sp==0: + a=[s for s in mem if L[s][oth[0]]*L[s][oth[1]]>0]; b=[s for s in mem if L[s][oth[0]]*L[s][oth[1]]<0] + else: + q0=[q for q in c2 if p[q]!=0][0] + a=[s for s in mem if L[s][q0]*L[s][oth[sp-1]]>0]; b=[s for s in mem if L[s][q0]*L[s][oth[sp-1]]<0] + Lsym[(c2,p)]=h.sym([h.sym(sorted(a)),h.sym(sorted(b))]) + Msym={} + for c in blocks: + for (c2,p),s in Lsets.items(): + pass + for (c2,p) in Lsets: + # p is a b-line of the block c for which p's support pair lies: find blocks c containing supp(p) other than c2 + supp=tuple(q for q in range(8) if p[q]) + for c in blocks: + if c!=c2 and set(supp)<=set(c): + Msym.setdefault((c,p),[]).append(Lsym[(c2,p)]) + for k in list(Msym): + assert len(Msym[k])==2 + Msym[k]=h.sym(sorted(Msym[k])) + Dsym={}; Bcw={} + for c in blocks: + ls=cw_lines(c) + # E(D4(c)) = all 8 codeword lines of c + 4 frame lines + p=None + for (c2,pp),s in Lsym.items(): + pass + # use two complementary L-like halves: split by relative sign on (c0,c1) + i,j=c[0],c[1] + A=[s for s in ls if L[s][i]*L[s][j]>0]; B=[s for s in ls if L[s][i]*L[s][j]<0] + Bcw[c]=h.sym([h.sym(sorted(A[:2])+sorted(A[2:])), h.sym(sorted(B)) ]) + Dsym[c]=h.sym([Bcw[c]]+[frame_line[q] for q in c]) + def bdir(u,w): + """the two b-line directions in the plane span(L[u],L[w]) (vectors a+-b normalized)""" + out=[] + for sg in (1,-1): + v=tuple(x+sg*y for x,y in zip(L[u],L[w])) + f=[a for a in v if a][0] + v=tuple(a//2 if f>0 else -a//2 for a in v) + out.append(v) + return out + for c in blocks: + cb=comp[c] + ls=cw_lines(c) + # pi-cosets: 4 mutually orthogonal lines + cos=[] + rem=set(ls) + while rem: + t=min(rem); Q=[t]+[s for s in rem if s!=t and E.G[t][s]==0] + assert len(Q)==4 and all(E.G[a][b]==0 for a in Q for b in Q if a!=b) + cos.append(Q); rem-=set(Q) + for Q in cos: + pr_=(pairing+par(('pair',c,min(Q)),3))%3 + pairs=[(Q[0],Q[1+pr_]),tuple(q for q in Q[1:] if q!=Q[1+pr_])] + partner={} + for x,y in pairs: partner[x]=y; partner[y]=x + for t in Q: + d=partner[t]; a,b=[q for q in Q if q not in (t,d)] + p5,p6=sorted(bdir(a,b)) + if par(('l5',min(t,d)),2): p5,p6=p6,p5 + M=lambda p: Msym[(c,p)] + need=[Dsym[cb], M(p5), h.sym([M(p6),a,b])] + q1,q2=sorted(bdir(a,d)); r1,r2=sorted(bdir(b,d)) + fo=par(('fold',t),2) if fold else 2 + if fo==0: + need+=[h.sym([M(q1),M(q2),d]), h.sym([M(r1),M(r2)])] + elif fo==1: + need+=[h.sym([M(q1),M(q2)]), h.sym([M(r1),M(r2),d])] + else: + need+=[h.sym([M(q1),M(q2)]), h.sym([M(r1),M(r2)]), d] + h.need[t]=set(need) + for m in range(8): + t=frame_line[m] + if not FRAMEOPT[0]: + h.need[t]=set([Dsym[c] for c in blocks if m not in c]+[frame_line[q] for q in range(8) if q!=m]); continue + avoid=[c for c in blocks if m not in c] + c0=avoid[(FRAMEOPT[1]+par(('fc0',m),7))%len(avoid)] + ns=[q for q in range(8) if q!=m and q not in c0] + n=ns[(FRAMEOPT[2]+par(('fn',m),3))%len(ns)] + A6=[q for q in range(8) if q not in (m,n)] + in6=[c for c in avoid if set(c)<=set(A6) and c!=c0]; assert len(in6)==2 + top=[c for c in avoid if n in c]; assert len(top)==4 + # pair top blocks so each pair spans a 6-dim coordinate space (always true) + need=[Dsym[c0], h.sym([Bcw[in6[0]],Bcw[in6[1]]]+[frame_line[q] for q in A6 if q not in c0]), + h.sym([Bcw[top[0]],Bcw[top[1]],frame_line[n]]), h.sym([Bcw[top[2]],Bcw[top[3]]])] + h.need[t]=set(need) + for t in range(V): + x=0 + for u in h.need[t]: x^=h.content[u] + assert x==Fm.HYP[t],(t,bin(x^Fm.HYP[t]).count('1')) + return h +if __name__=='__main__': + pr=int(sys.argv[1]) if len(sys.argv)>1 else 0 + fold=(sys.argv[2]!='nofold') if len(sys.argv)>2 else True + h=build(pr,fold) + pickle.dump(h,open('hier_ham2_%d_%s.pkl'%(pr,fold),'wb')) + print('symbols',len(h.content)-V,'reads',sum(len(n) for n in h.need)) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/params-r865.json b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/params-r865.json new file mode 100644 index 0000000000..110b4d94d8 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/params-r865.json @@ -0,0 +1,2082 @@ +[ +[ +"('fc0', 0)", +3 +], +[ +"('fc0', 1)", +3 +], +[ +"('fc0', 2)", +0 +], +[ +"('fc0', 3)", +0 +], +[ +"('fc0', 4)", +3 +], +[ +"('fc0', 5)", +0 +], +[ +"('fc0', 6)", +2 +], +[ +"('fc0', 7)", +0 +], +[ +"('fn', 0)", +1 +], +[ +"('fn', 1)", +1 +], +[ +"('fn', 2)", +0 +], +[ +"('fn', 3)", +0 +], +[ +"('fn', 4)", +0 +], +[ +"('fn', 5)", +0 +], +[ +"('fn', 6)", +0 +], +[ +"('fn', 7)", +2 +], +[ +"('fold', 10)", +1 +], +[ +"('fold', 100)", +1 +], +[ +"('fold', 101)", +0 +], +[ +"('fold', 102)", +1 +], +[ +"('fold', 103)", +0 +], +[ +"('fold', 104)", +1 +], +[ +"('fold', 105)", +0 +], +[ +"('fold', 106)", +1 +], +[ +"('fold', 107)", +0 +], +[ +"('fold', 108)", +1 +], +[ +"('fold', 109)", +0 +], +[ +"('fold', 11)", +1 +], +[ +"('fold', 110)", +1 +], +[ +"('fold', 111)", +0 +], +[ +"('fold', 112)", +1 +], +[ +"('fold', 113)", +1 +], +[ +"('fold', 114)", +0 +], +[ +"('fold', 115)", +0 +], +[ +"('fold', 116)", +0 +], +[ +"('fold', 117)", +0 +], +[ +"('fold', 118)", +1 +], +[ +"('fold', 119)", +1 +], +[ +"('fold', 12)", +1 +], +[ +"('fold', 13)", +1 +], +[ +"('fold', 14)", +0 +], +[ +"('fold', 15)", +0 +], +[ +"('fold', 16)", +0 +], +[ +"('fold', 17)", +1 +], +[ +"('fold', 18)", +0 +], +[ +"('fold', 19)", +1 +], +[ +"('fold', 20)", +0 +], +[ +"('fold', 21)", +1 +], +[ +"('fold', 22)", +0 +], +[ +"('fold', 23)", +1 +], +[ +"('fold', 24)", +0 +], +[ +"('fold', 25)", +1 +], +[ +"('fold', 26)", +0 +], +[ +"('fold', 27)", +1 +], +[ +"('fold', 28)", +0 +], +[ +"('fold', 29)", +1 +], +[ +"('fold', 30)", +0 +], +[ +"('fold', 31)", +1 +], +[ +"('fold', 32)", +1 +], +[ +"('fold', 33)", +1 +], +[ +"('fold', 34)", +0 +], +[ +"('fold', 35)", +0 +], +[ +"('fold', 36)", +0 +], +[ +"('fold', 37)", +0 +], +[ +"('fold', 38)", +1 +], +[ +"('fold', 39)", +1 +], +[ +"('fold', 40)", +0 +], +[ +"('fold', 41)", +0 +], +[ +"('fold', 42)", +1 +], +[ +"('fold', 43)", +1 +], +[ +"('fold', 44)", +1 +], +[ +"('fold', 45)", +1 +], +[ +"('fold', 46)", +0 +], +[ +"('fold', 47)", +0 +], +[ +"('fold', 48)", +0 +], +[ +"('fold', 49)", +1 +], +[ +"('fold', 50)", +0 +], +[ +"('fold', 51)", +1 +], +[ +"('fold', 52)", +0 +], +[ +"('fold', 53)", +1 +], +[ +"('fold', 54)", +0 +], +[ +"('fold', 55)", +1 +], +[ +"('fold', 56)", +0 +], +[ +"('fold', 57)", +0 +], +[ +"('fold', 58)", +1 +], +[ +"('fold', 59)", +1 +], +[ +"('fold', 60)", +1 +], +[ +"('fold', 61)", +1 +], +[ +"('fold', 62)", +0 +], +[ +"('fold', 63)", +0 +], +[ +"('fold', 64)", +0 +], +[ +"('fold', 65)", +0 +], +[ +"('fold', 66)", +1 +], +[ +"('fold', 67)", +1 +], +[ +"('fold', 68)", +1 +], +[ +"('fold', 69)", +1 +], +[ +"('fold', 70)", +0 +], +[ +"('fold', 71)", +0 +], +[ +"('fold', 72)", +0 +], +[ +"('fold', 73)", +1 +], +[ +"('fold', 74)", +0 +], +[ +"('fold', 75)", +1 +], +[ +"('fold', 76)", +0 +], +[ +"('fold', 77)", +1 +], +[ +"('fold', 78)", +0 +], +[ +"('fold', 79)", +1 +], +[ +"('fold', 8)", +0 +], +[ +"('fold', 80)", +1 +], +[ +"('fold', 81)", +0 +], +[ +"('fold', 82)", +1 +], +[ +"('fold', 83)", +0 +], +[ +"('fold', 84)", +1 +], +[ +"('fold', 85)", +0 +], +[ +"('fold', 86)", +1 +], +[ +"('fold', 87)", +0 +], +[ +"('fold', 88)", +1 +], +[ +"('fold', 89)", +0 +], +[ +"('fold', 9)", +0 +], +[ +"('fold', 90)", +1 +], +[ +"('fold', 91)", +0 +], +[ +"('fold', 92)", +1 +], +[ +"('fold', 93)", +0 +], +[ +"('fold', 94)", +1 +], +[ +"('fold', 95)", +0 +], +[ +"('fold', 96)", +1 +], +[ +"('fold', 97)", +0 +], +[ +"('fold', 98)", +1 +], +[ +"('fold', 99)", +0 +], +[ +"('l5', 10)", +0 +], +[ +"('l5', 100)", +0 +], +[ +"('l5', 101)", +0 +], +[ +"('l5', 102)", +1 +], +[ +"('l5', 103)", +0 +], +[ +"('l5', 104)", +0 +], +[ +"('l5', 105)", +0 +], +[ +"('l5', 106)", +1 +], +[ +"('l5', 107)", +0 +], +[ +"('l5', 108)", +0 +], +[ +"('l5', 109)", +0 +], +[ +"('l5', 11)", +1 +], +[ +"('l5', 110)", +0 +], +[ +"('l5', 111)", +1 +], +[ +"('l5', 112)", +0 +], +[ +"('l5', 113)", +0 +], +[ +"('l5', 114)", +1 +], +[ +"('l5', 115)", +0 +], +[ +"('l5', 116)", +0 +], +[ +"('l5', 117)", +0 +], +[ +"('l5', 118)", +1 +], +[ +"('l5', 119)", +1 +], +[ +"('l5', 12)", +0 +], +[ +"('l5', 13)", +0 +], +[ +"('l5', 14)", +0 +], +[ +"('l5', 15)", +0 +], +[ +"('l5', 16)", +0 +], +[ +"('l5', 17)", +0 +], +[ +"('l5', 18)", +0 +], +[ +"('l5', 19)", +0 +], +[ +"('l5', 20)", +0 +], +[ +"('l5', 21)", +0 +], +[ +"('l5', 22)", +1 +], +[ +"('l5', 23)", +1 +], +[ +"('l5', 24)", +0 +], +[ +"('l5', 25)", +0 +], +[ +"('l5', 26)", +1 +], +[ +"('l5', 27)", +0 +], +[ +"('l5', 28)", +0 +], +[ +"('l5', 29)", +0 +], +[ +"('l5', 30)", +0 +], +[ +"('l5', 31)", +0 +], +[ +"('l5', 32)", +0 +], +[ +"('l5', 33)", +0 +], +[ +"('l5', 34)", +0 +], +[ +"('l5', 35)", +0 +], +[ +"('l5', 36)", +0 +], +[ +"('l5', 37)", +0 +], +[ +"('l5', 38)", +0 +], +[ +"('l5', 39)", +0 +], +[ +"('l5', 40)", +0 +], +[ +"('l5', 41)", +0 +], +[ +"('l5', 42)", +1 +], +[ +"('l5', 43)", +0 +], +[ +"('l5', 44)", +0 +], +[ +"('l5', 45)", +0 +], +[ +"('l5', 46)", +1 +], +[ +"('l5', 47)", +0 +], +[ +"('l5', 48)", +0 +], +[ +"('l5', 49)", +0 +], +[ +"('l5', 50)", +1 +], +[ +"('l5', 51)", +1 +], +[ +"('l5', 52)", +0 +], +[ +"('l5', 53)", +0 +], +[ +"('l5', 54)", +1 +], +[ +"('l5', 55)", +1 +], +[ +"('l5', 56)", +0 +], +[ +"('l5', 57)", +0 +], +[ +"('l5', 58)", +1 +], +[ +"('l5', 59)", +0 +], +[ +"('l5', 60)", +0 +], +[ +"('l5', 61)", +0 +], +[ +"('l5', 62)", +0 +], +[ +"('l5', 63)", +0 +], +[ +"('l5', 64)", +0 +], +[ +"('l5', 65)", +0 +], +[ +"('l5', 66)", +1 +], +[ +"('l5', 67)", +0 +], +[ +"('l5', 68)", +0 +], +[ +"('l5', 69)", +0 +], +[ +"('l5', 70)", +0 +], +[ +"('l5', 71)", +0 +], +[ +"('l5', 72)", +0 +], +[ +"('l5', 73)", +0 +], +[ +"('l5', 74)", +1 +], +[ +"('l5', 75)", +1 +], +[ +"('l5', 76)", +0 +], +[ +"('l5', 77)", +0 +], +[ +"('l5', 78)", +0 +], +[ +"('l5', 79)", +0 +], +[ +"('l5', 8)", +0 +], +[ +"('l5', 80)", +0 +], +[ +"('l5', 81)", +0 +], +[ +"('l5', 82)", +0 +], +[ +"('l5', 83)", +1 +], +[ +"('l5', 84)", +0 +], +[ +"('l5', 85)", +0 +], +[ +"('l5', 86)", +0 +], +[ +"('l5', 87)", +1 +], +[ +"('l5', 88)", +0 +], +[ +"('l5', 89)", +0 +], +[ +"('l5', 9)", +0 +], +[ +"('l5', 90)", +0 +], +[ +"('l5', 91)", +1 +], +[ +"('l5', 92)", +0 +], +[ +"('l5', 93)", +0 +], +[ +"('l5', 94)", +1 +], +[ +"('l5', 95)", +0 +], +[ +"('l5', 96)", +0 +], +[ +"('l5', 97)", +0 +], +[ +"('l5', 98)", +0 +], +[ +"('l5', 99)", +0 +], +[ +"('ls', (0, 1, 2, 3), (0, 0, 1, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (0, 0, 1, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (0, 1, -1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (0, 1, 0, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (0, 1, 0, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (0, 1, 1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (1, -1, 0, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (1, 0, -1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (1, 0, 0, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (1, 0, 0, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (1, 0, 1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 2, 3), (1, 1, 0, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (0, 0, 0, 0, 1, -1, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (0, 0, 0, 0, 1, 1, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (0, 1, 0, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (0, 1, 0, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (0, 1, 0, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (0, 1, 0, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (1, -1, 0, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (1, 0, 0, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (1, 0, 0, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (1, 0, 0, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (1, 0, 0, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 4, 5), (1, 1, 0, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 6, 7), (0, 0, 0, 0, 0, 0, 1, -1))", +0 +], +[ +"('ls', (0, 1, 6, 7), (0, 0, 0, 0, 0, 0, 1, 1))", +0 +], +[ +"('ls', (0, 1, 6, 7), (0, 1, 0, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (0, 1, 6, 7), (0, 1, 0, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (0, 1, 6, 7), (0, 1, 0, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (0, 1, 6, 7), (0, 1, 0, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (0, 1, 6, 7), (1, -1, 0, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 1, 6, 7), (1, 0, 0, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (0, 1, 6, 7), (1, 0, 0, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (0, 1, 6, 7), (1, 0, 0, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (0, 1, 6, 7), (1, 0, 0, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (0, 1, 6, 7), (1, 1, 0, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (0, 0, 0, 0, 1, 0, -1, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (0, 0, 0, 0, 1, 0, 1, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (0, 0, 1, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (0, 0, 1, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (0, 0, 1, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (0, 0, 1, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (1, 0, -1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (1, 0, 0, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (1, 0, 0, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (1, 0, 0, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (1, 0, 0, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 4, 6), (1, 0, 1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 5, 7), (0, 0, 0, 0, 0, 1, 0, -1))", +0 +], +[ +"('ls', (0, 2, 5, 7), (0, 0, 0, 0, 0, 1, 0, 1))", +0 +], +[ +"('ls', (0, 2, 5, 7), (0, 0, 1, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (0, 2, 5, 7), (0, 0, 1, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (0, 2, 5, 7), (0, 0, 1, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (0, 2, 5, 7), (0, 0, 1, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (0, 2, 5, 7), (1, 0, -1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 2, 5, 7), (1, 0, 0, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (0, 2, 5, 7), (1, 0, 0, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (0, 2, 5, 7), (1, 0, 0, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (0, 2, 5, 7), (1, 0, 0, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (0, 2, 5, 7), (1, 0, 1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 4, 7), (0, 0, 0, 0, 1, 0, 0, -1))", +0 +], +[ +"('ls', (0, 3, 4, 7), (0, 0, 0, 0, 1, 0, 0, 1))", +0 +], +[ +"('ls', (0, 3, 4, 7), (0, 0, 0, 1, -1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 4, 7), (0, 0, 0, 1, 0, 0, 0, -1))", +0 +], +[ +"('ls', (0, 3, 4, 7), (0, 0, 0, 1, 0, 0, 0, 1))", +0 +], +[ +"('ls', (0, 3, 4, 7), (0, 0, 0, 1, 1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 4, 7), (1, 0, 0, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 4, 7), (1, 0, 0, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 4, 7), (1, 0, 0, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (0, 3, 4, 7), (1, 0, 0, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (0, 3, 4, 7), (1, 0, 0, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 4, 7), (1, 0, 0, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (0, 0, 0, 0, 0, 1, -1, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (0, 0, 0, 0, 0, 1, 1, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (0, 0, 0, 1, 0, -1, 0, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (0, 0, 0, 1, 0, 0, -1, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (0, 0, 0, 1, 0, 0, 1, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (0, 0, 0, 1, 0, 1, 0, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (1, 0, 0, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (1, 0, 0, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (1, 0, 0, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (1, 0, 0, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (1, 0, 0, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (0, 3, 5, 6), (1, 0, 0, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 0, 0, 0, 1, 0, 0, -1))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 0, 0, 0, 1, 0, 0, 1))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 0, 1, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 0, 1, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 0, 1, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 0, 1, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 1, -1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 1, 0, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 1, 0, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 1, 0, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 1, 0, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 4, 7), (0, 1, 1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 0, 0, 0, 0, 1, -1, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 0, 0, 0, 0, 1, 1, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 0, 1, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 0, 1, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 0, 1, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 0, 1, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 1, -1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 1, 0, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 1, 0, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 1, 0, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 1, 0, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (1, 2, 5, 6), (0, 1, 1, 0, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 0, 0, 0, 1, 0, -1, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 0, 0, 0, 1, 0, 1, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 0, 0, 1, -1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 0, 0, 1, 0, 0, -1, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 0, 0, 1, 0, 0, 1, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 0, 0, 1, 1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 1, 0, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 1, 0, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 1, 0, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 1, 0, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 1, 0, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 4, 6), (0, 1, 0, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 0, 0, 0, 0, 1, 0, -1))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 0, 0, 0, 0, 1, 0, 1))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 0, 0, 1, 0, -1, 0, 0))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 0, 0, 1, 0, 0, 0, -1))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 0, 0, 1, 0, 0, 0, 1))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 0, 0, 1, 0, 1, 0, 0))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 1, 0, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 1, 0, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 1, 0, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 1, 0, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 1, 0, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (1, 3, 5, 7), (0, 1, 0, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 0, 0, 1, -1, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 0, 0, 1, 1, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 0, 1, -1, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 0, 1, 0, -1, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 0, 1, 0, 1, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 0, 1, 1, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 1, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 1, 0, -1, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 1, 0, 0, -1, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 1, 0, 0, 1, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 1, 0, 1, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 4, 5), (0, 0, 1, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 0, 0, 0, 0, 1, -1))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 0, 0, 0, 0, 1, 1))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 0, 1, 0, 0, -1, 0))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 0, 1, 0, 0, 0, -1))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 0, 1, 0, 0, 0, 1))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 0, 1, 0, 0, 1, 0))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 1, -1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 1, 0, 0, 0, -1, 0))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 1, 0, 0, 0, 0, -1))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 1, 0, 0, 0, 0, 1))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 1, 0, 0, 0, 1, 0))", +0 +], +[ +"('ls', (2, 3, 6, 7), (0, 0, 1, 1, 0, 0, 0, 0))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 0, 0, 1, -1))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 0, 0, 1, 1))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 0, 1, -1, 0))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 0, 1, 0, -1))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 0, 1, 0, 1))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 0, 1, 1, 0))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 1, -1, 0, 0))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 1, 0, -1, 0))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 1, 0, 0, -1))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 1, 0, 0, 1))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 1, 0, 1, 0))", +0 +], +[ +"('ls', (4, 5, 6, 7), (0, 0, 0, 0, 1, 1, 0, 0))", +0 +], +[ +"('pair', (0, 1, 2, 3), 64)", +0 +], +[ +"('pair', (0, 1, 2, 3), 65)", +0 +], +[ +"('pair', (0, 1, 2, 3), 66)", +0 +], +[ +"('pair', (0, 1, 2, 3), 67)", +1 +], +[ +"('pair', (0, 1, 2, 3), 68)", +0 +], +[ +"('pair', (0, 1, 2, 3), 69)", +0 +], +[ +"('pair', (0, 1, 2, 3), 70)", +2 +], +[ +"('pair', (0, 1, 2, 3), 71)", +1 +], +[ +"('pair', (0, 1, 4, 5), 32)", +0 +], +[ +"('pair', (0, 1, 4, 5), 33)", +0 +], +[ +"('pair', (0, 1, 4, 5), 34)", +1 +], +[ +"('pair', (0, 1, 4, 5), 35)", +1 +], +[ +"('pair', (0, 1, 4, 5), 36)", +1 +], +[ +"('pair', (0, 1, 4, 5), 37)", +1 +], +[ +"('pair', (0, 1, 4, 5), 38)", +1 +], +[ +"('pair', (0, 1, 4, 5), 39)", +1 +], +[ +"('pair', (0, 1, 6, 7), 24)", +0 +], +[ +"('pair', (0, 1, 6, 7), 25)", +0 +], +[ +"('pair', (0, 1, 6, 7), 26)", +2 +], +[ +"('pair', (0, 1, 6, 7), 27)", +0 +], +[ +"('pair', (0, 1, 6, 7), 28)", +2 +], +[ +"('pair', (0, 1, 6, 7), 29)", +2 +], +[ +"('pair', (0, 1, 6, 7), 30)", +2 +], +[ +"('pair', (0, 1, 6, 7), 31)", +2 +], +[ +"('pair', (0, 2, 4, 6), 16)", +0 +], +[ +"('pair', (0, 2, 4, 6), 17)", +0 +], +[ +"('pair', (0, 2, 4, 6), 18)", +2 +], +[ +"('pair', (0, 2, 4, 6), 19)", +0 +], +[ +"('pair', (0, 2, 4, 6), 20)", +2 +], +[ +"('pair', (0, 2, 4, 6), 21)", +0 +], +[ +"('pair', (0, 2, 4, 6), 22)", +0 +], +[ +"('pair', (0, 2, 4, 6), 23)", +1 +], +[ +"('pair', (0, 2, 5, 7), 40)", +0 +], +[ +"('pair', (0, 2, 5, 7), 41)", +0 +], +[ +"('pair', (0, 2, 5, 7), 42)", +0 +], +[ +"('pair', (0, 2, 5, 7), 43)", +2 +], +[ +"('pair', (0, 2, 5, 7), 44)", +1 +], +[ +"('pair', (0, 2, 5, 7), 45)", +1 +], +[ +"('pair', (0, 2, 5, 7), 46)", +0 +], +[ +"('pair', (0, 2, 5, 7), 47)", +2 +], +[ +"('pair', (0, 3, 4, 7), 72)", +0 +], +[ +"('pair', (0, 3, 4, 7), 73)", +0 +], +[ +"('pair', (0, 3, 4, 7), 74)", +0 +], +[ +"('pair', (0, 3, 4, 7), 75)", +0 +], +[ +"('pair', (0, 3, 4, 7), 76)", +0 +], +[ +"('pair', (0, 3, 4, 7), 77)", +2 +], +[ +"('pair', (0, 3, 4, 7), 78)", +1 +], +[ +"('pair', (0, 3, 4, 7), 79)", +2 +], +[ +"('pair', (0, 3, 5, 6), 112)", +0 +], +[ +"('pair', (0, 3, 5, 6), 113)", +0 +], +[ +"('pair', (0, 3, 5, 6), 114)", +2 +], +[ +"('pair', (0, 3, 5, 6), 115)", +0 +], +[ +"('pair', (0, 3, 5, 6), 116)", +0 +], +[ +"('pair', (0, 3, 5, 6), 117)", +1 +], +[ +"('pair', (0, 3, 5, 6), 118)", +0 +], +[ +"('pair', (0, 3, 5, 6), 119)", +2 +], +[ +"('pair', (1, 2, 4, 7), 10)", +2 +], +[ +"('pair', (1, 2, 4, 7), 11)", +0 +], +[ +"('pair', (1, 2, 4, 7), 12)", +2 +], +[ +"('pair', (1, 2, 4, 7), 13)", +0 +], +[ +"('pair', (1, 2, 4, 7), 14)", +1 +], +[ +"('pair', (1, 2, 4, 7), 15)", +1 +], +[ +"('pair', (1, 2, 4, 7), 8)", +0 +], +[ +"('pair', (1, 2, 4, 7), 9)", +0 +], +[ +"('pair', (1, 2, 5, 6), 48)", +0 +], +[ +"('pair', (1, 2, 5, 6), 49)", +0 +], +[ +"('pair', (1, 2, 5, 6), 50)", +2 +], +[ +"('pair', (1, 2, 5, 6), 51)", +1 +], +[ +"('pair', (1, 2, 5, 6), 52)", +2 +], +[ +"('pair', (1, 2, 5, 6), 53)", +0 +], +[ +"('pair', (1, 2, 5, 6), 54)", +1 +], +[ +"('pair', (1, 2, 5, 6), 55)", +2 +], +[ +"('pair', (1, 3, 4, 6), 80)", +0 +], +[ +"('pair', (1, 3, 4, 6), 81)", +0 +], +[ +"('pair', (1, 3, 4, 6), 82)", +1 +], +[ +"('pair', (1, 3, 4, 6), 83)", +2 +], +[ +"('pair', (1, 3, 4, 6), 84)", +1 +], +[ +"('pair', (1, 3, 4, 6), 85)", +1 +], +[ +"('pair', (1, 3, 4, 6), 86)", +1 +], +[ +"('pair', (1, 3, 4, 6), 87)", +2 +], +[ +"('pair', (1, 3, 5, 7), 104)", +0 +], +[ +"('pair', (1, 3, 5, 7), 105)", +0 +], +[ +"('pair', (1, 3, 5, 7), 106)", +0 +], +[ +"('pair', (1, 3, 5, 7), 107)", +2 +], +[ +"('pair', (1, 3, 5, 7), 108)", +2 +], +[ +"('pair', (1, 3, 5, 7), 109)", +1 +], +[ +"('pair', (1, 3, 5, 7), 110)", +2 +], +[ +"('pair', (1, 3, 5, 7), 111)", +1 +], +[ +"('pair', (2, 3, 4, 5), 100)", +0 +], +[ +"('pair', (2, 3, 4, 5), 101)", +2 +], +[ +"('pair', (2, 3, 4, 5), 102)", +1 +], +[ +"('pair', (2, 3, 4, 5), 103)", +2 +], +[ +"('pair', (2, 3, 4, 5), 96)", +0 +], +[ +"('pair', (2, 3, 4, 5), 97)", +0 +], +[ +"('pair', (2, 3, 4, 5), 98)", +2 +], +[ +"('pair', (2, 3, 4, 5), 99)", +1 +], +[ +"('pair', (2, 3, 6, 7), 88)", +0 +], +[ +"('pair', (2, 3, 6, 7), 89)", +0 +], +[ +"('pair', (2, 3, 6, 7), 90)", +0 +], +[ +"('pair', (2, 3, 6, 7), 91)", +0 +], +[ +"('pair', (2, 3, 6, 7), 92)", +1 +], +[ +"('pair', (2, 3, 6, 7), 93)", +2 +], +[ +"('pair', (2, 3, 6, 7), 94)", +0 +], +[ +"('pair', (2, 3, 6, 7), 95)", +1 +], +[ +"('pair', (4, 5, 6, 7), 56)", +0 +], +[ +"('pair', (4, 5, 6, 7), 57)", +0 +], +[ +"('pair', (4, 5, 6, 7), 58)", +0 +], +[ +"('pair', (4, 5, 6, 7), 59)", +2 +], +[ +"('pair', (4, 5, 6, 7), 60)", +0 +], +[ +"('pair', (4, 5, 6, 7), 61)", +1 +], +[ +"('pair', (4, 5, 6, 7), 62)", +0 +], +[ +"('pair', (4, 5, 6, 7), 63)", +0 +] +] \ No newline at end of file diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/price.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/price.py new file mode 100644 index 0000000000..9014d97d51 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/price.py @@ -0,0 +1,23 @@ +# Dylan Crow, with Anthropic Claude assistance; Apache-2.0. +import math +from collections import Counter +def price(steps, R, v=120, h=8, L=72, ncent=9, exact=True): + """steps: Counter of step ranks over x, y, helpers for ONE invocation (centres added here). + Five-stage: H5 = 5*(steps + centres) + 2v*(2h-2,h-1,2h+2,4); W = 4v+R; m=5h.""" + m=5*h + H=Counter() + for r,n in steps.items(): H[r]+=5*n + H[h]+=5*ncent # centres at full frame (rank = frame dim = h) + for r in (2*h-2,h-1,2*h+2,4): H[r]+=2*v + W=4*v+R + mass=sum(r*n for r,n in H.items()) + g=lambda r:r*math.log(m/r) + D=sum(n*g(r) for r,n in H.items()) + s1=(W*m-mass)/D + if not exact: return s1,W*m-mass,D + lo,hi=0.0,0.01 + for _ in range(80): + s=(lo+hi)/2 + if sum(n*(r/m)**(1-s) for r,n in H.items())>W: hi=s + else: lo=s + return lo,W*m-mass,D diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/search2.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/search2.py new file mode 100644 index 0000000000..b653f4b52a --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/producer/search2.py @@ -0,0 +1,44 @@ +# Dylan Crow, with Anthropic Claude assistance; Apache-2.0. +import sys, random, pickle, time, os +import ham2, compile2 as C2, compile as C, e8lib as E +V=E.V +def evalP(Pd): + ham2.P.clear(); ham2.P.update(Pd) + h=ham2.build(0,True) + W=C2.compile2(h) + bad=C.f2_check(W) + assert not bad[0] and not bad[1] + s,deficit,D,steps=C.evaluate(W) + return s,W.nh,h +keys=[] +import itertools +from ham1 import blocks, cw_lines +for c in blocks: + ls=cw_lines(c) + for t in ls: keys.append((('fold',t),2)); keys.append((('l5',t),2)) + for t in ls: keys.append((('pair',c,t),3)) +for m in range(8): keys.append((('fc0',m),7)); keys.append((('fn',m),3)) +if os.environ.get('LSKEYS'): + import e8lib as E2 + for c2 in blocks: + for t in cw_lines(c2): pass + hh=ham2.build(0,True) + for k in list(ham2.LSKEYS): keys.append((k,3)) +seed=int(sys.argv[1]); rng=random.Random(seed); iters=int(sys.argv[2]) +Pd={} +if len(sys.argv)>3 and os.path.exists(sys.argv[3]): Pd=pickle.load(open(sys.argv[3],'rb')) +t0=time.time(); best,R,_=evalP(Pd); print('start',best,R,flush=True) +for it in range(iters): + k,n=rng.choice(keys) + old=Pd.get(k,0); new=(old+rng.randrange(1,n))%n + Pd[k]=new + try: + s,R,h=evalP(Pd) + except AssertionError as e: + Pd[k]=old; continue + if s>best-1e-12: + if s>best+1e-12: print(it,'improved %.6e'%s,'R',R,k,new,'%.0fs'%(time.time()-t0),flush=True) + best=s; pickle.dump(Pd,open('P_best_%d.pkl'%seed,'wb')) + else: + Pd[k]=old +print('final',best) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/receipts_e8.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/receipts_e8.py new file mode 100644 index 0000000000..f514db37ab --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/receipts_e8.py @@ -0,0 +1,23 @@ +"""Assemble the finite-bill input for the E8 bit word from this run's receipts (no pinned numbers are trusted: +every value is read from a receipt written earlier in verify.sh, and cross-checked). +usage: receipts_e8.py WORD.json.gz RECORDDIR legality.json columns.json kappa.json OUT.json""" +import sys, json, gzip, struct +from collections import Counter +w=json.load(gzip.open(sys.argv[1],'rt')); rd=sys.argv[2]; leg=json.load(open(sys.argv[3])); col=json.load(open(sys.argv[4])); kap=json.load(open(sys.argv[5])) +v,R,h=w['v'],w['R'],w['h']; m=5*h; T=kap['T']; assert T==1 and kap['m']==m and kap['h']==h +rec=open(rd+'/249-records.bin','rb').read(); n=len(rec)//24 +adds=sum(1 for i in range(n) if struct.unpack_from('<6i',rec,24*i)[0]==1) +assert adds==leg['common_frame_ADDs']==col['local_scalar_additions'] and col['local_odd_scalar_additions']==adds # every coefficient is 1 +ncopy=len(w['ret']); assert ncopy==leg['copies']==leg['erasures']==col['fresh_center_copies']//5==9 +fwd=int(col['signed_lift_prefix'][0]['cancellation_free_signed_row_l1_upper']); inv=int(col['signed_lift_prefix'][1]['cancellation_free_signed_row_l1_upper']) +assert col['signed_lift_prefix'][0]['reverse'] is False and col['signed_lift_prefix'][1]['reverse'] is True +stock=T*kap['W']; maxops=0 # identity chart only: inverse_integer(I_h) has no factor +factors=maxops+(m-1)+m; K=2*5*T*((stock-1)+R*m*factors) +deficit=4*v-5*ncopy*h +out=dict(h=h,m=m,v=v,R=R,T=T,stock=stock,literal={k:T*c for k,c in kap['normalized_histogram'].items()},ncopy=ncopy,deficit=deficit, + weighted=adds,unit=adds,fwd_row=fwd,inv_row=inv,K=K,coarse=kap['bit_coarse'],qstar=w['lines'][0],word=sys.argv[1], + provenance=dict(adds='ADD records of the exported word = legality common_frame_ADDs = columns local_scalar_additions', + rows='columns_h signed_lift_prefix', K='2*5*T*((stock-1)+R*m*(maxops+(m-1)+m)), identity chart maxops 0', + ncopy='retained totals of the word = COPY = ERASE count')) +json.dump(out,open(sys.argv[6],'w'),indent=1) +print('finite-bill input: m %d, v %d, R %d, T %d, stock %d, NCOPY %d, unit additions %d, rows %d/%d, K %d'%(m,v,R,T,stock,ncopy,adds,fwd,inv,K)) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/certify_bit.py b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/certify_bit.py new file mode 100644 index 0000000000..b8a6c4be59 --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/certify_bit.py @@ -0,0 +1,45 @@ +"""Exact bit coarse saving + outer assembly for a PR249-format p=10 local word, using PR #315's engines +(moment.py, base_two_moment.py, outer.py) and its math_check.run logic, with a given complex coarse b.""" +import sys, json, importlib.util, os +from fractions import Fraction as Q +from collections import Counter +sys.path.insert(0,os.path.dirname(os.path.abspath(__file__))) +import cost as C +P=os.environ['PR315']+'/' +def load(n): + s=importlib.util.spec_from_file_location(n,P+n+'.py'); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); return m +moment=load('moment'); other=load('base_two_moment'); outer=load('outer') +d=sys.argv[1]; b=Q(sys.argv[2]) if len(sys.argv)>2 else Q(787306366225361,10**18) +s,fr,dim,rec=C.load_snapshot(d) +H,resid,v=C.local_profile(rec,s,dim,h=20); prof,W,m,deficit=C.five_stage(H,resid,v,h=20) +T=12; norm={int(k):int(c)*T for k,c in prof.items() if c}; Wn=Q(4*v*20+resid,20)*T; assert Wn.denominator==1; Wn=int(Wn); m=100 +mass=sum(k*c for k,c in norm.items()); print('normalized W',Wn,'calls',sum(norm.values()),'mass',mass,'deficit',m*Wn-mass,'maxchild',max(norm)) +root=moment.certify(dict(norm),m,Wn,True); c=Q(int(Q(root['lower'])*10**18),10**18) +bm=moment.moment(norm,m,Wn,c,True); nextbm=moment.moment(norm,m,Wn,c+Q(1,10**18),True); assert bm[1]<1cap-grid, 'complex-bound saving not tight against the cap' +chain=[Q(384599,10**10)] +for _ in range(3): + a=(1-sv)*sv+sv*chain[-1]; assert chain[-1]0 +try: + outer.assembly(bit,b,bridge,k+Q(1,10**18),eta=eta,beta=beta); raise SystemExit('ADJACENT ADMITTED') +except AssertionError: pass +if binding=='complex': + try: outer.assembly(cap,b,bridge,k,eta=eta,beta=beta) + except AssertionError as e: assert 'leaf_saving_above_bit' in str(e); print('complex leaf cap itself rejected (leaf_saving_above_bit), as in PR #315 math_check') + else: raise SystemExit('complex leaf cap admitted') +print('complex b =',b,float(b),'| binding:',binding) +print('KAPPA =',k,'=',format(float(k),'.12e'),'| 47 strict constraints positive, adjacent grid point rejected') +print('vs PR315 kappa 7.6423e-4: %+.3f%%'%(100*(float(k)/7.6423e-4-1))) +json.dump(dict(word=d,normalized_histogram=norm,W=Wn,m=m,bit_coarse=str(c),complex_coarse=str(b),binding=binding,kappa=str(k),kappa_float=float(k)),open(d+'/kappa.json','w'),indent=1) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/columns_h_pr346.cpp b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/columns_h_pr346.cpp new file mode 100644 index 0000000000..07b7fd220c --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/columns_h_pr346.cpp @@ -0,0 +1,42 @@ +#include "json.hpp" +#include +#include +using boost::multiprecision::cpp_int; +#include +#include +#include +#include +#include +#include +#include +using J=nlohmann::json; +struct E{int kind,dst,src,c;}; +void need(bool x,const char*s){if(!x)throw std::runtime_error(s);} +int main(int argc,char**argv){try{ +need(argc==3,"usage RAW6_RECORDS OUTPUT");std::string pre=argv[1];int v=VPORTS,r=RHELP,loc=2*v+r,global=4*v+r,temp=global; +struct Raw{int op,a,b,c,f,z;};std::ifstream f(pre,std::ios::binary|std::ios::ate);size_t sz=f.tellg();need(sz%sizeof(Raw)==0,"stream alignment");std::vectorp(sz/sizeof(Raw));f.seekg(0);f.read((char*)p.data(),sz);std::vectore;std::mapH;for(auto q:p){if(q.op==0){if(q.f)H[q.f]++;}else if(q.op==1)e.push_back({0,q.a,q.b,q.c});else if(q.op==2){H[q.z]++;e.push_back({1,loc,q.a,0});}else if(q.op==3)e.push_back({2,loc,q.a,0});else need(false,"opcode");} +J prefix=J::array();cpp_int largestF=0,largestB=0;for(int rev=0;rev<2;rev++){std::vectornorms(loc+1,1);cpp_int maxrow=1;bool isopen=false;for(size_t z=0;zmaxrow)maxrow=norms[q.dst];}else if(k==1){need(!isopen,"boundcopy");norms[loc]=norms[q.src];isopen=true;}else {need(isopen,"bounderase");norms[loc]=0;isopen=false;}}need(!isopen,"prefix copy closure");if(rev)largestB=maxrow;else largestF=maxrow;prefix.push_back({{"reverse",bool(rev)},{"cancellation_free_signed_row_l1_upper",maxrow.convert_to()},{"bits",boost::multiprecision::msb(maxrow)+1}});} +cpp_int payload=64*largestF*largestF*largestF*largestB*largestB;need(payload<(cpp_int(1)<<104),"payloadfiniteprefix2^104"); +long long copies=0,adds=0,odd=0;bool open=false;int center=-1;long long reverseCopies=0; +for(auto q:e){need(q.kind>=0&&q.kind<=2,"kind");need(q.dst>=0&&q.dst<=loc,"local dst");if(q.kind==0){need(q.src>=0&&q.src<=loc&&q.dst!=q.src,"source distinct");need(q.dst!=loc,"copy immutable");need(q.src!=loc||open,"temp not open");if(open)need(q.dst!=center,"source changes inside copied-center block");adds++;odd+=q.c&1;} +else if(q.kind==1){need(!open&&q.dst==loc&&q.src>=0&&q.srca((size_t)(global+1)*words);auto row=[&](int i){return a.data()+(size_t)i*words;};for(int i=0;i=v&&i<2*v&&w==(size_t)(i-v)/64)want^=1ull<<((i-v)%64);need(x[w]==want,"local defining-decoder full formal column");}}} +if(stage==1||stage==2||stage==4){int b=stage==1?0:stage==2?1:2;for(auto q:bridges[b])for(int i=0;i(std::chrono::steady_clock::now()-t0).count()<<"s\n";} +for(int bank=0;bank<4;bank+=2)for(int i=0;i()},{"payload_prefix_bits",boost::multiprecision::msb(payload)+1},{"new_Q_categories",{28,29}},{"local_raw_H",H},{"negative_controls",controls},{"seconds",std::chrono::duration(std::chrono::steady_clock::now()-t0).count()}};std::ofstream(argv[2])< 0: H[int(r[4])] += 1 + copies = rec[rec[:, 0] == 2] + for r in copies: + if r[5] > 0: H[int(r[5])] += 1 + init = s['initial'] + resid = sum(h - dim[init[str(r)]] for r in range(2 * v, n)) + return H, resid, v + +def five_stage(H, resid, v, h=24, stages=5): + m = stages * h + prof = collections.Counter() + for j, c in H.items(): prof[j] += stages * c + for j in (2*h - 2, h - 1, 2*h + 2, 4): prof[j] += 2 * v + W = mpf(4 * v) + mpf(resid) / h + mass = sum(j * c for j, c in prof.items()) + return prof, W, m, W * m - mass + +def solve_moment(prof, W, m, bad=mpf('1e-16')): + calls = sum(prof.values()) + items = [(mpf(j) / m, c) for j, c in prof.items()] + def mu(sv): + t = 1 - sv + return (sum(c * x ** t for x, c in items) + bad * 32 * m * m * calls * (mpf(1) / m) ** t) / W - 1 + return findroot(mu, mpf('0.0007')) + +def evaluate(rec, s, dim, h=24): + H, resid, v = local_profile(rec, s, dim, h) + prof, W, m, deficit = five_stage(H, resid, v, h) + sv = solve_moment(prof, W, m) + return dict(saving=sv, kappa_approx=sv / (1 + sv), W=W, deficit=deficit, m=m, + calls=sum(prof.values()), local=dict(sorted(H.items())), resid=resid) + +if __name__ == '__main__': + import sys + s, fr, dim, rec = load_snapshot(sys.argv[1]) + r = evaluate(rec, s, dim) + print({k: (float(v) if hasattr(v, 'real') and not isinstance(v, dict) else v) for k, v in r.items() if k != 'local'}) diff --git a/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/json.hpp b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/json.hpp new file mode 100644 index 0000000000..82d69f7c5d --- /dev/null +++ b/research/e8-signed-donor-gauge-bit-closure/bit-source/code/bit/regression/json.hpp @@ -0,0 +1,25526 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_DIAGNOSTIC_POSITIONS + #define JSON_DIAGNOSTIC_POSITIONS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_DIAGNOSTIC_POSITIONS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#ifdef JSON_HAS_CPP_17 + #include // optional +#endif +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#if JSON_DIAGNOSTICS + #include // accumulate +#endif +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) + #define JSON_HAS_CPP_23 + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 201402L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifndef JSON_HAS_STATIC_RTTI + #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + #define JSON_HAS_STATIC_RTTI 1 + #else + #define JSON_HAS_STATIC_RTTI 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType, \ + class CustomBaseClass> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1) : nlohmann_json_default_obj.v1; + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.11.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.11.3 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/ +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + template::value, int> = 0> \ + void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE +@since version 3.12.0 +@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/ +*/ +#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + template::value, int> = 0> \ + void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows calling any std function as if (e.g., with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // char_traits +#include // tuple +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector, // cppcheck-suppress syntaxError + class CustomBaseClass = void> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +///////////////// +// char_traits // +///////////////// + +// Primary template of char_traits calls std char_traits +template +struct char_traits : std::char_traits +{}; + +// Explicitly define char traits for unsigned char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = unsigned char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(std::char_traits::eof()); + } +}; + +// Explicitly define char traits for signed char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = signed char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(std::char_traits::eof()); + } +}; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& +is_complete_type < +detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template