From 3a698e614330df77622909104ff7ae8c73e10806 Mon Sep 17 00:00:00 2001 From: Ruge Lin Date: Wed, 23 Sep 2026 05:11:40 +0800 Subject: [PATCH] Audit subset-state research and adopt Markdown-only documentation --- .github/workflows/tests.yml | 5 + .gitignore | 6 + AGENTS.md | 10 + CHANGELOG.md | 18 +- CITATION.cff | 9 +- PROVENANCE.md | 167 ++----- README.md | 207 ++------ data/README.md | 20 +- docs/CITATION_AUDIT.txt | 18 - docs/FINAL_MANUSCRIPT_REVIEW.md | 154 ------ docs/REFERENCES.md | 23 + docs/REPRODUCIBILITY.md | 72 +++ docs/RESEARCH.md | 178 +++++++ docs/SANITY_CHECK.md | 40 ++ outputs/README.md | 10 +- outputs/fig1/fig1_concentration.pdf | Bin 26451 -> 0 bytes outputs/fig2/fig2_peak_scaling.pdf | Bin 18141 -> 0 bytes outputs/fig3/fig3_spectral_bulk.pdf | Bin 27821 -> 0 bytes outputs/fig4/fig4_approximation.pdf | Bin 29472 -> 0 bytes outputs/fig5/fig5_qft_residue_controls.pdf | Bin 30486 -> 0 bytes outputs/fig6/fig6_renyi.pdf | Bin 50639 -> 0 bytes outputs/fig7/fig7_partitions.pdf | Bin 18654 -> 0 bytes .../peak_verification_n10.pdf | Bin 19095 -> 0 bytes .../peak_verification_n12.pdf | Bin 18964 -> 0 bytes .../peak_verification_n14.pdf | Bin 19141 -> 0 bytes .../peak_verification_n16.pdf | Bin 18852 -> 0 bytes .../peak_verification_n18.pdf | Bin 18916 -> 0 bytes .../peak_verification_n20.pdf | Bin 18754 -> 0 bytes .../peak_verification_summary.pdf | Bin 16340 -> 0 bytes pyproject.toml | 2 +- requirements-tested.txt | 4 +- scripts/check_repository.py | 52 +++ scripts/fig1_concentration.py | 4 +- scripts/fig2_peak_scaling.py | 4 +- scripts/fig3_spectral.py | 4 +- scripts/fig4_approximation.py | 4 +- scripts/fig5_qft_residue_controls.py | 18 +- scripts/fig6_renyi.py | 4 +- scripts/fig7_partitions.py | 4 +- scripts/final_scientific_validation.py | 441 ++++++++---------- scripts/peak_scaling_verification.py | 8 +- scripts/plot_fig1_from_csv.py | 2 +- scripts/plot_fig2_from_csv.py | 2 +- scripts/plot_fig3_from_csv.py | 2 +- scripts/plot_fig4_from_csv.py | 2 +- scripts/plot_fig6_from_csv.py | 2 +- scripts/plot_fig7_from_csv.py | 2 +- scripts/plot_peak_verification_from_csv.py | 2 +- scripts/regenerate_fig5_baseline.py | 79 ++-- scripts/reproduce_publication_figures.py | 144 ++++-- scripts/run_residue_controls.py | 2 +- scripts/validate_residue_results.py | 339 +++++++++++--- subset_states/core.py | 137 ++++-- subset_states/csv_plotting.py | 38 +- subset_states/plotting.py | 6 +- tests/test_figure_workflow.py | 95 ++++ tests/test_input_validation.py | 139 ++++++ tests/test_validation.py | 172 +++++++ validation/FINAL_SCIENTIFIC_VALIDATION.txt | 35 -- .../REFERENCE_FINAL_SCIENTIFIC_VALIDATION.txt | 35 -- validation/RELEASE_VALIDATION.txt | 17 - validation/SCIENTIFIC_SANITY_CHECKS.md | 49 ++ validation/evidence_sha256.json | 57 +++ 63 files changed, 1786 insertions(+), 1058 deletions(-) create mode 100644 AGENTS.md delete mode 100644 docs/CITATION_AUDIT.txt delete mode 100644 docs/FINAL_MANUSCRIPT_REVIEW.md create mode 100644 docs/REFERENCES.md create mode 100644 docs/REPRODUCIBILITY.md create mode 100644 docs/RESEARCH.md create mode 100644 docs/SANITY_CHECK.md delete mode 100644 outputs/fig1/fig1_concentration.pdf delete mode 100644 outputs/fig2/fig2_peak_scaling.pdf delete mode 100644 outputs/fig3/fig3_spectral_bulk.pdf delete mode 100644 outputs/fig4/fig4_approximation.pdf delete mode 100644 outputs/fig5/fig5_qft_residue_controls.pdf delete mode 100644 outputs/fig6/fig6_renyi.pdf delete mode 100644 outputs/fig7/fig7_partitions.pdf delete mode 100644 outputs/peak_verification/peak_verification_n10.pdf delete mode 100644 outputs/peak_verification/peak_verification_n12.pdf delete mode 100644 outputs/peak_verification/peak_verification_n14.pdf delete mode 100644 outputs/peak_verification/peak_verification_n16.pdf delete mode 100644 outputs/peak_verification/peak_verification_n18.pdf delete mode 100644 outputs/peak_verification/peak_verification_n20.pdf delete mode 100644 outputs/peak_verification/peak_verification_summary.pdf create mode 100644 scripts/check_repository.py create mode 100644 tests/test_figure_workflow.py create mode 100644 tests/test_input_validation.py create mode 100644 tests/test_validation.py delete mode 100644 validation/FINAL_SCIENTIFIC_VALIDATION.txt delete mode 100644 validation/REFERENCE_FINAL_SCIENTIFIC_VALIDATION.txt delete mode 100644 validation/RELEASE_VALIDATION.txt create mode 100644 validation/SCIENTIFIC_SANITY_CHECKS.md create mode 100644 validation/evidence_sha256.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6c6bf7f..8636759 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,6 +7,9 @@ on: jobs: tests: runs-on: ubuntu-latest + env: + OPENBLAS_NUM_THREADS: "1" + OMP_NUM_THREADS: "1" strategy: matrix: python-version: ["3.10", "3.12"] @@ -22,3 +25,5 @@ jobs: - run: python -m pip install -r requirements.txt - run: python scripts/run_smoke_tests.py - run: python scripts/final_scientific_validation.py + - run: python scripts/check_repository.py + - run: python scripts/reproduce_publication_figures.py diff --git a/.gitignore b/.gitignore index 8c47abb..aa93132 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,9 @@ final_audit.txt *.zip *.tar.gz *.tgz + +# Regenerated checks and figures +generated/ +*.egg-info/ +build/ +dist/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..82e77e9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,10 @@ +# Repository working rules + +- Keep research prose and audit reports in Markdown. Use plain-text or Unicode mathematics; do not introduce TeX sources, BibTeX, PDF deliverables, or a TeX build dependency. +- Preserve the existing license and author attribution. +- Keep proved finite-ensemble identities, asymptotic consequences, heuristic approximations, finite numerical observations, and historical estimates explicitly distinguished. +- Never infer a von Neumann entropy maximum from the purity minimum or its dense-side crossover. Never label local peak checks as a global search. +- Treat `data/` CSV files and `outputs/` CSV/PNG files as released evidence. Default computations write under `generated/`. Evidence changes require an explicit reason and an updated provenance record; never silently refresh the checksum manifest. +- Keep public preprint metadata tied to a verified public version, rather than an unpublished working title. +- Before delivery run the unit tests, `scripts/final_scientific_validation.py`, `scripts/check_repository.py`, and a CSV figure redraw if plotting changed. For computational changes use a small smoke run; do not launch high-n searches without a concrete research need. +- A validator PASS is scoped to its listed checks. It is not a novelty or submission-readiness verdict. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bb9109..79ae4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,24 @@ # Changelog +## Markdown cleanup — 2026-09-22 + +- Replaced manuscript-readiness reports with a scoped sanity check, research proofs, reproducibility instructions, and primary references in Markdown. +- Corrected the public preprint title and year; aligned the existing rc2 software version labels without creating a release tag. +- Fixed support validation, coefficient-matrix basis ordering, and invalid Rényi inputs. +- Reworked scientific validation to read released data and compare production routines, with explicit failures that survive Python optimization. +- Made all seven CSV figure redraws and reduced simulations write under `generated/`; changed default graphics to PNG. +- Removed PDF duplicates and obsolete text reports. Preserved all released CSV/PNG evidence and the license byte-for-byte, with checksums. + + ## 1.0.0-rc2 — 2026-08-21 - Added the general power-law support window - $1/2<\gamma<3/4$ implied by the exact average-purity formula. -- Distinguished the purity-optimal interior balance $\gamma=2/3$ from the - dense-side boundary $\gamma=3/4$. + 1/2 < γ < 3/4 implied by the exact average-purity formula. +- Distinguished the purity-optimal interior balance γ = 2/3 from the + dense-side boundary γ = 3/4. - Clarified that the finite-size peak-support regression is a separate numerical observation and not an asymptotic consequence of the purity bound. -- Standardized ordinary Shannon-entropy notation from $H_2$ to $H$. +- Standardized ordinary Shannon-entropy notation from H₂ to H. - Kept all seven released figures, Table I values, and numerical datasets unchanged. diff --git a/CITATION.cff b/CITATION.cff index 1df213b..40ab912 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,8 +1,7 @@ cff-version: 1.2.0 -message: "Please cite the accompanying paper and this software release." +message: "Please cite the public preprint and the repository commit used." title: "Support-size entanglement trajectories of random subset states: code and data" -version: "1.0.0-rc2" -date-released: 2026-08-21 +version: "1.0.0rc2" repository-code: "https://github.com/GoGoKo699/Subset-states" url: "https://arxiv.org/abs/2501.06292" license: MIT @@ -18,8 +17,8 @@ authors: affiliation: "Centre for Quantum Technologies, National University of Singapore" preferred-citation: type: article - title: "Support-size entanglement trajectories of random subset states" - year: 2026 + title: "Arithmetic sequences as quantum states" + year: 2025 authors: - family-names: Lin given-names: Ruge diff --git a/PROVENANCE.md b/PROVENANCE.md index cb53090..19613da 100644 --- a/PROVENANCE.md +++ b/PROVENANCE.md @@ -1,154 +1,45 @@ -# Numerical provenance and robustness notes +# Evidence and provenance -This document records the evidence hierarchy behind the publication release. -It is intentionally more technical than the repository landing page. +This document describes the evidence present in the repository, rather than treating earlier review verdicts as evidence. The cleanup started from commit [4cb99f1](https://github.com/GoGoKo699/Subset-states/tree/4cb99f109194124f500d75dd065ff43581a2682d), dated 21 August 2026. -## Table I peak estimates +## Evidence hierarchy -`data/table_i_peaks.csv` contains the retained production estimates -$(\widehat{M}_n,\widehat{S}_n)$ for even $n=10,\ldots,30$. +| Material | What can be checked | Remaining limitation | +|---|---|---| +| Exact mean-state, purity, diagonal-entropy and residue formulas | Counting proofs in [research notes](docs/RESEARCH.md), independent enumeration, production-code comparisons | Enumeration alone is not a proof for arbitrary size | +| `data/table_i_peaks.csv` | Transcription of Table I in the [2025 preprint](https://arxiv.org/html/2501.06292v1), arithmetic regressions, agreement with released derived tables | No complete original global-search records, raw peak samples, search uncertainty or full execution provenance | +| `outputs/peak_verification/` | Local grids and quadratic fits for n = 10, 12, 14, 16, 18, 20 | These are neighborhood checks around given centers, not global rediscovery; files named `samples` hold aggregate statistics at each M | +| `outputs/fig1/` | Released individual entropy samples and summaries | Support labels and a full original execution manifest are absent | +| `outputs/fig3/` | One n = 24 reduced-state spectrum | One sample does not establish typicality or a random-matrix limit | +| `outputs/fig4/`, `outputs/fig6/` | Summary curves and plotting inputs | Complete per-state records are not released here | +| `data/residue_matched_*` | 12,000 paired entropy observations, 12 group summaries, seeds, and residue populations | Raw support labels are absent; a limited seed replay checks implementation consistency, not every stored observation | +| `outputs/fig7/` | Partition entropy samples for two selected n = 20 states | Does not establish a uniform statement about all supports or all cuts | -The complete intermediate global-search records for -$n=22,24,26,28,30$ were not retained. Repeating those searches with the -released dense exact-entropy implementation is computationally expensive. The -recorded point estimates are therefore preserved as historical production data, -not reconstructed raw data. +CSV files and retained PNGs are unchanged by the cleanup. Their SHA-256 checksums are recorded in [the evidence manifest](validation/evidence_sha256.json), alongside the original license. This freezes the inherited evidence; it does not certify the original data-generation process. -The repository supplies `scripts/peak_scaling_verification.py`, which samples a -local window around a recorded $\widehat{M}_n$ and fits a quadratic in -$\log_2 M$. This verifies neighbourhood consistency; it is not a global -rediscovery procedure. +## Retained peaks and finite fits -## Robustness of the finite-size regressions +All eleven Table I rows, for even n = 10 through 30, appear in the public 2025 preprint. Their publication establishes the source of the numbers, not independent reproducibility of the global searches. In particular, the complete intermediate searches at n = 22, 24, 26, 28, 30 were not retained. -Using all eleven retained rows, $n=10,\ldots,30$, +The unweighted regressions recomputed from the CSV are: -$$ -\widehat{S}_n=0.509300\,n-0.990091, -$$ +| Range | Entropy fit | Log-support fit | +|---|---|---| +| n = 10–30 | Ŝ = 0.509300n − 0.990091 | log₂ M̂ = 0.703541n − 0.357734 | +| n = 10–20 | Ŝ = 0.514457n − 1.065190 | log₂ M̂ = 0.693450n − 0.210116 | -$$ -\log_2\widehat{M}_n=0.703541\,n-0.357734. -$$ +The slopes differ by roughly 1.01% and 1.43%, respectively, relative to the full-range slopes. This is a descriptive sensitivity check. It supplies neither missing uncertainty estimates nor a proof that the historical estimates are unbiased. Regression standard errors describe scatter of the rounded table entries, not uncertainty in the original search. -Restricting the fit to the computationally accessible range -$n=10,\ldots,20$ gives +The effective ratio log₂ M̂/n grows from about 0.674 to 0.694 across the table. These finite observations establish no limiting exponent. In particular, the purity crossover at exponent 3/4 does not predict convergence of the entropy maximizer to that exponent. An entropy slope above 1/2 also cannot persist asymptotically, since S ≤ n/2. -$$ -\widehat{S}_n=0.514457\,n-1.065190, -$$ +## Residue-matched comparisons -$$ -\log_2\widehat{M}_n=0.693450\,n-0.210116. -$$ +The structured supports contain labels x with 1 ≤ Ω(x) ≤ k, where Ω counts prime factors with multiplicity and k = 1, 2, 3. For n = 14, each support is compared with four ensembles matching populations modulo 2ᵗ, for t = 0, 1, 2, 3. Each group contains 1,000 samples, and the same sampled support is evaluated before and after the QFT. -The slope changes are approximately 1.01% for peak entropy and 1.43% for peak -support size. The unreconstructed larger-size rows extend the observed trend but -do not create or materially change it. Neither regression is claimed as an -asymptotic theorem. +A remaining deficit means that uniform placement conditional on those counts does not reproduce the structured entropy. It does not identify the cause or a unique fingerprint of primality. Zero sampled null entropies below a structured value is a finite rank observation, not a zero tail probability. The exact computational-basis residue ceiling is not automatically a Fourier-basis ceiling. -## Analytic scale hierarchy and peak interpretation +## Historical material -For a power-law support $M=cN^\gamma$ with fixed $c>0$, the exact -average-purity formula has the leading structure +The old manuscript-readiness review, bibliography audit, duplicated text validation reports, and PDF copies of PNG figures were removed from the active tree. They remain available at the starting commit above. No manuscript source or complete revised bibliography was present in that tree, so this cleanup does not claim a lossless conversion of an unseen manuscript. -$$ -\overline{P}_{N,M} -= -2N^{-1/2} -+c^{-1}N^{-\gamma} -+c^2N^{2\gamma-2} -+\text{lower-order terms}. -$$ - -This gives the following hierarchy. - -- Every fixed $1/2<\gamma<3/4$ yields - - $$ - \overline{S}_{N,M}\geq \frac{n}{2}-1-o(1). - $$ - -- The exponent $\gamma=2/3$ uniquely balances the sparse and rectangle - corrections. Optimizing the remaining coefficient gives - $M=2^{-1/3}N^{2/3}+O(1)$. - -- The exponent $\gamma=3/4$ is the dense-side boundary at which the rectangle - term becomes comparable with the $2N^{-1/2}$ balanced-cut contribution. At - $M=cN^{3/4}$, - - $$ - \overline{P}_{N,M} - = - (2+c^2)N^{-1/2}+o(N^{-1/2}). - $$ - -These are statements about the exact average purity and the entropy lower bound -derived from it. They do not locate the maximizer of the mean von Neumann -entropy. - -For the retained numerical peaks, the pointwise effective exponent - -$$ -\gamma_n^{\mathrm{eff}} -= -\frac{\log_2\widehat M_n}{n} -$$ - -increases from approximately $0.674$ at $n=10$ to $0.694$ at $n=30$. -The full-range fitted slope is $0.703541$. This motivates comparison with the -$3/4$ dense-side boundary but does not establish convergence to $3/4$ or any -other asymptotic peak law. No released figure or numerical dataset was altered -for this interpretation. - -## Exact analytical validation - -The release exposes code for: - -- the exact fixed-cardinality ensemble-mean reduced state; -- the exact ensemble-average purity; -- the hypergeometric diagonal-entropy curve; -- the residue-class entropy ceiling - $S(A)\leq n/2-t+H(\mathbf{p}^{(t)})$. - -`tests/test_exact_purity_and_residue.py` and -`scripts/final_scientific_validation.py` independently check these formulas by -exhaustively enumerating all 65,535 nonempty supports at $n=4$. - -## Residue-matched reference ensembles - -For each almost-prime support $U_{N,k}$ with $k=1,2,3$, the released -Figure 5 analysis uses four nested null ensembles: - -| matched low bits $t$ | retained information | -|---:|---| -| 0 | support cardinality only | -| 1 | even/odd populations | -| 2 | populations modulo 4 | -| 3 | populations modulo 8 | - -For every $(k,t)$, 1,000 supports are independently sampled while preserving -the complete residue-count vector. The same support is evaluated in the -computational and Fourier bases, giving paired observations. Seeds are recorded -in `data/residue_matched_summary.csv`; all 12,000 paired samples are in -`data/residue_matched_samples.csv`. - -The residual deficit after matching a constraint means “not explained by the -matched information under uniform placement.” It is not claimed to be a unique -fingerprint of primality or to isolate all higher-order arithmetic correlations. - -## Figure files and generated data - -The manuscript-ready vector PDFs in `outputs/fig1/` through `outputs/fig7/` are -the files used for the final manuscript candidate. Existing historical output -CSVs in the GitHub repository may be retained when applying this release as an -overlay. Figure 5’s final raw and summary data are included directly in this -release because the constrained-null calculation is new and central to the -revised manuscript. - -## Historical best-of-random-candidates experiment - -The former “greedy” Figure 8 experiment is not part of the manuscript. It -screened independent random candidates and selected the one with the largest -mean balanced-cut entropy; it was not a greedy construction. The code is kept -under `exploratory/best_of_random_candidates/` with corrected terminology. +The historical best-of-random-candidates experiment remains under [exploratory](exploratory/best_of_random_candidates/README.md). It selects among independent random candidates; it is not a greedy construction. diff --git a/README.md b/README.md index 58bdba4..057511f 100644 --- a/README.md +++ b/README.md @@ -1,196 +1,61 @@ -# Support-size entanglement trajectories of random subset states - -Code, data, released figures, and validation for the manuscript -**“Support-size entanglement trajectories of random subset states.”** -The manuscript updates the existing preprint record [arXiv:2501.06292](https://arxiv.org/abs/2501.06292). - -Equal-positive-amplitude subset states exhibit a rise–peak–fall entanglement -trajectory as their computational-basis support grows. This repository contains -the fixed-cardinality ensemble calculations, exact-moment checks, numerical -figure scripts, and constrained reference ensembles used in the paper. - -## Key results represented in this repository - -- Exact ensemble-mean reduced state for uniformly random supports of fixed size. -- Exact average purity across a balanced bipartition, yielding a rigorous - power-law support window, an optimal interior balance, and a dense-side - boundary. -- Numerical rise–peak–fall trajectories and retained peak estimates through - $n=30$. -- Exact hypergeometric diagonal-entropy and residue-class entropy bounds. -- Cardinality-, parity-, mod-4-, and mod-8-matched reference ensembles for - almost-prime supports, evaluated before and after a quantum Fourier transform. - -## Analytic scale hierarchy - -Let $N=2^n$ and write a power-law support size as $M=cN^\gamma$, with -$c>0$. The exact fixed-cardinality average-purity formula has the leading -structure - -```math -\overline{P}_{N,M} -= -2N^{-1/2} -+c^{-1}N^{-\gamma} -+c^2N^{2\gamma-2} -+\text{lower-order terms}. -``` +# Subset states: support size and entanglement -**Near-maximal window.** Every fixed exponent -$\frac{1}{2}<\gamma<\frac{3}{4}$ gives +How does entanglement change when an equal-positive-amplitude quantum state occupies more computational-basis labels? A single label and the full basis both give product states. Random supports in between can give high bipartite entanglement. -```math -\overline{S}_{N,M} -\geq -\frac{n}{2}-1-o(1). -``` +This repository contains exact finite-ensemble formulas, numerical experiments, and released evidence for that question. **The exact mean-state and purity results survive the September 2026 sanity check. The asymptotic location of the von Neumann entropy maximum and the novelty of the revised research contribution remain unresolved.** -**Purity-optimal interior scale.** The exponent -$\gamma=\frac{2}{3}$ uniquely balances the sparse -$N^{-\gamma}$ correction and the dense rectangle -$N^{2\gamma-2}$ correction. Optimizing the remaining prefactor gives +The related public preprint is [*Arithmetic sequences as quantum states* (2025), arXiv:2501.06292v1](https://arxiv.org/abs/2501.06292v1), by Ruge Lin, Germán Sierra, and José I. Latorre. “Support-size entanglement trajectories of random subset states” was the working title of a later revision; it is not the title of the current arXiv record checked on 22 September 2026. -```math -M -= -2^{-1/3}N^{\frac{2}{3}}+O(1). -``` +## Read the project -**Dense-side boundary.** The exponent $\gamma=\frac{3}{4}$ is the point at -which the rectangle contribution enters at the same $N^{-1/2}$ order as the -balanced-cut background. +| Document | Purpose | +|---|---| +| [Research notes](docs/RESEARCH.md) | Definitions, exact formulas and proofs, approximations, and figures | +| [Sanity check](docs/SANITY_CHECK.md) | Findings, corrections, and limits of the validation | +| [Provenance](PROVENANCE.md) | What the released data can and cannot substantiate | +| [Reproducibility](docs/REPRODUCIBILITY.md) | Commands, environments, and computational costs | +| [References](docs/REFERENCES.md) | Verified primary sources and the open novelty question | -The numerical maximum of the mean von Neumann entropy is a separate quantity. -Over $n=10,\ldots,30$, the retained estimates give +All research prose is Markdown with plain-text or Unicode mathematics. There is no TeX source, bibliography build, or PDF workflow. Python code, CSV evidence, PNG figures, and machine-readable metadata retain their useful formats. -```math -\log_2 \widehat{M}_n -= -0.703541\,n-0.357734. -``` +## What is established? -The pointwise effective exponent is +For an even number of qubits n, write N = 2ⁿ and d = 2^(n/2). Choose M distinct basis labels uniformly, assign each amplitude 1/√M, and split the qubits into two fixed halves. -```math -\gamma_n^{\mathrm{eff}} -= -\frac{\log_2 \widehat{M}_n}{n}, -\qquad -\gamma_{10}^{\mathrm{eff}}\approx 0.674, -\qquad -\gamma_{30}^{\mathrm{eff}}\approx 0.694. -``` +| Result | Status | +|---|---| +| Exact ensemble-mean reduced state and average purity | Derived by counting; independently checked on all nonempty supports at n = 4 | +| Mean entropy at least n/2 − 1 − o(1), for M = cN^γ and 1/2 < γ < 3/4 | Consequence of the exact purity formula, for fixed c > 0 | +| Purity-minimizing support M = 2^(−1/3)N^(2/3) + O(1) | Analytic result; does not locate the von Neumann entropy maximum | +| Rise–peak–fall curves and retained peak estimates through n = 30 | Finite numerical evidence; original global-search records are incomplete | +| Hypergeometric diagonal-entropy bound and low-bit residue ceiling | Exact bounds with stated ensemble/cut assumptions | +| Almost-prime deficits after matching cardinality and residues | Finite comparisons at n = 14; no unique arithmetic fingerprint established | -It increases over the retained range. This motivates comparison with the -$\frac{3}{4}$ dense-side boundary but does not establish an asymptotic peak law. +![Released support-size trajectory](outputs/fig1/fig1_concentration.png) -## Repository map +This figure summarizes sampled finite systems. It is not a concentration theorem or an asymptotic scaling result. -```text -subset_states/ reusable scientific routines -scripts/ figure, validation, and local-verification entry points -data/ Table I and released matched-null datasets -outputs/ manuscript-ready figures and generated outputs -tests/ lightweight and exhaustive small-system regression tests -validation/ final independent validation reports -exploratory/ historical experiments not used in the manuscript -docs/ audit and release documentation -``` - -## Quick start +## Run the checks ```bash python3 -m venv .venv source .venv/bin/activate -python3 -m pip install -r requirements.txt -python3 scripts/run_smoke_tests.py -``` - -Run the independent publication validation: - -```bash -python3 scripts/final_scientific_validation.py -``` - -Regenerate the fast deterministic figures and verify that all seven released -PDFs are present: - -```bash -python3 scripts/reproduce_publication_figures.py -``` - -A reduced computational smoke run is available through: - -```bash -python3 scripts/reproduce_publication_figures.py --smoke -``` - -The full publication computations can be launched with `--full`, but several -runs are intentionally expensive. - -## Publication figures - -| Figure | Scientific content | Main script | Released output | -|---|---|---|---| -| 1 | Support-size trajectory and cut comparison | `scripts/fig1_concentration.py` | `outputs/fig1/fig1_concentration.pdf` | -| 2 | Peak entropy and support-size scaling | `scripts/fig2_peak_scaling.py` | `outputs/fig2/fig2_peak_scaling.pdf` | -| 3 | Reduced-state spectrum near the peak | `scripts/fig3_spectral.py` | `outputs/fig3/fig3_spectral_bulk.pdf` | -| 4 | Sparse and dense approximations | `scripts/fig4_approximation.py` | `outputs/fig4/fig4_approximation.pdf` | -| 5 | Cardinality and residue controls | `scripts/fig5_qft_residue_controls.py` | `outputs/fig5/fig5_qft_residue_controls.pdf` | -| 6 | Rényi trajectories | `scripts/fig6_renyi.py` | `outputs/fig6/fig6_renyi.pdf` | -| 7 | Entropy over balanced cuts | `scripts/fig7_partitions.py` | `outputs/fig7/fig7_partitions.pdf` | - -Figure 5 can be redrawn exactly from the released CSV files. The matched-null -raw dataset contains 12,000 paired computational/Fourier samples. - -## Table I and local verification - -`data/table_i_peaks.csv` stores the retained peak estimates used in the paper. -The command - -```bash -python3 scripts/peak_scaling_verification.py --n-values 10 12 14 +python -m pip install -r requirements.txt +python scripts/run_smoke_tests.py +python scripts/final_scientific_validation.py +python scripts/check_repository.py ``` -performs a local neighbourhood check around selected tabulated values. It is not -a reconstruction of the original global search. Full technical provenance and -the robustness comparison are documented in [PROVENANCE.md](PROVENANCE.md). - -## Figure 5 constrained ensembles - -The released files are: - -```text -data/fig5_random_qft_summary.csv -data/fig5_almost_prime_unions.csv -data/residue_matched_summary.csv -data/residue_matched_samples.csv -data/residue_entropy_bounds.csv -``` - -Regenerate the null samples with: +Redraw all seven figures from released CSV files, without repeating simulations: ```bash -python3 scripts/run_residue_controls.py -python3 scripts/fig5_qft_residue_controls.py +python scripts/reproduce_publication_figures.py ``` -## Reproducibility levels - -1. **Fast:** unit tests, exact small-system checks, Figure 2, and Figure 5 redraw. -2. **Standard:** regenerate selected numerical figures with reduced or custom - workloads. -3. **Computational:** use publication defaults for the full sampling runs and - local high-dimensional peak checks. - -All stochastic scripts expose seeds. The tested software environment is recorded -in `requirements-tested.txt`. - -## Citation +The historical command name is retained for compatibility. New outputs go under `generated/`; the released evidence stays in `data/` and `outputs/`. See [reproducibility](docs/REPRODUCIBILITY.md) for reduced simulations and expensive runs. -Use the citation metadata in `CITATION.cff`. The preferred paper citation is the -updated arXiv record and, once available, the journal version. +## Scope and citation -## License +This is a research repository, not a submission-readiness certificate. The original global searches, especially n = 22–30, have not been reconstructed. Small changes in fitted slopes when dropping those rows do not resolve that provenance gap. Broader novelty claims require comparison with existing sparse-state and fixed-size subset-state results. -The repository is released under the MIT License. See `LICENSE`. +Use [CITATION.cff](CITATION.cff) for the public preprint, and cite a specific repository commit when using this revised implementation or data. The existing [MIT license](LICENSE) and author attribution are preserved. diff --git a/data/README.md b/data/README.md index 26a9a9d..c76bae8 100644 --- a/data/README.md +++ b/data/README.md @@ -1,11 +1,15 @@ # Released data -- `table_i_peaks.csv`: retained peak estimates used in Table I and Figure 2. -- `peak_verification_schedule.csv`: default local-check workloads. -- `fig5_random_qft_summary.csv`: random-support baseline for Figure 5(a). -- `fig5_almost_prime_unions.csv`: deterministic almost-prime points. -- `residue_matched_summary.csv`: constrained-null summary statistics. -- `residue_matched_samples.csv`: all 12,000 paired constrained-null samples. -- `residue_entropy_bounds.csv`: residue populations and exact entropy ceilings. +These inherited CSV files are preserved as evidence. Regeneration defaults write under `generated/`; they do not replace these files. -See `../PROVENANCE.md` for interpretation and limitations. +| File | Contents | +|---|---| +| [table_i_peaks.csv](table_i_peaks.csv) | Historical peak estimates from Table I of the 2025 preprint; original global searches are not fully reconstructable | +| [peak_verification_schedule.csv](peak_verification_schedule.csv) | Default local-check workloads; high-n entries are computationally expensive | +| [fig5_random_qft_summary.csv](fig5_random_qft_summary.csv) | Cardinality-matched computational/Fourier baseline summaries | +| [fig5_almost_prime_unions.csv](fig5_almost_prime_unions.csv) | Deterministic almost-prime support entropies | +| [residue_matched_summary.csv](residue_matched_summary.csv) | Twelve matched-ensemble summaries and seeds | +| [residue_matched_samples.csv](residue_matched_samples.csv) | 12,000 paired entropy observations; no raw support labels | +| [residue_entropy_bounds.csv](residue_entropy_bounds.csv) | Residue populations and exact computational-basis entropy ceilings | + +See [provenance](../PROVENANCE.md) for limitations and [research notes](../docs/RESEARCH.md) for definitions. diff --git a/docs/CITATION_AUDIT.txt b/docs/CITATION_AUDIT.txt deleted file mode 100644 index 889441a..0000000 --- a/docs/CITATION_AUDIT.txt +++ /dev/null @@ -1,18 +0,0 @@ -FINAL CITATION AUDIT -==================== - -Citation occurrences in main.tex: 58 -Unique citation keys used: 33 -Entries in Citations.bib: 33 -Missing bibliography keys: none -Unused bibliography entries: none -Duplicate bibliography keys: none -Biber warnings or errors: none - -Positioning checks completed: -- Prior fixed-size random-subset moment work is cited where the exact moment section begins. -- The compressed-support result is distinguished from pseudorandomness and does not claim to rederive indistinguishability results. -- Sparse-support, constrained-ensemble, prime-state, QFT, random-matrix, Page, and Renyi references are attached to their specific scientific roles. -- No citation cluster is used to imply prior authorship of the manuscript's new exact purity or residue-ceiling results. - -STATUS: PASS diff --git a/docs/FINAL_MANUSCRIPT_REVIEW.md b/docs/FINAL_MANUSCRIPT_REVIEW.md deleted file mode 100644 index 0289764..0000000 --- a/docs/FINAL_MANUSCRIPT_REVIEW.md +++ /dev/null @@ -1,154 +0,0 @@ -# Historical target-reader and submission-level review - -> **Historical record.** This review is dated 17 August 2026 and predates the -> three-scale manuscript revision, the public repository release, and the -> `1.0.0-rc2` metadata. It is retained as a development record. For current -> scientific provenance, see [PROVENANCE.md](../PROVENANCE.md) and the files -> under [`validation/`](../validation/). - -**Manuscript:** *Support-size entanglement trajectories of random subset states* -**Target:** *Journal of Physics A: Mathematical and Theoretical* -**Review date:** 17 August 2026 - -## Verdict - -The manuscript is scientifically coherent, internally consistent, readable as a quantum-information paper, and ready for author-level confirmation and repository release. I found no remaining mathematical, numerical, citation, or LaTeX defect that blocks submission. - -The main result hierarchy is now clear: - -1. exact ensemble mean reduced state; -2. exact average-purity theorem; -3. rigorous near-maximal average-entanglement guarantee at support size \(2^{(2/3)n+O(1)}\); -4. finite-size rise--peak--fall von Neumann trajectory through \(n=30\); -5. sparse hypergeometric and dense separated-mode explanations; -6. cardinality- and residue-matched application to almost-prime supports. - -The paper no longer depends on the historical arithmetic framing for its identity. The almost-prime analysis functions as a controlled application of the general subset-state framework. - -## Substantive refinements made in the final pass - -### Prior-work positioning - -The exact-moment section now acknowledges recent multi-copy moment analyses of fixed-size random subset states. The manuscript states precisely that its contribution is the direct balanced-bipartition formula for the ensemble-mean reduced state and average purity, rather than implying that fixed-size subset-state moments were previously unstudied. - -The finite-size scaling section now relates the rigorous \(N^{2/3}\) support scale to known pseudorandom-subset-state regimes while explicitly distinguishing entanglement from indistinguishability. - -### Claim calibration - -The abstract now says that the estimated peak support grows exponentially while occupying a decreasing fraction of the basis **over the studied range**. It does not convert the finite-size fit into an asymptotic law. - -Single-instance results are consistently described as sampled or selected states. Figure 3 is one sampled spectrum; Figure 7 concerns two selected states. No concentration theorem is inferred from those examples. - -### Dense-side interpretation - -The dense approximation is written in the transparent form - -\[ -T_{N,M}=h_2(\lambda_{\mathrm{mf}}) - +(1-\lambda_{\mathrm{mf}}) - \left(\log_2 d-\frac{1}{2\ln2}\right), -\] - -which separates the binary mixing entropy of the coherent mode from the rescaled Page-like bulk entropy. This is algebraically identical to the previous expression. - -### Residue-matched application - -Fourier-space matched means and deficits are now explicitly defined: - -\[ -\mu_t^F(B)=\mathbb E_{A\sim\mathcal E_t(B)}S_F(A), -\qquad -\Delta_t^F(B)=\mu_t^F(B)-S_F(B). -\] - -The manuscript uses **deficit reduction** rather than causal language such as “fraction explained.” It also distinguishes two different statements: - -- the exact parity ceiling gives a guaranteed gap from the algebraic balanced maximum; -- the parity-matched null ensemble measures the residual gap from a cardinality-matched random mean. - -### Readability - -The long Section 3 heading was manually broken between “support” and “entanglement” to avoid an unattractive hyphenated section title. No substantive compression or expansion was needed elsewhere. - -## Independent scientific validation - -The final validation script exhaustively enumerated all 65,535 nonempty supports at \(n=4\). - -| Check | Maximum discrepancy or violation | -|---|---:| -| Ensemble-mean reduced matrix | \(2.07\times10^{-14}\) | -| Exact average-purity formula | \(8.88\times10^{-16}\) | -| Residue ceiling, \(t=1\) | 0 | -| Residue ceiling, \(t=2\) | 0 | -| Independent entropy implementations | \(5.55\times10^{-16}\) bits | - -The Table I regressions were reconstructed exactly: - -\[ -\widehat S_n=0.5093n-0.9900909\ldots, -\] - -\[ -\log_2\widehat M_n -=0.703540951\ldots n-0.357734368\ldots. -\] - -The Page gap and support fraction decrease monotonically across all eleven retained rows. The old and revised dense-ansatz formulas agree to \(2.66\times10^{-15}\) bits over the complete \(n=14\) support range. - -The residue-control summary reproduces the displayed residual deficits, deficit reductions, Prime-state parity ceiling, and all six finite-sample rank statements. Full numerical output is in `FINAL_SCIENTIFIC_VALIDATION.txt`. - -## Bibliography audit - -- 33 bibliography entries; -- 33 entries cited; -- no missing keys; -- no unused keys; -- no duplicate keys; -- no Biber warning or error. - -The citations are generous but role-specific. Prior work is cited for terminology, random-state benchmarks, constrained ensembles, subset-state moments, sparse supports, prime-state structure, and QFT entanglement without obscuring which propositions and theorems are new here. - -## LaTeX and PDF validation - -The clean source compiles with - -```text -pdflatex main.tex -biber main -pdflatex main.tex -pdflatex main.tex -``` - -Final status: - -- 24 A4 pages; -- approximately 5,581 body words by `texcount`; -- 189 abstract prose words, excluding its two displayed formulas; -- no unresolved citation or reference; -- no LaTeX/package warning; -- no overfull or underfull box; -- all fonts embedded; -- PDF openable and unencrypted; -- not a scanned PDF; -- all pages rendered and visually inspected; -- no clipping, overlap, black box, or broken glyph. - -## Journal fit - -The paper is best submitted as a regular **Paper** in the journal's quantum-mechanics and quantum-information section, with additional relevance to physical combinatorics, asymptotics, number theory, and random matrices. The manuscript is shorter in words than a typical long JPhysA Paper, but its 24-page review layout contains seven figures, formal results, and four proof/diagnostic appendices. Padding would reduce readability and is not recommended. - -## Author and release confirmations still required - -These are administrative or authorial decisions, not scientific defects: - -1. Confirm the author order and each current affiliation. -2. Confirm the corresponding author, current email addresses, and submission-system ORCID information. -3. Confirm the acknowledgement wording and all funder/grant identifiers. -4. Confirm the conflict-of-interest declaration. -5. Make the GitHub repository public before submission, create a release tag, and preferably archive the release with a persistent DOI. -6. Once the repository is public, change the data-availability sentence from future tense to a stable “openly available” statement and update the software citation with the release identifier. -7. Upload this manuscript as the revised version of arXiv:2501.06292 and ensure the arXiv metadata match the new title and abstract. - -## Final assessment - -After the seven confirmations above, the manuscript is suitable for submission-level packaging. No further scientific expansion is recommended before peer review. diff --git a/docs/REFERENCES.md b/docs/REFERENCES.md new file mode 100644 index 0000000..4b78c32 --- /dev/null +++ b/docs/REFERENCES.md @@ -0,0 +1,23 @@ +# References and research positioning + +Primary records checked on 22 September 2026. This is a targeted literature check, not a completed novelty assessment or a reconstruction of the absent revised manuscript bibliography. + +| Source | Role in this project | +|---|---| +| Ruge Lin, Germán Sierra, José I. Latorre, [Arithmetic sequences as quantum states](https://arxiv.org/abs/2501.06292v1), arXiv:2501.06292v1 (2025) | Public predecessor. Its [Table I](https://arxiv.org/html/2501.06292v1) contains the retained n = 10–30 peak values. The currently listed title is not the later working title used in old repository metadata. | +| Fernando Granha Jeronimo, Nir Magrafta, Pei Wu, [Pseudorandom and Pseudoentangled States from Subset States](https://arxiv.org/abs/2312.15285), arXiv:2312.15285 (2023; revised 2024) | Prior analysis of the same equal-positive-amplitude, fixed-size random subset ensemble. The multiple-copy calculation includes falling-factorial inclusion probabilities; see Equation 3.2 in the [full text](https://arxiv.org/html/2312.15285v2). | +| Tudor Giurgica-Tiron, Adam Bouland, [Pseudorandomness from Subset States](https://arxiv.org/abs/2312.09206), arXiv:2312.09206 (2023) | Independent prior subset-state moment and indistinguishability analysis. Equal-amplitude subset states and their phase-free pseudorandomness are not introduced by this repository. | +| Giuseppe De Tomasi, Ivan M. Khaymovich, [Multifractality meets entanglement: relation for non-ergodic extended states](https://arxiv.org/abs/2001.03173), [Physical Review Letters 124, 200602 (2020)](https://doi.org/10.1103/PhysRevLett.124.200602) | Sparse random states can reach Page-scale entanglement despite occupying a vanishing fraction of the basis. Their Gaussian nonzero amplitudes distinguish that ensemble from the equal-positive-amplitude model here. | +| Don N. Page, [Average Entropy of a Subsystem](https://arxiv.org/abs/gr-qc/9305007), [Physical Review Letters 71, 1291 (1993)](https://doi.org/10.1103/PhysRevLett.71.1291) | Haar-random reference mean and its asymptotic behavior; a benchmark for a different ensemble. | + +## What the comparison establishes + +The broad fact that sparse support can coexist with high entanglement is established prior work. Fixed-cardinality subset moments are also established objects of study. The counting arguments in the research notes should therefore be read as direct derivations and checks for this repository, without a claim that moment counting itself is new. + +The equal-positive-amplitude assumption matters: full support is a product state, and the coherent dense-side contribution cannot be transferred unchanged from random-phase or Gaussian-amplitude ensembles. + +It remains necessary to compare the exact balanced-cut purity formula, its finite-size minimization, and the residue ceilings directly against prior equations before asserting a new publishable theorem. This cleanup makes no claim of quantum speedup, computational pseudorandomness, a unique primality fingerprint, or a settled asymptotic entropy-peak exponent. + +## Citation metadata + +`CITATION.cff` names the existing public preprint with its actual title and year. Its software title describes this repository separately. Cite the commit used for revised code or data. A working title in a README is not evidence of a new arXiv version or a journal publication. diff --git a/docs/REPRODUCIBILITY.md b/docs/REPRODUCIBILITY.md new file mode 100644 index 0000000..84b55b1 --- /dev/null +++ b/docs/REPRODUCIBILITY.md @@ -0,0 +1,72 @@ +# Reproduce the checks and figures + +Run commands from the repository root. Python code and CSV data remain executable and machine-readable; all narrative documentation and reports use Markdown. + +## Environment + +```bash +python3 -m venv .venv +source .venv/bin/activate +python -m pip install -r requirements.txt +``` + +The cleanup was checked with Python 3.12.14, NumPy 2.3.5, SciPy 1.17.0, and Matplotlib 3.10.8. For those numerical package versions use `python -m pip install -r requirements-tested.txt`. That file pins the direct dependencies, not every transitive dependency or BLAS implementation. CI checks the supported Python 3.10 and 3.12 configurations against the dependency ranges in `requirements.txt`. + +Matplotlib uses its own math-text renderer for plot labels, with external TeX disabled. No document compiler is required. + +## Scientific validation + +```bash +python scripts/run_smoke_tests.py +python scripts/final_scientific_validation.py +python scripts/validate_residue_results.py +python scripts/check_repository.py +``` + +The test suite covers exact identities, API input rejection, basis ordering, numerical entropy behavior, validator failure cases, and figure-output isolation. The comprehensive validator independently enumerates all nonempty supports for n = 2 and n = 4, compares against production routines, reads the actual peak table, and checks released residue summaries against the 12,000 observations. The residue command is a focused view of those checks. Default validators print Markdown and do not modify released evidence. + +To save a new report: + +```bash +python scripts/final_scientific_validation.py --output generated/scientific-validation.md +``` + +Choose a new Markdown path; report writing rejects existing files and protected evidence destinations. Acceptance checks remain active under `python -O`. A passing report is limited to the checks it lists: it does not reconstruct the high-n global searches or establish novelty. + +The repository check verifies frozen evidence hashes, local Markdown link paths, and the absence of TeX/PDF artifacts. It does not fetch external links or inspect missing historical records. + +## Three figure workflows + +| Command | Work performed | Output directory | +|---|---|---| +| `python scripts/reproduce_publication_figures.py` | Redraw all seven figures from released CSVs; no simulations | `generated/figures/` | +| `python scripts/reproduce_publication_figures.py --smoke` | Small fresh numerical runs, including Figure 5 baselines and matched controls; Figure 2 refits the retained table | `generated/smoke/` | +| `python scripts/reproduce_publication_figures.py --full` | Original-size figure computations; expensive; Figure 2 still uses the historical table | `generated/full/` | + +The driver rejects destinations that overlap the released `data/` or `outputs/` trees. Missing input CSVs cause failure even if old images are present. Individual scripts also default to generated directories. Explicit custom destinations on individual scripts remain the caller's responsibility. + +All outputs are PNG by default. Pixel identity with historical images is not guaranteed across library/font versions. Fresh simulations may differ in floating-point details even with the same seed. CSV redraw demonstrates that a figure can be reconstructed from its supplied inputs; it does not independently regenerate those inputs. + +## Local peak check + +A modest example is: + +```bash +python scripts/peak_scaling_verification.py --n-values 10 --samples 20 --points 7 +``` + +This samples a neighborhood around a supplied Table I value, then fits a quadratic in log₂ M. It does not search the entire support-size range. The original global searches for the historical peaks are not part of `--full` either. + +Inspect a workload without executing it: + +```bash +python scripts/peak_scaling_verification.py --all-table --dry-run +``` + +The default schedule reaches dimensions that can be expensive with dense exact entropy. A d-by-d real coefficient matrix needs 8N bytes before copies, reduced states, or SVD workspace; a complex state vector needs 16N bytes. At n = 30 these alone are 8 GiB and 16 GiB. Dense SVD time grows roughly as N^(3/2), multiplied by support sizes and sample counts. The September cleanup did not run those high-n searches or the full figure simulations. + +## Evidence protection + +[The manifest](../validation/evidence_sha256.json) records all 50 released CSV/PNG files and the original license. `generated/` is ignored by Git. The manifest's hashes were computed from the pre-cleanup commit and checked against the working tree; they must not be silently regenerated to hide a mismatch. + +See [provenance](../PROVENANCE.md) for original-data limitations and [the sanity check](SANITY_CHECK.md) for corrections made during this cleanup. diff --git a/docs/RESEARCH.md b/docs/RESEARCH.md new file mode 100644 index 0000000..9c4f207 --- /dev/null +++ b/docs/RESEARCH.md @@ -0,0 +1,178 @@ +# Research notes: equal-positive-amplitude subset states + +These notes state the mathematical model, derive the exact results represented in the code, and separate them from approximations and numerical evidence. They are the maintained research text for this repository. Entropies and logarithms use bits unless `ln` is written. + +## 1. Model and endpoints + +Let n be a positive even integer, N = 2ⁿ, and d = 2^(n/2). Choose a support A uniformly among all M-element subsets of the N computational-basis labels, with 1 ≤ M ≤ N. Define + +```text +|A⟩ = (1/√M) ∑ over x in A of |x⟩. +``` + +All nonzero amplitudes are real and positive. Random phases or Gaussian nonzero amplitudes give different ensembles. A fixed balanced cut identifies each label with a pair (a,b) in a d-by-d grid. Write X for its binary incidence matrix and C = X/√M. The right reduced state is ρ = XᵀX/M. For a general complex coefficient matrix with entries C[a,b], the corresponding formula is ρ = CᵀC*, where * denotes entrywise conjugation. Its eigenvalues are the squared singular values of C. + +The von Neumann entropy is S = −∑ λ log₂ λ, with zero terms omitted. Rényi-2 entropy is −log₂ Tr(ρ²); min-entropy is −log₂ λmax. Always 0 ≤ S ≤ log₂ d = n/2. + +A singleton support is a computational-basis product state. Full support is |+⟩ raised to the n-fold tensor product and is also unentangled. A permutation-matrix support of size d is maximally entangled. Thus support size alone does not specify an individual state's entropy. The curves here describe ensembles indexed by M, not a physical time evolution or a nested growth process. + +Uniform support sampling is invariant under bit permutations, so every fixed balanced cut has the same ensemble distribution. This does not imply that all cuts of an individual support have the same entropy. + +## 2. Exact mean reduced state + +For k distinct grid cells, the probability that all are occupied is + +```text +pₖ = (M)ₖ / (N)ₖ, +(z)ₖ = z(z−1)…(z−k+1), +pₖ = 0 when k > M. +``` + +Each diagonal entry of ρ sums d occupied-cell indicators divided by M. Each off-diagonal entry sums d products of two distinct indicators divided by M. Therefore + +```text +E[ρ] = (1/d − β) I + β J, +β = (M−1) / [d(N−1)], +``` + +where J is the all-ones matrix. Its uniform-vector eigenvalue is 1/d + (d−1)β. Each of its other d−1 eigenvalues equals 1/d − β. + +This is the spectrum of the mean matrix. It is not the mean of the ordered sample eigenvalues. For example, M = 1 gives E[ρ] = I/d even though every sample has zero entropy. Concavity gives E[S(ρ)] ≤ S(E[ρ]), not equality. + +Implementation: `fixed_cardinality_mean_spectrum` in [core.py](../subset_states/core.py). + +## 3. Exact average purity + +Expand Tr(ρ²) as the sum of X[a,b] X[a,c] X[a′,c] X[a′,b] over all four indices, divided by M². There are three cases: + +| Index pattern | Number of terms | Distinct occupied cells | +|---|---:|---:| +| a = a′ and b = c | N | 1 | +| Exactly one equality | 2N(d−1) | 2 | +| Neither equality | N(d−1)² | 4 | + +Substituting the inclusion probabilities gives + +```text +P̄ = E[Tr(ρ²)] + = 1/M + + 2(d−1)(M−1) / [M(N−1)] + + (d−1)²(M−1)(M−2)(M−3) / [M(N−1)(N−2)(N−3)]. +``` + +The formula covers n ≥ 2 even and every valid M, including both product-state endpoints. The last contribution counts rectangles in the grid; no independence approximation is used. + +For each sample S ≥ −log₂ Tr(ρ²). Since −log₂ is convex, Jensen's inequality yields the ensemble bound + +```text +E[S] ≥ E[−log₂ Tr(ρ²)] ≥ −log₂ P̄. +``` + +This is a lower bound on mean entropy. A concentration claim or an individual-state guarantee requires an additional argument. + +Implementation: `fixed_cardinality_average_purity` and `average_entropy_lower_bound_from_purity`. + +## 4. Three distinct support scales + +For fixed c > 0 and a fixed exponent 0 < γ < 1, take integer M asymptotic to cN^γ. Expanding the exact purity gives + +```text +P̄ = 2N^(−1/2) + c^(−1)N^(−γ) + c²N^(2γ−2) + + terms smaller than their respective leading contributions. +``` + +For every 1/2 < γ < 3/4, the last two displayed contributions are smaller than N^(−1/2), so + +```text +P̄ = [2 + o(1)] N^(−1/2), +E[S] ≥ n/2 − 1 − o(1). +``` + +The deficit stays bounded by approximately one bit. This is not a statement that the absolute deficit vanishes, nor that the ensemble attains the Page mean. + +The smallest correction to this purity background occurs when the sparse and rectangle terms balance, giving γ = 2/3 and c = 2^(−1/3). The O(1) correction to the resulting minimizer can be checked directly. Set + +```text +a = 2/(d+1), +b = (d−1)/[(d+1)(N−2)(N−3)]. + +P̄(M) = bM² − 6bM + a + 11b + (1−a−6b)/M. +``` + +For N ≥ 16, the last numerator is positive. The second derivative is positive, and the derivative vanishes exactly when + +```text +M²(M−3) = N(N−5)/2. +``` + +The continuous minimizer is 2^(−1/3)N^(2/3) + 1 + O(N^(−1/3)); comparing the two neighboring integers gives an integer minimizer of the form 2^(−1/3)N^(2/3) + O(1). At N = 4, direct evaluation gives the minimum at M = 3. + +At γ = 3/4 instead, + +```text +P̄ = (2+c²)N^(−1/2) + o(N^(−1/2)). +``` + +This is the crossover where the rectangle term becomes comparable with the balanced-cut background. It is not a theorem about the von Neumann entropy maximum. The average-purity minimizer, the maximizer of average Rényi-2 entropy, and the maximizer of average von Neumann entropy are different optimization problems. + +## 5. Exact diagonal and residue bounds + +The occupancy W of any column is hypergeometric with population size N, d marked cells, and M draws. The diagonal probability of that column is W/M. Hence the mean diagonal entropy is exactly + +```text +E[H(diag ρ)] = −d E[(W/M) log₂(W/M)]. +``` + +Deleting off-diagonal coherences cannot reduce entropy, so E[S] ≤ E[H(diag ρ)]. The function named `hypergeometric_occupancy_approximation` computes this exact diagonal expectation; treating it as an approximation to von Neumann entropy is appropriate only when coherences are sufficiently small. + +For the natural cut, the right subsystem consists of the low n/2 bits. Let pᵣ be the fraction of occupied labels congruent to r modulo 2ᵗ, with 0 ≤ t ≤ n/2. Dephase the t low bits. The resulting blocks have total weights pᵣ and dimension at most d/2ᵗ. Their entropy is at most H(p) + log₂(d/2ᵗ), while dephasing cannot decrease entropy. Therefore every such support satisfies + +```text +S ≤ n/2 − t + H(p). +``` + +This is a cut-specific computational-basis statement. Applying a global QFT changes the state; the input residue populations do not automatically bound its output entanglement in the same way. + +## 6. Approximations and reference ensembles + +The dense-bulk ansatz uses the uniform-mode eigenvalue λ of E[ρ] as an estimate for a separated sample eigenvalue, then assigns the remaining weight a Page-like bulk: + +```text +T = h₂(λ) + (1−λ)[log₂ d − 1/(2 ln 2)], +h₂(λ) = −λ log₂ λ − (1−λ) log₂(1−λ). +``` + +The mean-state formula is exact. The identification of its eigenvalue with a typical separated eigenvalue, the bulk shape, and this entropy expression are approximations. Algebraically equivalent formulas and one spectral plot do not establish their accuracy uniformly in M or n. + +The Page mean for a complex Haar-random pure state across a d-by-d cut is + +```text +S_Page = [H_(d²) − H_d − (d−1)/(2d)] / ln 2, +``` + +where H_j is the j-th harmonic number. It is a reference average for a different ensemble, not an entropy ceiling. The ceiling is log₂ d. Related work and ensemble distinctions are in [references](REFERENCES.md). + +## 7. Numerical evidence + +The retained peak table fits log₂ M̂ = 0.703541n − 0.357734 over eleven even sizes n = 10–30. This is a descriptive regression of historical point estimates. The original global-search records are incomplete, especially for n = 22–30. Local checks near the supplied centers cannot recover global optimality or supply the original search uncertainty. See [provenance](../PROVENANCE.md). + +| Figure | What is shown | Scope | +|---|---|---| +| [1](../outputs/fig1/fig1_concentration.png) | Support-size curves and cut sampling | Finite ensemble samples | +| [2](../outputs/fig2/fig2_peak_scaling.png) | Historical peak table and regressions | No asymptotic exponent established | +| [3](../outputs/fig3/fig3_spectral_bulk.png) | Spectrum and a bulk comparison | One sampled n = 24 state | +| [4](../outputs/fig4/fig4_approximation.png) | Sparse and dense approximations | Numerical comparison, not a uniform error theorem | +| [5](../outputs/fig5/fig5_qft_residue_controls.png) | Almost-prime supports and matched ensembles | Paired computational/Fourier comparisons at n = 14 | +| [6](../outputs/fig6/fig6_renyi.png) | Several Rényi entropy curves | Different entropy orders need not peak together | +| [7](../outputs/fig7/fig7_partitions.png) | Entropy over sampled balanced cuts | Two selected n = 20 states | + +The QFT uses the positive-exponent convention, implemented by NumPy's orthonormal inverse FFT. Changing its sign conjugates the output for these real inputs and leaves bipartite entropies unchanged. This convention check says nothing about implementing a physical QFT at large n. + +## 8. Open scientific questions + +1. Determine the asymptotic maximizer of the mean von Neumann entropy, with error control; the purity calculation alone does not do this. +2. Establish a quantitative dense-bulk approximation for this fixed-cardinality, positive-amplitude ensemble, with a stated regime and finite-size errors. +3. Compare the exact formulas and their consequences directly with existing fixed-size subset-state moment calculations before making a novelty claim. +4. Recover or replace the missing global-search evidence if the high-n numerical peak law is retained as a central contribution. + +The present cleanup strengthens the repository's reliability and boundaries. It does not settle these research questions. diff --git a/docs/SANITY_CHECK.md b/docs/SANITY_CHECK.md new file mode 100644 index 0000000..c03c0c1 --- /dev/null +++ b/docs/SANITY_CHECK.md @@ -0,0 +1,40 @@ +# Sanity check and cleanup — 22 September 2026 + +**Assessment: the core exact results survive this audit; the repository does not establish a complete publication-ready contribution.** The remaining high-n provenance and novelty questions are substantive. They are now visible in the landing page and research notes. + +The baseline was commit [4cb99f109194124f500d75dd065ff43581a2682d](https://github.com/GoGoKo699/Subset-states/tree/4cb99f109194124f500d75dd065ff43581a2682d). Independent mathematical, numerical-code, validator, and primary-literature reviews were used. Prior automated PASS reports were treated as historical claims to inspect. + +## Findings and actions + +| Finding | Action | +|---|---| +| Exact mean reduced state, average purity, entropy lower bound, hypergeometric diagonal entropy, and residue ceiling check out | Added derivations and explicit assumptions in [research notes](RESEARCH.md), including the exact cubic equation for the purity minimizer | +| Old validation hardcoded Table I and mainly checked copies of formulas | Validator now reads actual CSVs, compares derived tables, and checks production routines against independent calculations | +| Old acceptance assertions disappear under optimized Python | Replaced with explicit failures; mutation tests exercise both `-O` and `-OO` | +| QFT routine accepted duplicate and negative support labels; for example, duplicate labels could yield a state with squared norm 1/2 | Validate labels before indexing or integer conversion; added rejection and normalization regressions | +| State-vector and support constructors used inconsistent subsystem basis ordering | Aligned ordering and documented the complex partial-trace convention; valid historical entropy spectra are invariant under the corrected row/column permutations | +| Invalid Rényi orders/spectra and extreme orders could silently misbehave | Added input checks and stable entropy evaluation, with targeted regressions | +| Default figure “reproduction” redrew only two figures and checked that old PDFs existed; smoke mode overwrote some released outputs | Redraw all seven from CSV; put all default fresh outputs under `generated/`; test destination isolation and missing-input failures | +| Repository cited a 2026 renamed arXiv paper that is not the current public record | Corrected the citation to *Arithmetic sequences as quantum states* (2025); documented the later title as a working title | +| Old reports claimed submission readiness and audited absent manuscript/build files | Removed those reports from the active tree; linked the baseline commit for history; replaced them with scoped Markdown documentation | +| No TeX sources were present, but documentation contained TeX notation and the repository retained 14 PDF figures | Converted prose mathematics to plain text/Unicode, removed PDF duplicates, and made plot defaults PNG without an external TeX dependency | + +## What was verified + +The initial ten tests passed before editing. All 39 tests in the updated integrated suite passed. Exact/data checks and figure workflows are recorded in [the scientific report](../validation/SCIENTIFIC_SANITY_CHECKS.md) and [reproducibility instructions](REPRODUCIBILITY.md). + +The mathematical audit rederived the identities and separately checked integer/rational enumeration at n = 4. The maintained validator exhaustively checks 65,550 supports in total across n = 2 and n = 4, including comparisons with the production coefficient matrices, entropies, mean matrices, purity formula, diagonal expectation, residue ceilings, and entropy lower bound. QFT amplitudes receive an explicit small-system DFT check. + +The data check reconstructs all 12,000 released residue observations into their summaries and checks residue bounds. It replays three seeded supports per group, 36 in total. That is a limited seed replay, not a regeneration of every raw observation. + +All seven CSV-based figure redraws and all seven reduced-run outputs completed successfully. The complete original-size simulations and missing global peak searches were not run. SHA-256 comparison against the baseline confirms all 50 retained CSV/PNG evidence files and the original license are unchanged. + +## What remains unresolved + +- Historical peak values are publicly traceable to the 2025 preprint, but the complete global-search records and uncertainty estimates are absent. Later local checks cannot supply them. +- The exact purity minimizer does not locate the mean von Neumann entropy maximum. No asymptotic entropy-peak exponent is proved. +- The dense-bulk approximation lacks a uniform error theorem. Checking its implementation or algebra does not validate its accuracy throughout the parameter range. +- A single spectrum and two selected states do not prove concentration or universality. +- Existing sparse-state and fixed-size subset-state literature overlaps the broad framing. The targeted [literature check](REFERENCES.md) does not establish novelty of the revised contribution. + +The cleanup makes the project inspectable and reproducible within the stated limits. It does not replace peer review or recover missing experiments. diff --git a/outputs/README.md b/outputs/README.md index 095ea57..3e7f9e5 100644 --- a/outputs/README.md +++ b/outputs/README.md @@ -1,5 +1,7 @@ -# Released outputs +# Released figures and numerical records -The subdirectories `fig1` through `fig7` contain the manuscript-ready vector PDF -and a PNG preview for each final figure. Scripts write regenerated outputs to the -same locations unless an alternative `--outdir` is supplied. +Directories `fig1` through `fig7` contain inherited PNG figures and their available CSV inputs. PDF duplicates were removed in the Markdown cleanup; the original versions remain in Git history. Retained PNG and CSV bytes are unchanged. + +`peak_verification/` contains local checks for n = 10 through 20. Its `samples.csv` files contain statistics at each sampled support size, not individual states or their labels. These are not the missing original global-search records. + +Use `python scripts/reproduce_publication_figures.py` from the repository root to redraw all seven figures into `generated/figures/`. Rendering can vary with fonts and library versions, so pixel identity with the inherited PNGs is not promised. See [reproducibility](../docs/REPRODUCIBILITY.md). diff --git a/outputs/fig1/fig1_concentration.pdf b/outputs/fig1/fig1_concentration.pdf deleted file mode 100644 index 213d889d3d2f208d4cc9ce25348c956a658a9965..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26451 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 Nl#HES`l1Zk{{Wn76&wHn diff --git a/outputs/fig2/fig2_peak_scaling.pdf b/outputs/fig2/fig2_peak_scaling.pdf deleted file mode 100644 index 614cfe3ed7daa16407b250f14657025e2ce9fde9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18141 zcmcJ%1yo!+*YHoFEiT2K!Ci*IDemqL#kDwtTZ=ozT?)lri&H2Rr?@-Cy%aC-4eh=6 z>Aij4@4o-_U*E7;b0#Or**nQec6NRVrJ|@fBan#=fwFV~P|}0|1h4??jI0ozKL;?Y zy4#xqm_-c1hSqlG0A@u)b5kb(DDR;I>a z0O!x2Vs2mw6|f=L6u|Z~K+zBkHg&WGus{4nU{c#S{$Cfjm}J z93qOT8yLVWWdjjG_>XUqKfa{^dcTMR{9Sf+cn02R>*V4Fxo*tS^uWr$^G$XJ z(Qx?b`A*H=5lKb4enwWxvc7A<$MH#HiB0S*g7ra0egUKuCofx`;DVcBmCAi1dB2|K z^B9=fFEFpluWs$8y|?9kVO~oRave3HStFdiLah&p1^4kxzdF=LgP}^8uy=fQ_QhT9 z?x~-!MH(qbGVQxK3u9T@V8-^R!W=Zshe-JM+iffJDHyPH!s^QQ{0(bihSl6Lj%`gx z!%WTNTPD?w-xX~fui89~qtt61dp7Nyu5xbHtDCor(TJ34(`RlNPoJ{(rH3%&F%(In zY4z%z+bj6Rk?XwAw!G_`jpsXIU20KqIyVx@|DZF4Y!VCdH0S#w!z6eXxNu=HELJ+8 zY(zN235nb|qns>de^49JPV#a&b@cSpRJWr7G&Q4CfThEW9jrXp+H0^ilO1o>NcsZ) z+iEUt?=&wb{biGq^L|R$EKa+-*>qBiFRA3yw}>a9x+j)5Yj4|*SJnz8TW{_ni|n$c z!L!i~UQ1|BqrsS@bDKlKnfTp=6x?rkWe*182gjc#tDYKv7E4Fub|Sv?J)p!G)><@N zxz}8NOyI->tc{iH^SVy&nVxoA8D|TQ?=_6yIKL$EQk6qRWxTzW^~}_n^^W1RPc(V! zDaE$NFStd4rr4L)kWSe(dt7q^ZI4Dqp46b~M*XmnCBK)s_>5K(s<#l zueQW!tz(elqA5>HDPZ*iX=h_;4@B)?G7|zulXn&Y##dY<9~5*qWD4HN$I}!xth_AD z4kE>rz$@Axxo-1#-=yQMqgOGw%Q$wryS}@(>u`4NCc3!4DIV3Z4L6IJ156Hnd75>%W2ymmeld8}#K}a&VfZEU44VnZI*CA4p>Bkv64nKh89zUb#XG zC*AA;BWozH&vUweicRn=6=vg%1bPag5fdFh%XEgDY~J3X>x;A~kAs|{YRL{8! zQxjs%gv>JTH`yTTfMDKJpQ7LnoE{Yo6_)VGLAvEzHxywMNsHnBL$8Ss&C>#;P4zkG z2vOom)%@9Yq*=J2U~x59-te4NHW@?KAhwFQ>?o<31$4P(<>Nl&3i0va`RmmZyP#YvNf zl={_#k;gk_xQeMMJQ@Dl3@gTuvO#dl7HJ4*AvW1Fqz-l_I4_0G!7AM}K8olo&M(D9H6(*a-)2lKR$sBynQ-QY{y}-v~@(RvkE206o z4np%Kgri=svoXfBu&s?^OM3}pk>y=+1N1Wy3hB5kll(?R%mR%@@WSZ5l3QrQs5o&g zD*4lJ_ViTr=4JIxUBc#S9z(yS=6!c_%S(~Xq%9bE%+XU|$unuFh4Z!Yg>p=JA@+1w zckQb3HWX(W*HnAeZpeJG9yd6@5wFp?ERWGEV zu+JEGL8t1-vbL|zgHCYV2R`)q{|ZD zB6iGk0lY?V_|R{~6&W3*nGqyrGKix{@#q^{WPtrnL2<-uzO9BHF68bqEP|!TRsvvf ziDm7M-SG~e{tm~tQYUBE<`+I3agWd=NRC^Vk)%^y=o^+LHqM0C%a`2+?`O(&`7d

1N^Vy)3 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 diff --git a/outputs/fig3/fig3_spectral_bulk.pdf b/outputs/fig3/fig3_spectral_bulk.pdf deleted file mode 100644 index 60ea87db4930ea607153d7c783f20e938761e681..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27821 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

3X6rvA3n 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 diff --git a/outputs/fig4/fig4_approximation.pdf b/outputs/fig4/fig4_approximation.pdf deleted file mode 100644 index 0539f2721dafef5e7744ec8dfe3bd01a6ec0a46f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29472 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 diff --git a/outputs/fig5/fig5_qft_residue_controls.pdf b/outputs/fig5/fig5_qft_residue_controls.pdf deleted file mode 100644 index 619b0910714c88ca2718b7a03162ed6eb2c2236b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30486 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

1gjd2ULlFWp}Fn~jx=^l;3F=>sqd0T*Biki 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 K6r%EC@c#!H*KMBw diff --git a/outputs/peak_verification/peak_verification_n10.pdf b/outputs/peak_verification/peak_verification_n10.pdf deleted file mode 100644 index cb7cfdf63f8ebfae8d7731dadd831eba618362ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19095 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 diff --git a/outputs/peak_verification/peak_verification_n12.pdf b/outputs/peak_verification/peak_verification_n12.pdf deleted file mode 100644 index 6d5834cfd17e1a395c3f80c9386cb861cc0d7a1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18964 zcmd74byOV7*6@u44ekU6CIm_F8DNkA3GS{zg1fs0LLj)iySux)2De}d9wfNiJLH`6 z+?;#v``zcCcdc(&v!=VcWba*7-M!hrDk@n)VFnN*D=Jm-BCx0t6$E4kTIrgia&rTj z6kV(hfJ_29_B!TPMnEQ69U}ufAQ+lK9>~j!YGA4Vn33bR0>W07_CS_j8JJXMbWIKP z?1AimoC-PHizwLZ*c$*@|45M4v9~v{wFI&~o}w}-80+YpSQ-H#e_pk<(o-<72dYDx z6%>YwV&H5KWD>K0iopNpufU(bVnEH`!~y+Nfk(L?rMESJO81BOO!5YHRt~m$P<g|tk71N1fcpsE3pG|{vjowrKJ`0 z4D?vycbhz3{>zAx29`$l#z4@Y4GWu?L)8W{37bQ0A!wjyrEl;ky`8;9l#|cynd!=XBdZK71JZrVYc-%KacmT0LEhhqRtJNFvLp@uv43qo2bLZRh%e@QpLl(?t4l-{*$rMsDxx^Sl35lkq z;DLGs@To)5*?dpLf%(@ljutg6$cOG|JQNN>bUcf!qqKD1x+Wyf- z1+5Le30m)0{kTbzfuBbR0x5L!F?g%feOrBf>aX;AQP*Nm)W=KVloz+{tReL{i__1d zLlNbKL5xk)4<*K0-dMeRx~HH8>lip<1W6Gu{z4yZJq>(g!5h?dZd={wn8|I7NQ&?` zs_+pU1h^l>f)GoLRp7@bYjAT|8M_01t(Ztp`whp`~>uF*SbJPk2}tB$rSV^8@mckRZ+b4+jzQx!^@TlwVL$w%CmXP zXjPvku5h?lpVy<##a)G^-;%5(RF7w3AMEISX2t>?NM!&S>2&2bGFk9eBH46r zl_Qjz%aD}{Y_h(=EYsmN>_y=85y{UN+Ti@8lUpS6dJ`ueDzl@_^jaV}V_4wjLO$!N zCXb+T3}|92D9Q{EWubF6#L`}3*DP3vvX#Njh#dcGQ4Y0`jSLxKc`?H6R^#06s%YHQ z(r^~-LouUm7P5iiw&7KE{(M2fL7K0f2jy4B7jmz#7~Z%$v)me7lI0^0+GvA2$}8wH z3A_{;MUP@R1Vx2U2YkTpXS#Fp&D+9jR23-~S=e&Q)&5}WCP5x!w=s42iobgAfs|aJmb5wb4Un)Tc_Ty-~Zrf6XCr zsm`is7{)}#K7DQk6AwxoTEQnVQQywf zoA)xXgS<-Aj0h!+1EeYY)N)IS^osU_RNKMiGDSK`l+-9**n*=*8(_?mWJNs^t2^_$ zc>ZWAV#PtkIHI`I2w}!25d2T%n<7Bki(cXW8Ro84r(-vE&+z+40wq zkF3ISg%Lqi>wL$rp7yMfNj&Ydo@*eQ5Ll3+8x@Mu84w&7w3B{ST{*CwiC!R|rWCqh zi$XPgkAoB9?ypRqVQhjj9VslC7@l!rtDBqUGYN?j9_&*bv)V}B%O6q@EcZVSW#tCT zwaB|1b_u5f2_YNcttN1e#<$KKYAckPxrDbV-Ss@CL;jPvUt~MO>5v)ajm@Kr9jk47 zVWLQ5Uh^E=))Tmtb|+(A+|c>i*_*16U8s1}rzQFD-@vH~M;Y~2H2Hm>k2Acy^)pE5 zNua2ooDhQvu3(;X!8|&>n>NQqep0I3UiH>3;tA=w@-FH35D|9X_=@lmX&KtP9y~Di zNy0RH{fd`Nuxf5oBAJGGKPS>qayN%Cuh6T6;)7!4e#pS_N4-*oC)NqJETu&dYvtk~ zYYIZYB(yu}@mH{@chlHlijTMnt}n9D$uhkBN~ytI&+?>8jp5*;(<5R4PPiCAdJ-=8 zXO=Kjm^;|!vgJ)&n~|9V#1N;fv6Oa$TpvIjQMlJFbG1#2G|ZyZIp>**It^Zs5_d@! zO}vE2kFUnnYkagOM%%Cz))?^;uX2}{KNsQ%uolpqrJYM@2Q}{;>=$(SPq2zAyIsSy z2)uDnVHpmjB9qheUX?TzTbfXMvc;LQ(X4wcI#rdm-uOyMdjy49iSkqQi1zR~PYJAl zypM1C?WV8VRA7%wtK&%JmfJ3|tjK*U zo=`$Bw0&cyp8s4z)WRKu<4oBq!`E6iQj)f`sF%PbI`<>%XUj#0e$I)v>lt^B1EVL? z>e=JTpBS&_*p5j}%41yxFD7Q)f>^1kRY^@|9R@fjo(!j>)TflFXFtDsWyQ^JaIV5G z>iwYY&g%zwNO>Oe4EEYop)zGdJv-ybY!~k6T4#jq){PJVdx?B|PDcJw&W2_Rf7z_GFH#M7X2E;y>;JeH1- zgzR{h1jBIJG@8MehO%6+IgJA29;i}+<}|c0S*cuRK!o>{| zv-;Oa#S|#8P&N$`UsV~C=%jXSqzkuvmZi#+rp{R&yIS4VH*Vptj`akD*iw2^b8^va zt+86*Dfr385N^Ov8KNR}ykL40SrSgHpcIlRy1I_% z^h>Uw_jS9-ITtJq@0;4n^Z@0$UaWxm%s36BmjDMKX`weme!*TAmsbL_`X-F}23{Qo z-ob8j9N(L_f>l}-g^4{xN>QVYVn0)gszRhwP$)7$I%%0d8I?+FP=%7dD3N6uqA>W( zw^nNN1RzvcS|vCpn6Tjo_M!@_%|>yJ!5@5ZfKOqcxl%S#>D7-boUP`Yy(KV=5sh{z z?Hvf13fKV*wi*^=+^P}7h_+~Cjf`_K^UMM_!(;lM)0F6m3R|h6Gzw4p($c^y#qI6B zjiq_+$5k%M;v+eWR=|bW0?2auR@n_S{a#lwc;r{Wt>WkD{JDTBpK=Cvcz0SItVSH{ ztt5?@8RYA;4o4G^IVg6H7oCUZYW22ew{6Ytiaj5G=Ak1No{s1+MDB@hoVUT2OFu9LG#w9b6t zmy{lJ0|>bJbdEUmUWXdBd{=!>;E`?l?fw2!$9;^x-5;CELLl)@(e6$BVcP2uT4^RO zt=Tq)cZcLVbBmkou=h^|zauQF0=+LZ5sgeV`t;l0QxEAN(YTmvPV z^v2&+)?M!%!@Nb9fycZcv|_^C-iY4e2W?PfjJhkn-CL+PIDJbPdP+ae(L!|!8hihvr=jUOc`WD%>m29Wtj?bI)kU6Wf9M;C{qpvRRr}dp z4|>u?I|m^8t*<54=p1(lETfsYZEfAfRSRDzS5L%~hPI3I<&T~$&wVHBJzAXwHh`I3n9GDcMPlhR)-vtcbovRRz<@`Wk3$ElnU-1upccB#80dhO0{Q z!^IUzZhEK2n0c+|eQS!9OrqR|q3y0h;l5RE*;k{c!u?lE&HlHojAE`V5(qzrdODI3 z9-JJ+%?A(|LQYjD^u;s zg>39(2Gf_Iw;#Q_1-NNtZs*qWy53-Dk+*WXe|u;nZGF86@a?L*y_2{hyM*hxeR&Ug zhvt0|QZw1tGcnm$RHBdQpYiG#oWPC5CF9ka62-JD!$metC+2cpF+l&YK(tzDduHb8Sq4j!UpNgRz3yjiC zDsaj6&Nj2*=R6N<#gmX`Hz3kOPaApvfFI-`)miRA@v9Vp3+J7+F55)1V3g1-;PAVL zDfevU5trVU9m24(qGtz)Nn=`#z>@WYhlV+-`l0A^1LRrS89>S80*roSV5_52f*;;= z-}k}mXAh;R=q=L{a%F_nIK!v)g~VbmnEUE)M!zmH^ybLvFk$ZVimf#JW9~;N(lyVe zkfp@vg@!S*99Ju^PX`Ws6|z>*vLlRsx!~ZsmD>g~X0L8<0*~&GpUq;qj!&7Ie31l& zm9QCMyt^=It|e`-In30+4V(_NwzNxNK^62pX5V3#u zlbiSYP3_csvIq1ig?+fzx)*R_Bo_< za0n?7mONijS@o?C0;~{geu%0&>zNSyxM}sYT1`L(wUnrZ-GpEmC(YTZj%3ms`6ypI zTh~xAi!cyFh`>QzI$JGg-qnkfl!OMS&DPC}kzs%~jCP(dth$(v97ymJ?8lx-V|%fy z&Oj9SsKkIYVfXZG-J{~_D3)d5J>^lyXZ(cJ-1YV%7ElS9{LMKT4NV^PR|kSYs*x_u;|E2P zvCU+#+Ee=*kcp2Q!S#~2WdUhpa}y1qfnjPK&nRaVJF^nZh0A9!Q6ZQ91S`D|bGeXi znXxVSR)UA<#rgeiLiym@+L=)4x6UaVDih6lB}*%g+HYj2J!r1#K8A*nCA{ab5v|zK zb7kwmi^pg#clMxCP5O`m>raJN5F8A%n8iO~cDD};mGoMo-IH`DhbAlZ)0t~Hz!cO5Dz-YdlG8r-}cdl)3}1IBTld1NC$z?>!DKVvWQ&yQ~a*ZR8UG`Hr53J(I)xw5?h zGiq~wTHzfP&&bs{+uc`H{Z)WLt^&wB9}#3>y<`;)vZnfnUN8ldHjYkgKO{M(Emeju zZ@(!dDk^Mk>!aNliR}dIU@d1}({VhFyE5Rwa5?2cEvwYz_BNE}BX6eTXhs%M<+Uq! zPi!gVnzF1ANY1^A$yOIvUjFQ@uTaN|tPXwGz&Nvhr{UFgTI1Vm)j2xvSdS>vrQVEZ z+2vU5({c*%#X#t0GlUzU=@47O{Qy%`K&|atPjGG7sXT`kV=WI*1nil<+)>y=cZ9#^ z2Wj=h)Q7T$wwu%nh{;LQ<&-`B^|`q8+ax> zx1UT2HFPkm0QEr>3&kS9(hhu!(n!u{F*Dwr)nw_e7+(Ys5yjqA6V#A}9=aYoBvCYc z`W!Aj!}YP2_sR1eDy5hG#FCEli1lvLOCO!a!Lvz9V#HD8+M19NHkb`~ou$%_h=^kY z@#OqxSV!>N5VV&+qcK~}kG+EjP6p!|5Z}L~C9P6ZR1np}AM&5#e3pBZ*%>^pAbk^f z9@V;VY^;tpM$16o(d7TaHfx}NOdm{PiWu@@4beLnMd)QA7C&f`$`FL|!a_yDD_|2H zxd*Wdh*H&~&zfH?iT*?-xt+mAr&e8{&UX)Vg?)AIe_IgFdAAzwH%E^uSw+k{W4_vI zdI_f)hCu{Lv3&T9O3x~m#|-AW zuARw$PF)9o$OXRczBvka3{2UeIm|H4Hx!GY56BU$#A8WG+MqunP3t*ccO%?LiDPV` zWePA$6ZuBd6(!iYrSZLMRtHa=4_Di#=zUpeNnrsRo0JehhLMOy5WN#wSSsHh7=rNR zWyh;}Mjd8Tdrq8al=cuCYQUg6;r>;Y>Q@0{43}f__Tx5?K9}zXwp!xmgyEq^Np#sa zDR=gRX-V1?ERwnmsS1>)XC+is_H0T+ItaH(rl}AS&B4McrA^^h<$c|zdFgwL8X33H z6uC5Z8Xqj3i212>48ITnaVzCYlxNJnj@ohCb}J=4TGzvvO?j|;zD5p9GUDAb_tU2= zPmMAs`_ZT);c%OAmdeLA#mx~)*(c(R*!aBFXjTf6Ni}x6>0Mxd z?-mj(Z9qHcYq?bKFn&I;FZ0uaX17l;)S>#2W|K^ibkknLM}TT`{vC<8ZJyWAYZ%2)J8&nR6oV~R}f zho;}S8GRr4N!Pa_ca>L~wDhB7R^5}cnquxQDQ`}mpyB*tbvYV=wjT072}J`5ZW_MOt{af00ccO>f-OpQ3)gr z6pPP@I{=P578KlzYTA6Snb+L=at|4F=;;?xL6D~aP901m6VP|ecQnCuOI)7AgN1&} z9yUtD!9?#rbfuCDG#Tt&Vw*Yw+U2^9qx`Xqv-Usu$%!216xS2m+^mKxrIiJ|i2g!8 zsV*7d?sF(g)y|q(RU?9&xBb$uuz2Nu&@rpPMCswRSQ63-z&`G-qUgaVBCWY9l6-_d zq|kkDBH=YsOd_n-rG#NrQDag6{I>*W%?WAMYq zkqe4#gOz_~A#_(t=~biR&cVh@U1g&;W&md1!n+(iA(Zq{8+^`qI3@vnS{a}wg~J#x z1Wt*5$0ha^lh@d5fR)S7)|H`UT7wxk@rRupMw?mDi|(s}i>NP%rn{mOr=HFuEn78_ z+!jDBscc-J2@eMO4|le(&w^|b%Q&hsI5m{JPv4#RvASpAH}s2t{0fPDC*?RBo*Z z7$75h8{2JxQzyPiQDKy-emeDi4TpWfM&SaXLQMCf*L3^?Y*XDUlBPvnJvPfzT20GE zpv?!Y*SqCif&06QnJpNzHA4OlmgYh2%BV#SMDWYl0Sq`vRHY%kxoilT1sJp8VQdI< z_3iY}^eQrzX`gYcS_ydqW+K!yvCODS&);>M2Jk+eDSk#{x??@92dOY6El#b;H$fc3$@iUJPg+!!&!cB>fHN`h^h&L5tXF;h$qEXfD@gbAM zMxYSV1=|b|G6$?jt&YVQ6O>wK&#sy+cZp{brwH4-#ylbEjdFI!TKmM|k*pqE)@4(H zt(#1u_kx-FD}%0~ZZ%03B^RYIhMv!dWdCqunxb;LqP*{efUs z&i`J!rYw(D7Z7Xd3ZI=?K#*5WhCn`=k!(WQ;k6KenUp{t9eJ(ep%qD5vqsd~^4f}fQ!h(dt?BPYZ$`!-#)b z@Q=9UuV5pSf`hL8A7M%{!N-)xYhWM~zmA>39~ndhR8$3(=>!c-b(9?xbS&){WOU6< zY#a4J^bg4XuEW5l?voBNM25=K_4m2Mul-yaF=G*y9Hw613Nui6Ki`bTOjDqD5eS!I)olWgO5!qT8W4W zO6gbwL4QOK{}n<7{T@U8kIFqJGXF2N60(E_6(1#L`b%O4Q6ST!bWo2~$I|{$Ry$~z z^Os5GAH$l8R!Wv8zao*p2I}vT%wL-P)9%0N`b&3d9SdlP_5W(>U*S$8XxJ3;hpG7g z2(&VQn4$GEu&{xk7K1QDo{CM!FE7YHcj)-60H?$+9bevU8^q~P+4hYL{ zVdG!@^r)vgkewZBoX4x|tdG)gus}~CENsw25Y(-IJbsJ?|I4laePsUO$V1fuv4H>O z*R!*;vi$eCKJDtJ5k1}bP_?|(GMtj2fFB(dTKf->DvIIMeV36>_mHMf}s#@)w1rN75xDQ{LgiMhMP*Vq<%+iukXwKdQ)RUD&sNV423j3NogE z7-Y@kZ(R}Ic2c>ncp^He)|ryP;!NhJu@=eKel1EO9LXzH>+Lj z+JUC75he&ntRK58yG0?vBbl*LhN`c5SDB9XVKQZJeCkj3Z|OY)Qmwk$j(%MF4-R|Y z-G6oM%OK-PIs5kI;it#LF;B@9NU|(t|1y8g{GyaRz;P?y@{9eBjK=Gxn-|Pg-Xxts zR9zs!szXA32cJ`c9omi)G2UH)Z363938dq(ehJS6i%b1F^7G3T%K-@^UsY zHahzFmi$}Yl&-5fVrR5*wL+LU-6^$JG(w5bBk|(mA5+ zz`n+h>n{|t^xO1s7JNA#kC@Zci06AUo=u6~ z=unO1`?1fN)T-?We0cpGCpjk~#`>9=fp*sOBv)8opo^v~gqqMi2q`hSz5|Ry_N_5^17S*R| zlZ7YLrXTJbBS9I_icxKcuT`DS8xu~26sDZV)jM|MGA zFpl@~d$*KmcRQPuhuVPUI@GnB(|e^!v)N{ca4n+`{pu^@5pU!|l~H%`WB}A8JL~J+ zG7s}ZGB>AWQE$f8XL;RKw+g$0eC1Xy0~GNYc5?5(cbz)vPI6Ht+*>jho=B&B|1foL zyqYeuKZ$sTa*YzWr|;FNR%g#KPtrcXNO4E72uG(F{f<&F|GYNV?mz?SwEtQ7esA}f zgi#$+Q_8_cUqagE2hmV%@(}@R(ogu2@f4GDyFdlwaPrN49Xg zXm@(CXxGO4qV0Hy=@ylR_UabR({GSCR!ZeftY+7c3qslY#-7bNmRmdztSc7tuLtwnwfi-;SNYd+C0k}DuoFlwtTuaI4EIz0`NqMA z9C*Z}ffSfEZw{OX)z;MLqO@R|#B`};>H*V4ZVT~TP95=$<)4~*ry5XyQizwYUAA}T z+A;Kny-sdOnbMdk7~dPLOFU*MI++7}ZxBpcaq{ElOGxLTe^X2!TpB#pZzeb>m(81c zRW7TEr9{TFQbkHj5hubB_WtKQLQ^InO2-xqikKuvTx_?!&Y`5vSNnoazd+NZS(ppg zP>5@xhtj*(&cLL+=yu-WH!5`-*x#o(}aS>Wc zbdPS+mawiVy_m_gKyo)niXtv0d?dQS|s~M4sSGMF` z%8`}G_!gONdvzuMLsbDP`*B>t%3uBMR-WiH^iLK1Fn+@ zl@S#i37`_b##JGvr%`S2l+=(@7d<{VZIvIsi^nhd zXbeC#o-xJq9SR=Sg$pwcXMo&@=Jo3uau`c6}ASeT(8ejlEB|(q`DF8( zV+Wfq_QWO8iv=@RnZ2dK$V<-qB_6BcczgFviMEG3i8>yw^yIP)8DF2npocr2hmKvI z51KO_BT1OlIap^+$QQ(dEvO22*ntB4C;;%gSpMj&Pm+e|rsuUziKP5SU^i7Xd^qKD z@X<@E@y>wpqtJRAG$Pe)C+X<;KsoVJuy{hKgKVCu4_!q&&bwPi?&bUWcfAW$F(be|X4l!j~Sa1gox!kp*Q{7 zQBmb!vBQa8>nY&j3`MJHZ-DSJhEC-&W&?$1i3>MeY2^=x(<d{E5xM9EFsj6hIW}YuuW8QDxW&wp@TMdND>& zQAHWLdQ`Cs_fbYgc=)#pVVbA|>f@&73&LAJ>8?{hHlbEB2kz_oE$89g3Mm`4lB)5m z8eE#H0eE``Yu~R#oaf0N;rsYMQ>MHfDujsKxg1a8>%RD+eSNdbbW3RX5d7TkP~~z< zkG+aS*@huO!;ij!bOTV^Df!?gkQZ!NKBQE5TS0rQSiPwD~9!_*#rl=@Qp=b zHCgPyuuScD6|{4^5sQ(=*sDs>DoOq-v_`{m>=KD8{thA}N5i;P)~0bQdKOEzXEa&m z=#@%J_oa8MKhA@)k4m;azZWa_&mQvwlj5cTNM3#FPUs4O%mGRvbEM0G^!s~! zDql+qe7FnmRdSQ5d+5w2WG4X7$2*!&tT2krQw8Nlds+iOnBP=>jcgCF5D9x7$30VL zWnpTX)V{;4Q={n+f$plE{sxDH{&}x2@#?aH~Y}w@_gTXY&uM-xEApuMM11JZb+_)k`nH=aiWG+KB$cL985^satiDi7#g4P*tp zqg}3tm}C?pESWG4h3|1SL%dcs1<}150ECAUkvf!UMQoD~#YK|n7!A*peF$?n zOPB}QxCfVK_I4}DJgzeD{DR(j*ojv2xSH5I*h^LOcQ@QrTJ9j$I}~A`uRiT!>f?!f z*cpf_+kC_RGZqlFaCK9Rsc6>O2en-@!!L5g2(c&cUe>SME#3Y?|J&FPaqMqw`@=!p{yx>q}Za#^{1% zoZj~R=qamCqgZs@r`S78w;vs4XbOZkCt?|6qizL z*px7#ts_G5Ecq;!E!DVA-$8Q~B6gB~N&4ue?l+cSowZj8BJ2z! zUGD`|{rEFhvgQ(c%GC{G%ExmdiP^HK+`>KD=%6r%fZ{&NPX+IuOoALBEsUSc-{W58 zQRi8XjkH1naiVEtqdB&nwwlZq*Cm$(_0gU-Ms_Eg>u5~KI4D@@B;2<6Ha30`QJQ7B zV#!smF<5m|S_|F7Ry{#ErtJJGN&MB=Q#YHcce@xF-3+ze>^`vT9jE; zxKKLJ$+?lN;?vI96saPz$9rIkgxa{7Nm=6iw#p3aCVRH8TBBS_pKY(p4@tRdf2uxA zg#u(sR^&!q%(M?I>MR=WoRDlUnC=DC7sv??MoZ#KJ$JLhmbuQxMOF?+FK0m&W#>N~ zPHUQSrFFdH{eODrN|xYXM%u*%Ik?|MERn!kNS0J{?l6!@NrKxsz7vbo`z-AmrqO&V z?IKQ1s%h&V@gbn$`b4Qfr9LX(xxRYc6Eu5ZVN7(r^9h$GXMf*GLcP|Kv$my0-l4`S zLHRc2kb}nf#Lrj@TL%1+j5JEiOISYgql948m3%skk!V$Cs~IK3BfG7>pdiqRtWjA?~a5Ns&T|Jz4_uO0^7vM3`1j&AvF5R;@+5J(+!&%@dY1}8Z~!0&is~wmNLx_ z31^{JN)f5lr=NIYEwVKRBAn~_#P4%Iq_LjJ-xMHDPdkz~jd?VDD2txE2OYWLxA_Q^ z%i%2Ar;*$#H?681$57-*He~1XjUh8npV>*!D666Uu!NI5&dZn96GYAjB`(Mluk~DS z_lhxbg(GCe}7`Yb3_pM4Rb_%P=;2bP`WTv^@jq1lNo~z7V2Hu^w(a`;+hdnHMjKsJCV9mvlfR3CRYiP zr#0xVa|n&oeo@nYh3L}83Hs>F1_W-+ZG+M29=W$vs z4m-Oew+zdjZB$N)67MH_5CcV}JxpH9z0{pVzuzvMQ?yd=3f0v^>&c05_1VE5`q4g) zpL*M??S3s$JWNgFBrr+bUxsqHfsU@SR?k{a*LYyMl9y=eCTM#urSh?{*KB9XVT1VW zxmjkIFr;_;U9adMyKDCs#vSSVz{b??k!Q$R>m+~x`YJkI@eP%=?ey#GpXON~w8DUD z8aF3ld?lUZf+_How~W)0%G$l+>Ma#=ECtd2q1LE`r8iW830uq9e8+D+wr6BBWIFa% z3&Ee)w(FDJtUMxQxthV%Wk{GDfV{Ap0~#gTgu<8A>aR8+dB$~$mlJ75HKLG{%X(FB zxe3X&wN+ie#Ni5?$|T#=>B^$c7B2pE?t$o&?4HD7oAGChWESNnh$@|jtbEfAv4+@U zwsuXC>Ewbq>wCw>wN^j&%6>T68ims?&YOn~=$)%x%fCFZ_-R3GPHO(l9Lj^bbqqyj zvnnJus2JzcO)k;VGe8&^my*cRqSbT?nN?J2i=~h5YA6e+r-KQqGtmXcLL-Pik8ell z1s5dz5STcS(u!hw|Fpe6dulNJYlQ zRCF?w&NKD2w>UD&Yr`ye|LDNwn#uDeClGT!E>>CgTN~%{%x=Oo^v#xarsP zRz!GpGk+#&FwY${?4-=Zt7a7~^S2HdkcqrE^-+K6Vkw)I_+g2$aO#6beZFj99v|S~ z3!cIp@Au62g=K9&Vi0JSbv^a{a#HraO4P$F;t1~KtLpT3s1~W}$tCZPo;M&5?@>P> z_hgtB?!A47iz#G?Bj85~s=5prT4zp-caE1z3ASKkQv8kK80DP61X@oqVzMY|B>BKeXo za9lr>zit&GoG=Lz5`&zB-AcSw88Kw9P3}S(HtBaqIQWSzNiELRpX$KTMWY@`8+=mB zmtvM=CP+Lf$(cc#$Jwpgdu4&SP&)nY!T7HGtIi1C3aVHDUStRb^H7gFbgED5WG6$xC2!p$K0ID4YsTAca3>Txuv9L>%diGMb1%+hmFB3PCrtzLHn7=Hm=#3ERY zL`OtpDbUL*oftZKX?mH02!7?3!?3D4M^_snY^)fceoislrhF>5I>RSYX3F(x{tSL@ zB}x*HMSNp@oKIZKwT4gj-cG=~f49+?`?M06xc|_IJ1PAP=~AFmM7Gwrk_gRl-h_mN zdi!Z4O@0%|5`tgFI4w$Ny)^!0#*IUxjIB4K$F^xNlRTBdc$uxoS51qorO6CT z18MAp7o99RrUA>=UP>~OpgQHk}y=9?KM_^QX-{jUX$*g1p*+x zCSoBGpd*Te!;!k3W@O7nA^UE5}Q02uTV2+FlhOkom}PnN`P`J6#InM zj)P<j3~93mGHI=4h1dk>DY#kZ zvg8)=`SdltUVg5mCJ$+>x$F(kp94z7o!qCU-OsmudQhP$O;0_K7NQ|v;@x^^aSlcKtLQ;Q+N1(Jg?WAh!kE5%dIijOq~p(_ z%2yJq+4bMbHQ?-iaH?2(HB7jLzuF1J#gJ&Q=3gdoH_iKAz8&>uwvUWJ&ziM{B^?h} z2c~6#hP_kU0AYk3A!tT)VyM~I5>vl}dv0W6&hWg7Rn8SdiN34mvevz#@hxNuL& zL;gTHO*zaAz6Ry%^L;B{9bX6E(cp;QI>|tj?0I91crCVvX`FJ>S-F9Bxc-mC+Rr7* zyIA0a<{3VZE8J2Sc2FL@jyI>2tvX!^5lZ1Bs`=!Af@Usg1aLbY;@LqJEVoHJKZJ}-H*{c5T>WE+9}C>~*6F^T_0GjnwBu%9jMiT1N6+K|)S#t3P~@6NTp$qaUM_5+HJoV*2^7hycp+T8ez&=g1>IkDr0%Cm6QCE zHph(mEKqaE#Jr$2GVJ_|Z?c)8!^n@@H%Xx@+Ycf~7inlq9^IZ(KC->^m4KrMuJ2f| za#&K=TREiWL}-54%s9dkc*0#oL{HbgDfjy=AbTJAECQ<6Qkb!S>f(_4;jSj3Sac-c z2&0V*?zkH|@!m{JNZbM1tj!(1j}BZ$VV0SPPG#_6fn&*0rtQ~b4B@BL6zNN=~vvEln zns#~Erg3?McuNKfsK3I z8ad~^*IEMl<(D6-8-UO}y`u|W_oTIf7>tcQF0d_mnl1&_2%A-Xo&EEK(9q zvhU7wUg-D(;_!Xf0wU3_p?(2s%Vd~LT)`rPeD)9CeSYjmW$ z9IeAPTA)__t`@h*n3kUUyqSVMv0gQrpVXO7b*qe_Oty;yHh#EucJ4Y!QZ5~S3+9*Z zpqa7oMD+TYwb(8C=$jzaVG`i{U|lZk8e z%PFp;W5s8sRo|mZ>T9q4D`WK>ruB2Kk(HTZic&?D3#s*Dv^*$?$+zk^D_RGig@&E= zhy;v?SanYq4G)?UmS*Y^I4Bb6Av{-#2&MyEs)y3WzK+HxjeBiP+?PWdXMO5)yBQ%8 zy<+XYj;)~)9E7?!n5pj`za~IRUi}@OK*P8bfpn`**M;tjSx-ZWYHvmK8fj?NsttAD z4L~5~rf=;7sS)?5$pX1fn`eExp$eSR--(EPgi4&l5NPb0gVrcRKjTV?>(EKFeoxVf z7);?!Za>2KdKH?X`mOh9xHLGdeL>TCVOw?s5_)CW9J5xhzBkAbS~q7y-v>H1MC%)8 zUx*pcaJCCpYM2krD&~k>^GD}!hsRiRj+zo_D8Tn4>mcb%Pg}zZW!E@Rw6y+y=JI^- zOnR8aTrnyGV<9JGEP((gb4zM#S6PT)nsXN#yp-ALD@pEc7~`=az`n^Fw>_vOVTW;a2X zYHSsYCuj@-ViU#ce7Q<0;)5lc_;hYfg+9@@b!iqlyVq{+KUZOmzV!^jRU%g+gZXlS zxa)w(J&f=dBQTuWNOOI%98bsczM-8GDLoOBCH_RY4lmEi0pBt#7wZ=tk@+-~k)!w) z<{J#&R^PTr9_!6=xSGn)8s^5w zZh3Kp#jdxff0=Ol;=8YotUb9pkI9zp3X?lUH}F4n(&H-qzedl0L{gwc%OhR!58j4f zN>1)?yv_eZ&IbJFUIS3h=GQX*zjHRfX29<-3;1!bf&WjX{=wP&2W|ehd<_%;c|?Ey z&e!}q`twVJe~R><`I>(S1D!MGI#8~L1^n+^4U}hLV1+U)Aa+hx=-vY?ERS;hKjCWr z+~47UxEfA&*5A3BztARisE|;2h6TzxX#$~ZUjFA0@~=aVUvv!wO4$7Ks|jRdgTgt# zU(y6ZK+qB#EWa?F$0{Mv-5)f8oa~PoK`g(h9X2-RU%wC#8<2$!{Kqkr-~qEgmI5(9 z=4E5&{B`~)`Xk)~fv)L!Bz_*htk5dipw?vJd`x>Je?U-_2wDbu{u>4KI1vBpMqx1U z7tsZ!jf6qa?IV5-gMZOpzt1c_&@b%lj|uj#Ei#w{_@ITD^mKrrUw9cG`2U&>dPn~= z+izC?ZJhtB-QS)E|4RHFUXp?mSbt6^DJa79$M9v6f@<^cD*Vd!m%4ul|JQaO{{r%a zt!yoz$l9N%7le@w$N)7d^yd+!`fJG(3oCTw{+9($EQ%0|VY)>5!0=A4t6LX~;g+Pq1}JopZ4 zPU2{byj-h`iR8l-;kX!k){yA+Kl|x-EcTCK^v51EOcEygzYxVg=t-!m0#*)CBJkI2 z_;cMI%kRtS1faX8Jc5@mrF87A&8_UsO>}{dEQ}y#Mh<$QvAw;u9TyXm#s6Gmw6ZmN zg~}vrYo+g?2i=Y3_hQ!ihCp2%Ju_%Ce^mj^`l|sGD@(!09c*3-a)Ft_5M~H78;BJe zJ7K3|=AdC_rg`<-6m+&VFhqs!BLhNZ{+|yJ!o~)@r5FPLC+!iheEa|{|4ajMFtb7j z$KTV~!HGY@Gk>OAgTQcDA?GfzqzFzjkj@FmW}2jz1{WY-RO0b$)Tk hzewj_Q|H%-DNw+dqRb}mHBzX~vD$QxOi8oLm&|8Xel z;Ucc=V(4N@#PWwg!O+FU)X9#B_4N>jLD|C4#L~{3i0#j_PWHyirY=Osk6PSlQGbqSN(zg%bJ>4 z8VcEa0DEKvewdk9>Dky>*_c>~m{?ip*_l~@y)Xy^?E^OAOvL$zmV$P6_P`^+YmMK1 z@_PC&C(4-GnY&mJ0sib*%+dyEHW7oE4bT@NrpERrrmxyNyEvH|+QN8btfa|C<251& z@9=cyMYF9Je%-uz7eXlqhUM^P0rm&ckM)YeMEpwIA-Rm~?Be;Asl(LcmDqUcw-ycD ztfI9V6`lulZu}3ASNxr=UQaXOJH3P*e0JBDo4_$bZOPR$)Td z&KGHk(brmfVi$J~Dnzh>*J;X-4eCVP9y;+=&PirKw=AD=az9_)X1yFa7^jkPD=SqN z-eV0Dc@J0p;8^Cx%U&bMej0)|ZStA&c6vBEn>iiICHU6u!}aLe^t5?9xU@B5%)GUm z!CI4GF=F|oS8wfK*Zqlufz4c{szHE_7Rsosnv52LHty-lhY27ZwrO>$UVXwoJ2oNV zO5fV=FIR6bNL>VDcK@Si1|m=z)FD?=Fz<>2)N`T=#3(ZsuU&XlpAgKk_pQEcWykF{ zoaaOb_-Z;SRS;TUCm+;gFt}y};zS|Y(W{&)Esgm_>Uu6ju%o^Ub-c7lAz9>5^Z{eq zs7=M5=0(?5U=MybfZA)N{-XpdlWdO$^IKTv-3V3l#~-K1QybS0`6(8*l%iqrj2M)wEZe-e*3TIwb|?A9YVGz$4xG%DFM93|Rf4Vjvy z96DsG-HYz_RV|LrO(lv=6jR+SBd}FXg*?VYT5eWW{){v@ zb>W||9KLV~#rEFaYqW);C`kz$HKRB?lrSiX!&AgcJSt`zq4bdvcW4w6QCZ^AD-Aj( zNXg>NWTN&KNSOlWrv>28BYWta;-I3;0%U~0p2XR>(Gt8H1er6(pB#c+g@JbCg#Q3* zV$KO-lo4vk3*W}o41p&>S0f|*Nu5U%g{)FbnJQlse`W~WieSxJl33E~-WwqA6H0UAdy_1f0(*yW5Gd!6t1jX+)6mXj2UO=KEW~ zHR%GA%J=-4!bVh#E*;`-m>CS6o&FV31oNfh|Q+foUIw5T8aeE)W;djc~g z;mHB@!#4)0T zTJfov@A*@)XnTQ;Gs83mLL7-1qRnB-Yf7gt3fjuy>Dq`(It$g*bl)soocj^j$caGn zN8vg@#0Yl^Vn=$;zL$O<#PI`g7=IBiRnFGn)mJ*OEfdkC)APkGnqycK%2(<c8dW`)?mv%_DfZYtJ=OBwV6P(;j1R?0gtSzyg37&U_?+KAs-4X`&X&9bf&1B4zrRosw&5k$0664pSpvc8QN?FdZxd z?LcP*u7|lzaK(s4@u2bT0i46St=fCl#jN*1>{60=^)VCas5cH<(1NfTJu{7!90BQh z-s3-a8>4={wF^|ZGI2N@ea32f&l*!vuMz4yiLkcMbK;Q>JeiJcIT>t&>ML!4!oyy?H#Wr<3*y*i%gX zTzmAjOctNT=?6Vhj0qrtIsO!9;L-Y z9w@!JLwy#J&UGrh(4z5f} zWKgU*Az0`gRmpp|ggROy?X)oi#X?cqO5|;tFX8?|;}dK3;k@n56wYziJ53FX1C6R# ztVYHYbv^7blKXf%QmFF0SH>s1kMkrSF^E3Q3GFjcPmd?r<>BLMCK##CEgLwNOaBnp^#3suyN{lAf)=ibF|k z(5)%XB;S3Pn3=IWq)Hy5cUK0gqZ_o(#+u79#1;{;6=AXr5i0!h(_=o@h`N@J|0itk z>Mcu5j%8hY+OYz;yzRT6;)@X8UxwF{?j72)T(Wo}XK^odDDy^~TSYH%W%05{JFGf$ z-<=aK&acrNkVz-H@y_w`9shX2bcZ6XF1%Ce4;}hS!VV3CqL@k$XeRA7dJu2N|0e0Z z-SGDYFTLn+s;b4ppR&@kZ5^Ysg0jVY(gfRA!ySw~GqTd(?NMsamA|yu4uMy@*TA?U zJbal^?;{u%IQVWs=byfBZ8TQovwF3GT~kb}Tt~&vYO`2Ne(hg9K4scowlu4U?6r^f zZ5Xs=sm94S{!Ks3bVbWilCv3Nr7&S_ee+m&dZ1e;ldBoShviF3`pyp}h|q0aD_>m4N_;M*!V3?-d5az8lV%e&J0sG;HY9I^cW152E`Zix zn>VhyOyEvkV44zq(N7S(Dr>Y+^Sn5H;groX2GKf-aF#C>ScMDZa-}hhS(#l5%8V9Foc{SxQA?<2CsEqB1RJCW)b$LCap{n z248&_m+U;yJO^;g-N)ogKXcjn!T2*lbRD536c%`=4uTy#-hU%~Swh3WtJdyu`EGmv z#U&NiQ171B#W*HS&Ix{blK()i$j`ml4@G`%T>RFB7PsPoJ@dPxD_0FxHiMCK>~-<9 zH2=>6VvDos0~I=i&_PI}3;o9@feOA$$Gg6%=i;8TdRALJhIr)tnEU!xyHvy*YJXQ&4cjKKGgW)4bY z(xJLl@l>{--wzERdnXifUF^BaFXYn1$MP_QV`_GP_H>2P14c-_Oi-BlM8Y%)rK7#o7Pg%G~-t~k* zgT|+YW{Y{}6d0XV)W~it(4_U#5eWVaKsU%{ul<9kxP%iAM`-axY;vi2 zPLyQHyW^@(&~e15m`>Raw>7KXtA<9f9Cz1Nd-%)Q`?vVhZ1+p0M|SqXs}O!P6YxjR z4dY9@urV_EeyoudSK!{`ONZ93dvyIPOPdEafva6wJ_QZkb8p*^4nRp4Gzl$oz9=^O ztt~z)rx=+&2#miBV}uYTb6)utK)t-V%6P_MFaK1M(#-TF*sHLuqa;dfm?(# zYd%Cjrn?4*P>Zw6dsE|+I#IZ%FchypxB|!r1r^i$>8~Rs3=w!OW0Sit>2BF8wK1!^ z{AF0>WgVS^)JNh;Jxqp3t9kb{9I(lErW^?GFL`0AYjt@7%;W?K+h{o2pu{!!oIiV~ zwU=>C+tmnX6x}5jXiKTB1_hWXH?lx!-X^6vYzNW%)%|Qc;ek@UuIMUd4xYZ*K02>A;TB%g&bdPfESt%Mh9h2Bk>0(JXl% zKU!hx7$Vl;H-!@~RfrQ+b)(x>#c|>!&IWMS6XbXzd>4j*kmRq&Xds9>^*nb?CvN^2 z6eBmw<^P2b?A<<@D&<#f8Mg(9CNH@afAT8U zJC@EZwBg37>1exKKan`)4}BdsVIsDIh$Pv92q=OUr7S}d0!)#a0ia22)ulg#{)C6> zho~chuIo2pDXEu%2UE}JqH{F-qAlDQd6jJPYWYchs`%@v)N&F z`&Kv6TaTGh?a1e&^+vFRF`Tg6QD#Fp zLanpK*C~4AMS6C0HhSj_(X<6o4Fb#cs-r5)O5s>#Me*h7u_#2~d!WQ*OI(N|!NDlI zsha2w8LeD6Q4*lLA|1)`hqW<}?(#Jjg)I=?pA&YScLGefg13>i(tb{wo$6F3RIkf= zv!Be!P-i0HHs;FKK)2#llGVAes*V_fKc-t{v5D&rmrbkw6zfnsGHP9rd$w(m_ln9? z%x0$uL^6zBn9e~6iNwe5AYF_1OMEueI`7==Af<)teHnNB9N}G}Q^=eF@wCbV3(E{^ zo;URsjyyJHmzFU#GZZHLoV&~@SvjgoDXBGi9#hsO4Q13ZP(Y_mHC#T+!s}sRiCxbt zGD*&qdOp~0rO9>Tdgw_0*p}j8P$bH={*;3xz^Zx#uFRAt+@(O6YenylmYZoQ7C#Z+ z))C8H^eAk=N^P{Bik3_>(n*AZi6Y!dK*`BUD=XgA%gMQ@(5#k<)*OfQeO_X@<@3l4 zznA&O&@s*6w&GoJRr<y#$w{(qKQlOP%{dcN zua@#Qr+h}rl~J9umpwDd3Q&j(T>v)|wk!zW-;coI=pw!i%EAXXMk24+P>WB+r6XR( z!S2R)+qWg=S=KTTmPyHr1X~-bC5u9zBFdDR zpvfh9FHxL zzH9+1ktHtz;hr~ZbdU&Z>?(?eJW2!U0j%al2#a?vdh=H)|3$VqO8giUQ>Jzg|(wjbVt4^?&ppe^^(*UDwu7V3}H zO!pW+FN^C8s12K;3}Wmrq8?Q?{c*Ez)|-j=%=^u`D>gL|pG7t`*|TakE!m$rJ{1R_ ziT8RaZHB&m%7U(K+C>=^VSykjf5i59JDZ*S#G%NUgQx`3c zaZT1rCMPzQc?$Ta6VSpINUJYLyN$xtf#? za`1?x@q485Bu&v75goJs!rms6Gw>Rb&COw}n%lSZt3@hmO`@i(YMzNO?0nRYig#!= z5=M7uIue4kF6(cZlN419TVq}lFBbbBFVhuC0xTR&1Z%@-T1XKjUe@ffq`sPDkd>U0{5;>;*7Rw=Pf*Cio#4Pm&6fTL?PQBVv`cZ7Mt}EH8Um23fOUdI|_qYPYQ z5=QbxIwLcqdfa?cE>bZB<3OK`Pcar0<=2iD@mTZ|QWzD2a3mpyycPiMKr)O`3>Hb2 z@q~Aus6)%+2$-;i&~k(_;yzg9L*_}IYM79l=z(v>!q>Lo%hyWk+kdEDcvh!_et}RN zbfx+aKjZ%c&cg)w@4v>44Y2C{gFc{tHzOGVb9)2k{|57)jWfLhM*sfPpNNTt^S`&Q ztH5jDON6v?ht5teEW)QHkD-)6PcW(G$}Nh|h=-vB54F|((g7)_+aTfKd9&KO6{Vk6 zJg@-v$m%&`^wu~tisPP&IuOC@V15H?vCKt$TQvYKBEC6uFi?0a!rT@9G4d;*ADhkm zhW;qy z?d@l8$@h`QF);ZqytSV4;sUn2P{DF9Tk_%M%;k@Q@fmMnnw~ynr~2@qr}Wx}lIa>s zs=F&E&P*Q`+Z?AS*CP}bVOeI?4lzj(baUw><9mOt^6mtw>F_K6rw0MA(Boeo`~%DU z1yC|5yBfLt0c}c(yh>irF%dBc89JN(Q9xW+T|-2TM#R+0P|a1@(9W4o-pIz%(bW`& zL0D2m`MtA?sjZ})nLW`fN~&aPZV3$U-V;#@0s&D|Dk27XClgbrS1^-O(gX+>TDrUk z3YA?Q9BfQ&Uol9=SHzFuwJQ-*XJaQz2N!!MBEX->r#caE3cbRKuU)Cwi%W{g8afaG z{y-f61-k-%$6f!Uaj!zg|D{!;c0eHVRbz&~G^UdvVtCaK7_l1KxxDJ?41`91xm4*D z3RSUJwX^(%UjCY>zoVbOEcvJ3f3x+M?Q({;Kv?$w>grz*sW}j8W&6WbLVtj>bO1(R z`*h5#0HDX%7=hR;8^^0Yg0HH&5OFdASI8fFyAaVaF#}^`VM7NAQ%iFTpxSX%`9~lRGzY-?s_vh0Jv#?G z>wjPCGoD^Ls;c)lb=P$aJKs4&oSO&`LbyM{d?=yZ9%?HzOEEDr1`R8D4$rR-yNpes18+ZPO&?%qd7W@n1K#sDh%0RL4zBQfJSDgC zzY(zNZSXq&hHJ>Z_~OpO8FK7(jGvqY*eZ@weKQQ!!tXnL*rW7ikW#TVYVjqd)}aH@ zOvDtlq_zJdOuBe9Ysq}0_YH(q@2X{xX<^O;$N-O(cG0MoO54^|PGhO=8zg}5{d5m; zZvp!-$maf@@7mt9;Yt~={89OIR5qX2bH2Tv3#;Oc=+RT1R1q3q6`ii6?S4RL9V{VT zB72!L2#WXg^(a*aFYDgJ5^m`cg(rPdQo`s9@j2uso#Z#aBA3!x}P^%VdXy%PYc6 z%_6FTh|y@l8VdfbIqftFXFWLhh~5DzfM%7AV%`y;zg|6lg@23ai%+PWdUtZNrgg$G zSy^01pmE2qd$P7#OyLSQVU5YfciiM)JQFS2>iiAzrOFp#ccS1Fal?bQ>fvH!WDM z?N0FP57Nmm#z7Y_6vC<-Z41shR_AR!*b1zL4szI;#qycrJE9k6f;07{WGdNg_WLp= zX?h$X12WlMsh(yS->Cx2G=s?a9Lae-z1=n*_Y_#oi*~6})i`j=e$u4~lk8xQrHbwB zZQi{I&AB9)ji#u1gm(;O&I5MK_0cznzzKRtQZKQg9g)Jeb z#y;+ht>bZQoaPtED*b2KKHl};a9~}_-p=Q%F zfAt8v@lyV9Hp{(^{tEK8Ic}emy@(u@%?-agM(z=-Vf%Y)oG*hW@}gOBO%9ZOmkDk; z3Qn;JHLhhCyF>rWN2AaREvE8M5Snpsop!HB=m@mHd{4Xc%fegd$!*zMy+^PPX$g>a zL1}X_rk0qXcyvX;Vf+wyhX_r3k76L14M2Fxti^KJbx-I5Q}Y_PoCdSGp3ApDYumT* zA-VRsu3uo&p>8|KGU@W4>jjW6FAr%y=C5XoYUpsGpWn5ttgLE+8NCM{%fCy+R)NAs z^0fj5QdWRXU!b=_SANmiFO5a$u}V`!w6CqRiJT6j zr=1<{5)&f7dh0Dw+dOc-j>Jon-mLMZD2^&37IEli=<0m#{QWLP^3cxq+vW(Jkhl*Z@+w&?wixR<*w-AvBd69r9wx2GT+tQv3w?{ zBw=?6P4$;9ofe;-(u%)wM!Qy`-y2lb5Tn`YMrhD;wREfx6R^Sbif zdK8^9pYwK&(KgrpQGT-fHIqo3`pz}17y%W|)k$c1=VkxrPP=E+aOQfsH6d5QMX4}s zu)Gu z>0Lt@Jx>_RZ_8B@G&urGufHUP@7RI16x@us80(zQz;dfC58j-`f0Mu9BhFuwzd*th zH%KHc`pR<6CNVWQ=;N~ScBfuRbkMXpuE3r=8gB&a9W=g+IfEk-@@G>O7-1p>1>t>w7 zJHz`hX6Tn!R{8{1;xc;mu0*RKb{s6*Vz0HGm1h zY8kwc4jUM~a_`?eQ<@b&nXRdFf?*ciKWd>5Zl;>UqQ-p|7Lq1EM~BUJ`~jA}*pI0VIN%B(BG*Y=ye zc&KEiV%6>eoLl|t2x4RVL(LGXb>5Z161 z&0ML50k`+KVc8mgENtQJHCC0G8cJbozd=#Jx9`Y1pN51Ir6bJGq?1=I{UjtUS|fIr znA|UL)J}`+&XTu@^LStg&IgB()AE-I&=vEWtq!d#l;A5qSIxM22=jgmBw$=nt!|HW zO%B(MS+k^bGo&LW_L@RB?CSX_$hoq3vD>yFDLXwuFT`%GFE@e`pBw z^Q{4T#WqF>w4yc7JMJUaB-WY(9&1$E8Zr4M_W1z7L@e|V1BuWySInv9S#M>ZNBXdZ z!!{R!u@UpcI_fi@aT-~pc#VpEw;(VJ)8kcIdbJ*Uu}$wD{C<-_3GS@TTp&KvKw4q?R!D6BcohCXBy}?^KW=C?Sf+E=g-Y(uo(=5Yl4j7YLdbg|g^z zT!ey}lSx;J12+ER-Rbv22Irfl`iEU$VKFvw_>f)uX zJkn5vfj>{LJ)^x~Qn1n`vn$&{&c{q5!hyY_vt_hZcYg_gj3bctj#st8*<5v|D${#s z*meADNB*t_eavQOu3CR*&OJh-(Q3PHtV*Xr&eK|1w7&>*n1(I#24ClS(d(rB%VQ41 zwaa$Mn)ij_wxt?}-}dmGiiEKmk~n&wVoDXjQOkvcCgc=nO0F4VHc(`4elDm&cAO_G z#eku2z_X&I2kA~1ut)Q3oZJz}64Z(8$aG$?V=|4qT4Yf8(IK(a#?YMSdvgD zDn~Sds3&EMb*&M_^5*lrpqz{cfi(9S@H4w+z+!^r@9M;BPhFWPm7XXd`!<}h<=6kQ z;~^|)cf*FpZ=A+}@3|1xw>Pdc1DHsnwXG0|w zAnEV7a4wmE@DiGVNbglA@R^=MQa{nawfdj{SBC@t(}JZbm^_a3yROa9SEv#n<%&y<~Wghw}b#*a14ip{IbyE^)IGIln0N|uxR zB{24)EO0ttPr1o>uRg$`>Fm2!y;2j@RlASn%&=DI<1|jd_L~j zaGM=NP9_7(lEBHpp5h%2l%U{SY0NV*7WR3{8KAh%w0%jHWU!~?$Y8(f>wD>-HpO7b z(z)KqO_(^Mu?mNkx8?SoY(6YqZMTk(TLe=Rhc3r23%3~ueR|rMH-Khh3v8Z)m=U*w zf-H9SND*Zffy=M>kkedLOg-9jFQ+fbud}XuTzN)3u~6tLLOqpID}wxig(v%S^2H7_1yEA|Ls_2Tr=6=4;j zDxWx3O5K#^#wxXCyUI7`jP<_x99{0sIqBm$kA0UsdIX&fFTJskue&ZR(&O`ccCxav z_2vPX7|XE{MU4}e{Rl0aSKqe~W$_=K$-$ak++TozOYA0scjp)t&cEbg1_Dr8vW+?0 zUk}m93$q2@nym1k*p*ikIv5NsAnbCq{t$S;?yp?)2MtqvCZ7qp`H-z8{Mssqf z@XmChBdOP^SEs!i3`oZwftRN|=9RJh{MpzL{=4UhmVALWQxiO+loJH})h;R9-d)xk z2BfkoaBunHoRZ0sw33^=Dlw`610-Bhcqha#6;CV6U>0L}W$1*@D5ZV6D3%#4>TmG! zA+_AwN)JDY(K_^jLBr3ugdsFW*bu3>N8gAE#CDNL8M=f_o15KUoNcW zQyh%R(59^P^II-DSiE2$7f(v?z6feS3U{pK&!_f(7B@xz++D<$R$u_bBi3&K&lK$z zs`H&x39L>6S!`zEvPA;lDeWsiE2nFK-FJ(8O2Gw0(a>IB_o~(b+3(Y`B4RcEG@&EI zXai(V`F6v+w2_@_3hIq7P5X-}+&)sK+BhBhoImIFKClup$dgu#Cb&mk4hCuGMSMSB zj|nESk%%alw_;%f!;k(X1qT^m+O+R-A6&GHOp}8kI|>rCo(wj*P=L;xbW^f-28#>R zAkFTavZPsDHZDg-$`a1D#XZO0=)B{6;6CfTs?}tFI8S%;bgXdQP1b2|{qPhQuy8eb zWbgNQwq(xte9Qd|{=zo=pfyG?sPE@6Y{KRry31#9o}l%Cfz!QNVz3c$p&faAU>YVp zf3>!|j}$ZlIm1vrqguYC_*5s)pIJmo- zj>A=JapIZAa%7f{!mVDtr0SYZIoubCU14Mhbo_X{02DPLX2!}?Y!>aMw+)ud*b6YFOiIZ&46ajK|J#N$Y= zL1Uvq*C4ZDsfKA$Ya+ri!*gOYAqPd({o0KDJFiin2ZBR%Bd;MsEpdDMu8`>HfibQ z^Hi!?r8@+ug)`8EG&I&D)*pDFSC6P~f0A?-{5;4MnLxw28O0_6z1DD&Y^G<+Kb6z6 zX!d#JXm0UF((x!8sgwOIocAp*Y4>R4%I7sJ^+%~HrJMw6b#&G@I3PtWzE*pEQsKla zkwKx)A~Tk7uy0wVoVBU*yfp|Hue0=Yythfv!Dv9msv|Ubt^OLS*d4};M zw%DDO1+Gl{a$ZlT&SWE6AFAQKWt{@9<;WLIy|q=ncbJFSZ10EQE6ET(=AKk)E#3Of zF8-vi$7_zi)qbr` zJvCmx`Ck1Q)Oo#Fzw_ez+*+H@&!y2v+tr><3imWwy{Z2Da0xkIOGrgZqbdC7uT}FZ z_Sz#+#>Qyw@DYI@Y{ZKh?Y$?|$LdV&so zLydm+I}=L~48yPD&|Xr-=q{@iDd1uIxQ~r8ph}6WL*87kzboE4480C0km^@P3sR%W zUH%DInFOZ);9P+*WJZ8_#EL~W%0kbz$USdzEjD5|{C@UpmD5ccW9$W~!uR+?*3^6w z)+UBYgDJSG`P`w8W#M$A#BnC(?qq`eVWeLdwkK@XxP|IipJa~V;sUwTj{xt#0pC)9 z+2$SPr2~xwl?5FIr86VE)o4qwkz%`nl5;L>_6j8RiqBW}rUINvZWlQ@Hy18buSzpZ zD#?~%(^-h(LgeE20^X8LkceZ)PbxtaK606A4xcBKC8Q;kQyJDnXLvC~hR?2LlsK+5 z?pn&&%-o~6-A<>hpw3mKJ}&1JWzM~@oQ-Ps7sIMoWwy+9-rSA(>U&EN)bn$4GK~4T zM^p|Du%;sp_Gf+_9wy|bW`9TN`!r1VaQS4*uhiH{rTtY{A=peAPOu3QuVO;MkO_6b z1jMaa)&q){^Xs^CK$5?FzK8eejDQU)_6Hi1oUe!|bs}c#2GO7Uy{}4Yw+0z(%S#l# zoU&6dS7_%&!;<>)c87ymRPKU){<%Y% zEGP8-ViPQhXUABbH)d|hekq#@tg3D~6`|q8%%Qo$aVeVKs4Scj`xTN9GsJotY3F^`DUjkb3;jd6otcWDdr8s-+E(lEMyRE!1d7Zpm+~S? z!sdHn73@o!M^hK%nrxz9?UeKO-0s+>p3XrR!IWz(-+9UCm5j3U(p9tACNvJ?)|<u!TuC-7zQA+K7eC|sHTpcCuy*dY4N((DIu>@3-t5E1VPk03Bh!s{Y!8KOcqq?0>kM(0g9OEBiXeu#(-!9WoRoAsdM z&SU{`YKyq;@+$V^?@jzC)%C2A5?-dqiOyT-aiZI(Kbb*x9`)77 z5BNUkj2kAT&#X&IiKg z)U$9ENzKRbjBGXaC5tPxUC~r!jm6L7D#D0f1xrX1y-*Wn?^dlNWbsxW$Q5Lg3QLY~*@S>!VUi&AU+<;L)Gq!de8OiSVsO``r58MjJg=oTG z$1o;$+o4q_7!yZMIOfNiO~30U z9A8~PzI7xoJ{p(j@Q6Mcw-(wPG3lJ$>g4%uu{yxXH_#&BS@HU5Z9c8FYL4Fm*LH+G z?4_7-`8HVkqJDt~rfZoiSp*>CY9OF$zdD8BVy~ZI&AR{49cb!DNPApcwcaa z&oK=-eNS5qb(a4Yppt@s@udAC_Mzx7Nobe4P*$Q;s?rFCVdzNZZW6`85^{A%A4l$19J)+u?m$B*@ zAsDPB-I=L7LL`O@+GNH{D|(2+kzpD;0mk?zDwZz_ev2wTV!7XAqqCSoz8A8XG4Z-X zL|#lhqG+`%bl!~YL`-EXiJ>Kq1L8gV%S>6mi1;Z%RAxeJHh$Yro4WH8#_ybXq4<&Q z$LrdT^g@Ux(p>k|Yx&-fC`ges)L&v!h;Z9j*nko)V1x1F4@MNRZVN2X8zK4#GPD6? zx0|Un#4a$87)b{dxzI+m#gClK!SHhOCv9eKdJk`=rAMCd`JHWCH{_vjqv6{0BK;aS zqVcL7A5Xv@)8SvVBGpk(LnuyEeAhh+aXPC9lGGln&|iAamOySt4Ib0B)Uj_(FF3YG ztZa%tjBcHtV_FVxt349K^Y7eZ56Uy2j?q6B;PC&vjYWN#Q+hnbdJf%!WO)oI^w`^U z*q&5sZ?Z~s=6?_g>_`&!o)>w*nkR*hHN<3;KcKdu|jf^sc z;*R_Dv;MR0TY}A7Emndb9{$GogX)~e3_a>LP4@O5YpbDdX1NmEp*0TrcttL=)Rsrj zOru&kj$JkpqLvyL5{|H&MuQp94dLNSO9v|P8rv*#A2Ian*MDO6B#w&S_K>%p3vt-h zZi%7tjX4T8s4jHXEQTFePTpI2A8V$c>oDdpX6@dwL>C8cHn6K^Xha)21zlXk>m4dayC*64GD863icg)|VP;WO!$ z#3TH{5o`Pm79Y13hAML_AklO#01>t0!C&e9V(`s*i^EKPAZWvf9*>(z1A7E87jff+ z=Nzqz-FrsB9rcqV>^NeRp@!P>ocPwbY?qd8f-j!W@FDZP02>1G;FUMChGR1`H@e&%#01b#EQ5s#8L@li&B&RWVCIOJCTIM z;>@xz@pVF=7Y>gVvrLq7N;Z|H3y4qQky%N%$1EUo)OxDb-&-c#zw{zL>!Y69`zgNQ zl60&R|C6=B^vZ+yi#_ls7|!tu%l{XOdtszFjK2aJDCFUa{fX|0p9taRHA7#QP27jB zF|4#zG}`Wg?*3j1B2r@V_mP)V(UbJpoZw{WtnhT1F1(;5sLZf5xZIFC#`^63IB&Q9 zgI@oE?8D6Rzrg5ql}79W7?Ij8(7j|3k)b7Jh~E`Zw>#_#7xId7`nQWn^lJp;-99W5 zNEB*)oQQHahs(OvX+vwlr+WU}PW!%~XlD3)e67-?>~417B0a`xn?rqru60u#DN`uZRQCgNKK%UR9)C2#{^Z7OVe<#xb6A=6tqyEA3 z`486oZ}~k;e`sYkyo_@|%$Gr#8_%KXLaVP^U}uLsDdp<@AZXaMY-EWmsT z%*_AKcs+mSr1&3R4<|dz@4TMBs8!m)G!Q`Y4l|HzrAq{S=jMNQ+5WZ50c8KM0eL(B zo3Abr8vt07gZURn=(RmIV7dxjB2M<#MgYveC_}8QjK8*Q09GPqR;EApf%G9J_Saef z#@Di}?3}-jU-f>a7O??eD0-zEy?$AMO|k-A$;|mGd!-!#fIKE(9pLeA6r|T#_}3VU zF%kWulL4ttVgO*i3*f2Wr{M3)N)Ygi^Y+K;`d3a524O*9B?ejf6{};vWw;RE~gugSVWP$XrKUb41kU#au++~mjTJv`keii%6+&`56D?iD< z*nnd8PPRb4+@Cx%HhNYfI-pB|n^zv!U%V`47T~n~FSjCQm9Lvj3a6V))6A;ltO{SZ zC&6pr(43l@GMe7VMS~;$^V0Q8_y3>u`)z>!ObheB^53iX{`&sQhX7{g|L#QF7)}Jx zcW|O!*&kuOO~T&@bDLHPqKc+HG@=T>K`yRod)g6QPM_!9GbZ9|37-#%LyY1z%XWs= z3^q55H-V-K+q(kk zh`(0DpD+C}|NbtYFfiTAE9;X|*3iYl#@@xo(ul~7nI6DM&p}IM;o{=p%*DW9`#Fpf>`h#af$3v@ujXK4Mr34YYz^$@uO@&+e|2DKZzuAaa)(lci;0nmjggI! z6~F=jUL9x{IVczzDX4y1f*ww$W-!3SHvkyM|M??gV`T+iQp||{NA}9?eElP``%?zs zV0tBh{=1Bw1z6%AG8W)k{aZO!mVee|1>OSwQH}$+xc{v#@PG|CDgP#8W&sYszss08 zffvrd$rza!{~=@MWCdPZ{;e*6oeg-Y{=1Bw^Pe(K*1yXb*@2b+R+o{Tnd9$$FtW4# zQx`T)_P_guk(u)!{W7w1a{j{y?Emx&fQ^&o@BISUSpT65fQ{pyl1PK$|VerA-CAho04Q>hU?(XjH1h+tN2p$OTA-KIm&N=ty zo^#*tdH#9V`i3>DyLVT0?Y+CIdp7%5MfzSygceB0j6hnp1SoAm00I~QHu~lWTwDNp zMORxR0KK3dSkKbN1VH~@&&0?9zz8WI58&ZJFtRp$D#-p@1rZx-Fo5Y-0eV$geRCrN zFo5lkLtz)Nr~+6IYy@EbL-1Y?3^ua22CzIGBG4KU3@n*dnr1z8d_C^rx{!pJ@-pIkm(cS=J&y)U; z_N9#s&GZCpTp%qnK>nB*8R%Hpf$VH707e#OIyNR|NGtS$5c?n(aR7k+(30QU+6Hn2 ze5&!gPo7Ty{rZd=)GI^9m&9;Zr=zTO;;eo5b5J#(Iue9Y+7ai8j3JFdX! zSau#8My(m5JUJJg*+!E%yVjcXT;#qb#=HCMgRO=AS=Ul)?e4vgwb{~|J@L(W z2u;oVMs<~n8Z&oJYwy5p9B#wUTl!SH^0-nlQB(HqBKokEiTfEFrjBHb<@7jmx#2Nj#U0tFuW&#CQ#cqA`E;mddC17es{`%*B=J$;aj24GcS zyH4LLL#~vKG&`i*3$pLOvXJf8^*xx6LY%>>btpv&hg30rnQ1ApZa^bj)up+x){8_b zL~WtfkYj)sLRiz-e``5hZ<5VAKN}$JV^%yzJFHu1rOJ&X1>X{Qqz3*XD?`Y0XtV0< z1V_YUk{V7xe>Sumcq6%%xZ@F0mhRo0>Ls2J_i3|f9O+0Y-RP0M=@h|fmi65;KH&9( z)Yq|o4>hIKq>5*|MijuWYjCBqp9Yh`Y&Ec#TDS<-SWB-SJ|>ZI&nR$RkHl(~0}5k; z>GH#|N`HK+qa54}f=Bdk#>ss8=Iu%~RayrnJF$i>c z;fiOqv``&_a>$^57wnN`GXJyaomu4$o?s3!%AjB^iy;;v9=iCueS@)%tjnf%7yN=n zn}%gxOE@(lkw}yQm>-Ge<>lMDqh4anEb!4;o*5(%r0CMZ8(P_+_1qC)~N2 znV0Qi`tg|CHU)DJl%$kGF!Hh5jk&UghFMlt><0B^YWigGt%yVprjwnkB0ak@z?&QQ zje2xFE_OCBByfal^;PVCBCUl-+&!$37x6D$_(yVA|@&sB3jBW=A(M^ zI>TceBkie^Z3K8S^EqCqa|dIcQpOJes~?vuzYVUw9XLzdRWnS0#!;MD7H3Ns@4ShG zGCiybK24|uN0}+6N-4vZ`qdRL?NEnPmp~$-EoN$oS~&B@J94!9x@S4xp+oql5PI2+ z8m39Z)0(iw%I!AL+ej-SGHe)mCY5S4R;e1ukX^P5HfBp+Y5N!xSow&-v{W)UyC4*O^qOU$>lR$IR^eU%fdr8PO&>^4j?im8)y1IUY5 z%NIG(1Z|0U#vn4n0d|fWq|xhU7L+4B72S4F2@^p5 z?%T$4wXrwy+j3*)vg=dp=O-M?qq;=ukxZX$AB5f29}gsVc^~yA`j?**5PM_2gO(yK zEvB}(j3-bKKx3CdDN~?`o|g}DAJ!YxoQFw;|lsSp&Pt1n(x`obzOIiEew20uQp#Biiy#<034Uq=%}jO$uCH?!VbSmO zLvvkU|LAE=ijCJ&V3>&^m9JZ}N%AX)d5IozaAeKAwqg*x%YQ1g`=R4@TPCpX<1>!& z^3JYTTb0Aim+`bc$hU4)Wc$pT&+>4boeRo7mL$Q8_nS`ipizrBF===gq)Ed%1P!{d ztHZ}!&Y0;6aE_wp;*Gw5L*0CBkM}9D(_JWu64qM*|MNS5EufBo8S9&~BOcc?bKfYT zXqp9ul{Ki|FiMqyNRO#hSc==tbz>oA8 zx1;aHh$Wm7Nv8bLa(my41UH55K@4X{4X(8!dA(_b&!27=kN`MVc>Jyzy)}iN0dV+a zJv4)f$aQQ%y08MW3iiMN&vPcBAb(&tOyYvR3j$Fa*|8p}prLlm173Sn1M$Zh@!|9p z>x;1_p|?6?$cHCu@5+V|&y9UvqZc7U4Fl3*+}qD7qI>p<@k3kCHtmX|`0loEg;KgJ zedO!Q8Ud%(Uu>n!vsM`2KZiNbi%4b&v&##RAjVAqsvi?XQ78E*9nkrQ4^9Tj&BF%q-w8S?WdvcTCkqxXF~!Qf&qb0}GL4lOBxr^r4=*03 zmJQVxU9ot+EVoJVty%uW4l@`y!1Kdnn%}rk1mTlo@gHFv1uQWi&-?396KzP)f(tPRj8OKBToGCKW?SpMfc^d4XFtHQ=q zbJQg3BJvYc{J^!5Y}k*xy)7Jj&vHMLg&9dyOHat5!j-N=V_fDoA>%4e3auv_f$^xp zE07lxU zPZlL<%EGuMmItiH=%SaGPDRe~GtE|anY+f+R=jOlS!yf}d6Q6g*6UUZ|6FN+8jmJi z&O?eN_Y>2)#-<{wl`6FlBI5a0>G0R7O}p8x&!-Y43UY6V4i~1O3*E7c_lj4D#p(fk zTtSxYP<(Aa8^U(xL%a>ea8ZEN+P<^duQd@k2$fx@&4_aYbrff1GakM(8`k*r6{ zsg{Hx6>Q|*k7sO6s0czsK3y0?Re|7E)6H)stYe?{#Tm?3vQd`m z*u~M}S2gL51-4x_PJ}}Zhn+h{u5Z@iG>z{T-RlL8VKO?C?K&TgVM|onXR9Yt6A6zg zX97?2kri}yn-;m6>kZGYzAKvr(A_@rwtF&hi&3KD+7w=D@6qdgu@ED`PHsKB8##5n z*-gavw=5V>VByu~T2A(I;neAeGC0?p%AI@M{u#=XGk)#7d~kI$;MI{zi%}VNf;$z# z#>skED>xMqW}Ol4siTCB0fLvybUwFty7DffLNr=1$5(ATurYo~i&2o$dWSw|qJt8d zf8S$JTw^K0(F(derjA|-5~=VYD-pJRS)N3Hv)%^xGZ;D#xQ}{1=#I*p{@{3X^K*2U z`0>I1=IH0vbY{oqV`p6?8DZ8(*>%<20r8*Q5q*oN`|G=R=jQa^j)Ba=+9HXCzGEBw zt1?504pNEd67pjiBsd$!%}e{_s? zie?b-COGAau8hf^s*oGK4u7lV{4vtmV52#K&4H!mM>A9n)(jg0S>H^Vu${r~ne{29 zWfw7w=goYOqo^uDY$=bBO#Za%2+~b&B^}CeDk#nE5Zb;g4%Gx@5ihYcIXdog*f#Mv zmc{1v_GDI7;;j>5mCBk$c00*Tik0ozUC3dlG5@wEmJYKE-tZ8N&eq%#6&;0Qx^8I!1POR!AK8Kg4tO%I=DB16Z9* zm#N2#*duf_C@={yno$%!p?vRHD~3m2hCmS(2`Q`c`N2R5GZ%%cdN7|0vrU-S&8XK0 zXOl^bSvgD!MS{rBf9gr4^2)~sIM};Ih+9PhX~PAN8?#s%K!w-DXX(k!&RZQ@m!qEv zbf4)Kia=?I>&XFye4sw`O__qlue(FwU&N*aXNq`a<>{Z6)x|Qc03JwAyZo_|GYYh1bI0`{u*#Zv z*)7nPpWWQ*)pUI<6sj8I+BR`qI+f7&7D{*eaFccN!)92M)Lmt8=J@<%GjQlL8M=3@ zi;9CqIm+S{?z7nNtDx7b{j8R9;k~ls+b=p^KgKP6J?zDn4{KOjyo!>_^=1h#JBRTYUp%mI+@X| z^jrC)?wMELHTS&zaQ_9#S2aS@tOmJ8@709|g(Q8WTfXtf;n#tHM9{fc9^B)z^Rx$C zw$h-Yq-Ms30Qda1j-m*WVL%o~o-e_y`h1{HR97`Fp*rZ3$GU2e3Lw-?5RUr;%zLPh z?-h-5rw2!f>BI0_zD({sraEOV*F>%C@Rs0|mUMIuP#uaUbTjIquH@WMv%gBbHeyG1 z{mG3`S);|}Yb?W0*hbCX1}Cb@<51<1(q6(bZCx#xR&X7kry-%d;_qvy(8vs@ac!)P zd~U0z`LX9`eL%lW_m{6uO|Y^(8f}=?Jx*nQ?LP?ukYRdRjGqsYcZn}!cs?sFCesaQ zdVOQvtvrtyZ!1rrNN`|Iv8Ql=+-Sb%#)a@``XIcY7JMQKD2<}TGd zgH=>(xMW&sOQb{jP`~x7%!5_Etb0VdTqYa2AF5vT*Xb$9VDx<-tiB5>OVSn zI!I^`dmhK_s=_>qH1nC#VDDGBUcF*^Ws);Bh)5Qlv_r#?oF0r2`h&AXKT#o~LO!82 zaUNS5oPs`T=f|hnrW7ihVd{R{zsRQT9-bg$L^U5^z1-wDaWQl#dt^nvKOhw0Sa-rs z>}y^*f>>h26$;K1wwa<_LV$TzN`q%pxIam|S@HG3GD;dM9pHgrTiuqk(4SdqHCTRx}Z4XPuWzfUck zmw(-Sak>6If2qx+Au&PPX)BHW$^;abe7=~oKIJ)5s(|5;x#X5knuku54+dUNSTQ4y zxsD*>YN0&$&me#?KqV{trW~7$M@zJX`=*P)Y0rv?Ye`*~pOaz3W1!%KR*!~e2?5CZ ziU6dCVqymThN4Cu*0{{!{du?~aK+0`>2ny4wr5WUp5%}kEyu;@nx)agr=0GM$j6YhGjMEVP{M6aN$%A(hk?7vbw z3uN}l#%dmv_^`klqbBV%7nK(JQ)8%=p7}B>JtQg~S(TlvGeYEEhiJo%&s?0M8+lzr zP@5amg!Q`z|80eJ|BIFz$qR)N4O5l7O2(VlTR#hHb*c24;dG;H&LZv<*FWH8UamC* zcue|CILp@6P#%QV)z~ts*Ui`-*nFz;C5nh|(zM6(XlsF&{et648ar)^2-7f3pW#U>#yPbY!Z@b-d5DhQ`n7ZyV@ri*^c^FxBGv zm;L4wo=~lglz6R6`UWi4KdH2=mjHI2sGR#%Jt2qtOF8YxbM?YOj@Fi;pOg_w9dTZ) zpas*Sr;=8L_ZP6h9m?!hs|qVP3en7oGF9Bu$Jeh22HjTcE~z+1oVA3C=L4fYWHbvAj zewZyu8$7SvmuEqvN{m8BG@ql{rS+Yl+ya0jKFR1zBr*x?!3E^feSwxq5voeL7VKW4Ok6j;+H+@}Un>V*^vC<=v^Cn#c z>=qA=*B|TRfx6+t?vVgK{uj8CbW|NQ9>U}OgU&sW!a&u!BKKwZAZVj~k2;!&4Gym3$GyVw=+k`~)|`OdOH!!UutUZ&*zZIhPoptoBoAw-`>HcG8vL_c-Qjb+Isg|C&inBue%=AH_4vIfPdy3RREAK^pwbZYD&>YR9r|}&lUjuBiHxugeUO#jOTwf?n%h-zqCr&8j=Eh z(wP1)jcLUI^iSGBB33YEcvJ3f3x+M z?J{~+kc8;})z!a}lO~WPC+i=s68Ix6N(*FwT%VSS1qksND+46!$;$qu5C4;@U;u~_ zGD7~)8w{XjWP-%Tf_k=MMrJ0a5WgePtNyhMu@sU}HZ$P2HnB8<_?un>&-^2hhnNFoVqpJQT+hY^garBjQ(Qme=IWs+-0)cJel+QB?c7r9 z#F5UeCwYJhK+P9sg#scFt*w!uJ|B$XdnOE?4}iub?}EWZBYG~t7dFWE9EzW*$oF&D zi>rV_9_)2ikzQB!Fko?;LL(JHd`%ofXWpiv+Gj1o94 zlMZtJ_F^ESg{fGJ@2~}AG!=sF)%a7~+*|xG*ddgVA~92Wdukj|e}5LTE%W7SOJtqC zK4=G|p{-nfvQC`Y0Ts29xH1<-YmvjozBjV71tsS*`~J(*Q?9NIvs`a9D%s? zOzDK+jOLd8mpKG)9pagMZ!qS*bljjZPIbMILwyOq=1U?-{?>L<3n7w!gU(luT?r%3ZW!mQ7@I_%2CbZSjqU?HVa&R_oqa7A323MfQJAgX<|8Q-=k_jaPSR|mYiM&ZvcHZDuQK}rzxBjsg;gU zHwb${eY(}VWx>+8$!m@`?%t7bE6Wl4@pwbm-n7g`yWCl0qvc^}dEr&X4CxO8US);$ zwY_Pnm~iVsYAPCD5%t6#8`6>~9AN;hPrnZl7gQ`knMjuOkWxlAWyd(i;|mGW8q=W? zq7*}Mgx&1L!YZ&TJaiWdN|E)EacW)jLARp;gJv5b59LJC9GFY{VkpjZx>z(H%PpE7 zfsg0#i5DtOEC-@wpxPfUh~7X9C-q9FMtY?PCt<-UpU@Wyc=PXZhaxSXvJ@ z(oIIdSwt*;l}cN*v~zfDJx7q@bJQB{ZyJ=aI2T}pCOFCn6zq40`c$<=?8R`M^+6K& z@h`hc!#DX~q~+{GPj?wN#H!~{^Jco4=igVQ7&CvuJHXVSJ}>AT>pD#ml`74p0;%^-@>AQLqrW1USl4#zK?l_rTops>`gGM3Ki+iYF@p})SdKu{)k=t z+GmMw@`Q4-?$Rtr@belV6U{{3H-}tr8%mK%G$gaN{Cb^g*i=hzpr^av+`Snaxcq7k z5?&#V^xKPqu7WEuJCxRsP#;b}JziI*QcgTd3{@rYAjLLQFgsj@i!lB2Vlur~j*?lf zS!X7=kl&J}f>fe!5t_X`Jf_x+r#y>WO7lgW-rFV7`ur-C3qhNuXESv%U6l(u*VLm+ zG~NPSDzyW7o!w@`Y&BVm9bz?PqA+;Rkj+Yna(lB9bt)4lt!axyWBs@*~>>?__k!Af$T0AsBJSGSQ( z<$HZ($%M2PYPL1|J$aF5X&iYZp{+l6wze~JJGV1#qm!@W3BA9oB&kt;FTCbdl&RHh zxv5!F*Y2Wr#j4betR_9+zeqY!$&7lHBqjIhc~_PR-0ZM?d5wUtdM%~gIS~nCsh1Pj zv-c`EoSB_nSKh)QDEiapY;8G+WJ7%DfDc+^a5C;eT!xgMb}sq5__`&gcYyRGE#6E= zyG#YnSB9EHO#)gzmnc!R0quG8&q3j#12~lm(Otz9KTz*ow_`8VFWr*wp6|R4R%@H! zD1mpo-EsSJHE}Mtar{Q>_^mgJoKO0|ODS`nMYp@Asd&PIts4ID0_s)MVYafBQqJ77 z;0E0_I#(Y?e)soY@73^iuu7xng5o#ecvk$YRJAZw&^pIk(Wwkn`pd&~c9&sV*V7er zC2)b!b0{~fy+3XW3Q0=USEOm!0PagA1<#vHFb)mG!kYUU+f}d6m{7P}oYoURb01`= zdNo&69CO=3TI*+ZNqT%8d$=BCffny_r$y3F%2zDD?fUvu=JHz%1?uOfDBN6LjkjAxgy3g6jB)r!e`XUvb(Jo^Jy&inH%Na{O56v4%6N_n82*TyE z7L$56fSSkF30&(eR1LY`HG`igJCV( zEcR|+Uhfq%BbR_;sGb|`A?=N@9sF}&>ky-ZIxw#6NMW1;)oJ@GxwM{wYR#UVsK2RE z1`p(4W!-cl@^{@*vCriuFIY4hE3&&k8)Oii%_ax&-taQ=W2)yRqQo{$k zES`x*aCIJ5)#bfoNq_YBcE7}YIGoEoaLiL`(p>MM=U0OUEUJ*hzFS$|rw3 ze_v_t_gWrNQct|~#ATq+1m}2AX-wKwBl{=j*WO%`RZ*nt0zTFybg9sHyT(QJ9V_(} z=N*o3=)d>Q%e%X97q7rExw6<>p^2Y@+}s`ZH@B1pt9%67XHM*I`tI)1j=H7x1zD3) z@Pg3$w+-Glrp2VC%r)v5&OH+d_-Q&CLBPVo>3l*!Jtw&B?b$n5>2e3-wKYYpTBBZQnK*V(rBgt{^5Q^=e~zfTdQL=)1&6*E>S0=l4mFcyF#-$3gMkG zjGdw|ejiSd_yoFv8fovWy3=5N6)RP>vJPQAo%ESoERkna+Ce?uhj%|(JD zSOz-YI&(cVUAlDdcWeojkIj6)8TR)}dVp=vibn26_@G~$;~o^sxOAuN6)C$g?@xj@H&#ou z>A56wGx-UxuE$t>nI;vJOfW>;hTaqz_0Ys$0h^VAPNI3CiK5ABj`YV$x|Ls3C7c~@ z7y^glE~VyI?CA89zE9N$r+e-6%K(vp}4JB({uub8vS z^6Q;`|EPGq7!g{?K^H^Nn2ymDqf2R)&9=$(nuC&6u1%~?B$c3wQ{4*8ejgtk*d9)a zH0C(L8q|-|`qfZcDArw-!)!ghw)`U>+{Gwu;-dIFa-=xWnZL-^Cdv0Jdvu38kT___ zm&pg7Uxxv>gF*%q`w9cW(?8h%p*yepdw1B6uo-xzj*?y~Z>7n-?Ie)QUVyH47#{^;F&*c1mYd-jBvbuy94QgEfCrln4EHwlRk@GP|E z93=M#1awJTTx9HBMT^s0({QkR-Bb@fdWsLzYH`%B-+e3t5>W3+gvwfSx-HcoOz?Q_ zF)}Xrmm$ZNHI!P{@Y5s0_3P)-b}!*2(R-ge{XE52)awvnhYS6kh{La(c zk{qfA8<$k}1#@a&ISNrRrC}T43R%Fy1Z&JyR z&A&Mq*en9`eLDx-n9eJ#>{nJYxare)JhM%{v`j1N4|Zu<>LQ4T7R8Wbc)E$H+l8;$ zvQZT{M!+_plku`mT*`t@NKSiBJ*ktVmC52=hu23Hwq8Mzzv-HdD*qM=_blZdSXz6wW7X+q+|x!T z{UY$|9iw-wQN8zY9jw_vigY;g?#j@>%E6+uPNcTwv)U>#r&o_vt{WdcHH6ZJ$y^@7 z4GG|5eYAy5Sf{MxmAXU%7Yw6`C{L2GV!69H`f1U*L&ea_h=g&pjv4ld94So69;Xi& z5nD*dW#oKn2t&|c`eq2omItO42L?&$zEg>bNu&;wywSL?TU2HBZmjO`T9uo*m-_bE zZ07LmmG${NvAbW{HMA?^&;mm8_b>ALR`A9uMuv(8(5wZ8%!bU#c*GI?q;kJZo5QcV4RA9Md5jTzworURdbf+qd@HKc zYOLl;-YtbpEPoPF!5`dNBd=b1H~iDD zj{mEv8^3)rRxOpYKoN^+i9tdJYdcP|>}JyKJjZ z;z@{yctk2AA+$TqoK$lR)23~1+=b%+kJ&|j1RI``^DT{2_J;j{Hf8>X;QD3CT?|T> zh`6o8c^ppNzQlV<#gI7r&6u13KauAO%e-{~M){ImbPZ+9^~_z(rOj!zD)YVK z7Lv`$3~^LXzykv;SuO&6L%2>JnUb4(cDC_o7iTXB+*A~SEAv?okTVIieB%7?F@&Dk{`#vl7vGBc<9g@@p zJJso|cB&2uC4n}<*MZQNnqvwB92XdI5`~lqhsq+&qp5WoupVeMRf{Bnj+!}N3=^0~ zntFv+QA1}EDcmWx)u>ykxh)KY#$rW4vISrCrNidd##~|rnVMq*jSx!48XAJcVlr3b zp*`ti04j;14jvm}V{>7g%}j%+N0t?H>-BC{o)mGHH5WBVj3_mTHOMt;_iHA_@&%+* z3&f0z>4&>$@w+2ZpMRK;<{K-jQPh&YwDpS8a`)`Um!z_?}uo-x&RN{zKwhO zK>gG~xFtDXA+M+ma>f_rt(ml&rJ^eM+-}wyO7S)Ro!ZNCtxg98<=$~2C10hVZ`=-w zN-=xH;=#hS&$Uf)yt1%on;&FrE;ksGM7o5F+73jWL2ug28Ri=B4-Lt4!R@}9kpiY4 zV$kj72LxzntAW>PFWj9}7rx51Iqp{KB zmWg9IeQ!tx1WTaThUnDM$kh4=2hQXqGuKWTP6ntlCl8UiNJn?G4CO8KV!I}su3IFz zi_Gn>Z!veI%L(o#Xyj>_@1)in`y`{uz0kVCh@Qrz(~3S<*YLRgStp!8YgaQ6W8Ey* z(Pf|L(a1U>Z?5+FZ5+16E855*YT7S@8k^w@8wt20G7TDDYAf08y2bS_v=r1KU-iQU zBiDfgYPAen;!KxSH-|6OcrH|K%b4rJBqqR<40iRyc!BUvz*VclCSHo_K zP!6&q-1fE)IU?gmM6r{l_`rc2Z97Y5!Psu-dhF&?E0quEjWQf=GvjDdY{ThVx|{-M{)7#`8?O)3$&(nK%=~^=*Sa9nYQk?boTgtB zD0<0!KEAsdBH&0!ffDW9s3 z5hKKi1s8SQxK|E!^U4fVHu`XXql2ZCIMzxaj~SD}UIcf(ayW|98lvc#TBj4lROU`% z7PBCz-Z6rg{Lb$y=@Q*+9^F^mrTm_GUBxZiR`JLXyHs%Pl>~@#B`t}OEEmrN)&Le! zzwKdJT&8$9p<^PKltsArT7X82?#kWkX7fSlju&L-Z@Zv{t;bXGqpGk~yJC;*=VCGQ zZt}}XXPG-!p{~m)Q%0{Qk4x-`go^F>%Y^}UvgE!;f~1OvG4ZpyW-h2tU6pNfPJsrK ztM^0;f;?7tTX5(ENqM5-HU7i563mKn*M7sWRHTXx?~4m+LWgq|m5W}kwRvRMN-b4$7}~P#(<9H57S-sVu|UaAbMyU6Sao0@4!-bV#`^%u@ywOO z*i_x9nvg9G0bvWGdm|muMr?asr~~6%@#W4qMoYu8kkiuBmt7F_mpu9;Fcq zr89!+4Nj>IvbVKnQM+hUuC>-)qf6G!LkP3MvmE;>4Z#h90g7(xE<5l{T_O!xJxl^2 zHKHLog;z+5zC-KI^k1a}MuA@BuN`6KrV(aH8LGd1<8azfY@NXh(lh9B#9AuDwEoCQ z5lGrQLX*VbN)OGO-dq@sb@PsoYm1L=reG3|7cm?7D%)rHc@lCT1GbyoaXCX||7G^V zC_^9}?~F*_D#^< zzWdA4Nv(}<9oPId@c=8^LsWqGtF?HfE0vdCUrreZ9%Xtu*-u)LTquz`J--`oYD8eO zt+C-%)gyIU_wYL0nFG8)(4A{nuFrTa-V}N?Kxvrjj@7w7XYcR+1W&uQf872N=@?H%{P zsvTE5)GBCGVdb04a9}6W+9JMeg%cHd`&BB1<<=GKz#J%J%_VKa0zcA@Yq&ai11%yj zeO@)WfZ5)X9V}$F=CZSfxjBx;Rj0{wwa>h{7N<-87IC;!rsoB|&hm#_P)B!l#>NQ# zW&D~X@=`0g^j8fZ_dU(w4CXS2Z`MR^&Ui=bS40Ep_|8qXoCDYmpg8R3O`{*bBTDI+zONk><8?{JOBj(VrmP;u3=8K+$L1<)Uph47Q!-d;peJQx?*8qaJ90G2)DUOuYLm{;>nH z+!0=2E&G@Uj>-GnxD9XwDSn|{+HkcC;C21CcGk4+)3*_^Aej_XIkNh1La$Z`uu7K* zKEdN3=cFIw`fPBsN9+za;j~SKJBNiR9<8aG_AP=U+ND+c?c1aWfcTUop`sKYVlqiTWZynC=Q1>O>?^u`X_loi z1_PGV7rR!X7E>X{!fOS{eQu% ze{dh^f)N+$iY38@Y-jh@}2y~8qi!+3IRaeJUxLdw2;z0B#W<5r?$&O$?T&k$>B zs&}82m+ji}hQBO#KP!gD#2!^r_kp%wnY@^VZNF_?wbV;uI3_>S$wB+`@Y{^d=?Q~w z9Ld#i5~d<*_bVQjsFc)MUgj9}dDdbovf{==ZH@cch+cV{mFdYNl#!O|hR%>mC5#d7 zFSaB=@f1hu!MZ&O@#gwceIpx{_^6o2i&|PsE$_-NTHI@hZ7ynjulZl|lMP}T`m_ng zY9WIrX-X&-e0ltH_)wl9Q#>0`MJR-h@1lH1INsIuX2&Q(^{qY8C=}5(e|I?d zrgN_9_yU~oBOZI~7$a7@-Q(8JUO{8S(V=P{7_hCj@g?{&ovc^Tu0*!-vsquBqOutr z7+xj+B>onl_a02B!ELr}|ApRTvzOq%+@q&i^M7@o{|cQzn3X4f;vYnffV7<4e-JhQ z4@nxvKj;2KNSa^M>i?6Z`85E3$5j}g=KlYG8ubs7=D%3;za?lGpIrENg68jV&o2x9 zsnUNZX#SxLWXM?RLC6^<#=ny@5MqUv8A7Q5*+9&YwE&oy{-2REf3COiFLDON#{4@u z^B26N0Z|fy$1p)?CM^JDR?EM3S^vGu{)?Ysg)lUKe6;{9j1c7JufxA@wE(O@NDX$T zUm(uYC0QY>F=zomY)_SdOux7s78ZtITUHIVPjxqcs6{J>ve*&hS!-%D1|3-UuM(HrOifKR@p=V$!C7K1#{|19>K*MIBh z|8DoU*TKJqzvD^L5XS1y0VNHAl>X?x^wJP({%*prVt<+Yhw^_dzwvM6PQ=FE3Ie75 z33IX1u>fcxE`@BKV5z?*H8C+mdhY))rHM&#aGmk}$vWdSlhQcL`@zjgm}*2!`=+L} zre`vdFev|gdi~P<|IhmUc7y(0_2hr$zbEhg_5HUGflN&QvlFeNK*%rNAqu-^`n>Wm z41FfZX;i_FA)IpCh#~k4t+2Z7ep`4cb)I|I0Kn4{Iv*H=62Wbp=>V_hdlH4-7rfm| zX;#1)Z;X_ym7kOcYwn4VHdJY9#$jWpV$@(QR3CoqOo%@=w}Gs9mH;vak@#8g2WM+o!xYc%{hvySQa z33Gyw)l8nyN(yN`u&t#H*wRcN;KW1+WT0cG0hofpwhkQh^j7~mM`vSiLWw~C-rmO0 z(EzeK%J0=|4UGZ%dIlDdX8yVar0A~(%xtWMo>r8h5aM8DU}R-rWncj^16i1X)C}z8 z3=HIyzYRebdn026$hs~-1crZo0IV!5kVlF!;9s&Qfb!`Bu>Mm9d0s=F)qj@(pH`Xq zTRBL(|Bx}V{If12ANE4HQOGOeZ*`g2S^r@N z8$0BM^0#uVAf~^|AT%n=-+cvysP|79%Rl@AWMO-vXrDg+@(TkS=n4A$4;he^9r9B8 zn~ddYd7!_^*g&A){0z3&gYc~OzgAOHFmp44^gjr;Y-95@bbgV>zgXs9L+95IBL}da VJ@{8w1+oJnFI!SlVObG`{{ud%X-fbA diff --git a/outputs/peak_verification/peak_verification_n18.pdf b/outputs/peak_verification/peak_verification_n18.pdf deleted file mode 100644 index 65508e3896fa953df7f28f51b6af8763ddb62dd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18916 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 U<=0dNa)E#x2$YoK3K9ta2kOXuKmY&$ diff --git a/outputs/peak_verification/peak_verification_n20.pdf b/outputs/peak_verification/peak_verification_n20.pdf deleted file mode 100644 index f5f7533163714c351631948e9c38f9ab3ed0fcf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18754 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

kYL{jpm5U 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 O)I(HiYB2?I)c*sW*| None: + errors = [] + manifest = json.loads((ROOT / 'validation/evidence_sha256.json').read_text()) + for name, expected in manifest['files'].items(): + path = ROOT / name + if not path.is_file() or hashlib.sha256(path.read_bytes()).hexdigest() != expected: + errors.append(f'released evidence changed or missing: {name}') + files = [p for p in ROOT.rglob('*') if p.is_file() + and not any(part in SKIP or part.endswith('.egg-info') for part in p.relative_to(ROOT).parts)] + for path in files: + rel = path.relative_to(ROOT) + if path.suffix.lower() in FORBIDDEN: + errors.append(f'unsupported document/build artifact: {rel}') + if path.suffix == '.txt' and path.name not in {'requirements.txt', 'requirements-tested.txt'}: + errors.append(f'narrative text should be Markdown: {rel}') + if path.suffix != '.md': + continue + content = path.read_text() + if re.search(r'\\(?:begin|end|frac|mathrm|mathbb|gamma|lambda)\b|\\[\[\]()]|\$|```math\b', content): + errors.append(f'use plain-text or Unicode mathematics in Markdown: {rel}') + # This repository uses inline links without spaces or optional titles. + for target in re.findall(r'!?\[[^\]]*\]\(([^)]+)\)', content): + url = urlsplit(target) + if url.scheme or not url.path: + continue + if not (path.parent / unquote(url.path)).exists(): + errors.append(f'broken local link in {rel}: {target}') + if errors: + print('\n'.join(errors), file=sys.stderr) + raise SystemExit(1) + docs = sum(p.suffix == '.md' for p in files) + print(f'PASS: {len(manifest["files"])} evidence checksums; {docs} Markdown documents; local link paths; no TeX/PDF artifacts.') + + +if __name__ == '__main__': + main() diff --git a/scripts/fig1_concentration.py b/scripts/fig1_concentration.py index a0ab52f..da225ca 100644 --- a/scripts/fig1_concentration.py +++ b/scripts/fig1_concentration.py @@ -67,7 +67,7 @@ def main() -> None: parser.add_argument("--zoom-samples", type=int, default=500) parser.add_argument("--zoom-stop", type=int, default=1600) parser.add_argument("--seed", type=int, default=20250604) - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig1") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig1") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) N = 1 << args.n @@ -84,7 +84,7 @@ def main() -> None: write_rows(args.outdir / "fig1_zoom_summary.csv", zoom_summary, fields) write_rows(args.outdir / "fig1_raw.csv", raw, list(raw[0].keys())) write_rows(args.outdir / "fig1_zoom_raw.csv", zoom_raw, list(zoom_raw[0].keys())) - plot_fig1(args.outdir, args.outdir / "fig1_concentration.pdf", n=args.n) + plot_fig1(args.outdir, args.outdir / "fig1_concentration.png", n=args.n) if __name__ == "__main__": diff --git a/scripts/fig2_peak_scaling.py b/scripts/fig2_peak_scaling.py index bacd4c7..cd358e6 100644 --- a/scripts/fig2_peak_scaling.py +++ b/scripts/fig2_peak_scaling.py @@ -36,7 +36,7 @@ def fit_line(x: np.ndarray, y: np.ndarray) -> dict[str, float]: def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--table", type=Path, default=ROOT / "data" / "table_i_peaks.csv") - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig2") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig2") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) @@ -63,7 +63,7 @@ def main() -> None: {"quantity": "S_n", **fit_line(n, S_n)}, ] write_rows(args.outdir / "fig2_linear_fit_summary.csv", fits, fits[0].keys()) - plot_fig2(args.outdir, args.outdir / "fig2_peak_scaling.pdf", write_fit_summary=False) + plot_fig2(args.outdir, args.outdir / "fig2_peak_scaling.png", write_fit_summary=False) if __name__ == "__main__": diff --git a/scripts/fig3_spectral.py b/scripts/fig3_spectral.py index 467aa6d..fb19fe8 100644 --- a/scripts/fig3_spectral.py +++ b/scripts/fig3_spectral.py @@ -28,7 +28,7 @@ def main() -> None: parser.add_argument("--m", type=int, default=None) parser.add_argument("--seed", type=int, default=20250604) parser.add_argument("--bins", type=int, default=500) - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig3") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig3") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) @@ -79,7 +79,7 @@ def main() -> None: "bulk_max", ], ) - plot_fig3(args.outdir, args.outdir / "fig3_spectral_bulk.pdf", bins=args.bins) + plot_fig3(args.outdir, args.outdir / "fig3_spectral_bulk.png", bins=args.bins) if __name__ == "__main__": diff --git a/scripts/fig4_approximation.py b/scripts/fig4_approximation.py index 64a0825..e30053e 100644 --- a/scripts/fig4_approximation.py +++ b/scripts/fig4_approximation.py @@ -53,7 +53,7 @@ def main() -> None: parser.add_argument("--zoom-points", type=int, default=100) parser.add_argument("--zoom-samples", type=int, default=500) parser.add_argument("--seed", type=int, default=20250604) - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig4") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig4") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) N = 1 << args.n @@ -67,7 +67,7 @@ def main() -> None: ) write_rows(args.outdir / "fig4_summary.csv", rows, rows[0].keys()) write_rows(args.outdir / "fig4_zoom_summary.csv", zoom_rows, zoom_rows[0].keys()) - plot_fig4(args.outdir, args.outdir / "fig4_approximation.pdf", n=args.n) + plot_fig4(args.outdir, args.outdir / "fig4_approximation.png", n=args.n) if __name__ == "__main__": diff --git a/scripts/fig5_qft_residue_controls.py b/scripts/fig5_qft_residue_controls.py index 8bd84df..de57dd9 100644 --- a/scripts/fig5_qft_residue_controls.py +++ b/scripts/fig5_qft_residue_controls.py @@ -32,7 +32,7 @@ def values(rows: list[dict[str, str]], key: str) -> np.ndarray: def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--data-dir", type=Path, default=ROOT / "data") - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig5") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "figures" / "fig5") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) @@ -40,6 +40,14 @@ def main() -> None: unions = read_rows(args.data_dir / "fig5_almost_prime_unions.csv") controls = read_rows(args.data_dir / "residue_matched_summary.csv") + largest_support = int(max(values(baseline, "m"))) + n = largest_support.bit_length() - 1 + if 1 << n != largest_support: + raise ValueError("baseline must include the full-support endpoint to infer n") + control_n = {int(row["n"]) for row in controls} + if control_n != {n}: + raise ValueError(f"Figure 5 baseline n={n} disagrees with controls n={control_n}") + apply_journal_style() fig, (ax, ax2) = plt.subplots( 1, 2, figsize=(7.25, 3.35), gridspec_kw={"width_ratios": [1.35, 1]} @@ -60,8 +68,8 @@ def main() -> None: ax.plot(union_m, values(unions, "qft_entropy"), "x", color=COOL_PALETTE[5], markersize=4.8, markeredgewidth=1.0, label=r"QFT $U_{N,k}$") ax.set_xlabel(r"support size $M$") ax.set_ylabel("entropy (bits)") - ax.set_xlim(0, 2**14) - ax.set_ylim(0, 7) + ax.set_xlim(0, 1 << n) + ax.set_ylim(0, n / 2) ax.legend(frameon=False, loc="lower center", bbox_to_anchor=(0.5, -0.42), ncol=2, columnspacing=0.9, handlelength=1.8) ax.text(0.02, 0.96, "(a)", transform=ax.transAxes, ha="left", va="top", fontweight="bold") @@ -83,7 +91,7 @@ def main() -> None: ax2.set_ylabel(r"residual deficit $\Delta_t$ (bits)") ax2.set_xlabel("constraint retained in null ensemble", labelpad=2) ax2.set_xlim(-0.5, 3.35) - ax2.set_ylim(0, 1.62) + ax2.margins(y=0.10) style_legend = [ Line2D([0], [0], color="0.2", marker="o", linestyle="-", markersize=4, label="computational basis"), Line2D([0], [0], color="0.2", marker="o", markerfacecolor="white", linestyle="--", markersize=4, label="after QFT"), @@ -91,7 +99,7 @@ def main() -> None: ax2.legend(handles=style_legend, frameon=False, loc="upper right", handlelength=2.0) ax2.text(0.02, 0.96, "(b)", transform=ax2.transAxes, ha="left", va="top", fontweight="bold") fig.subplots_adjust(left=0.085, right=0.99, top=0.97, bottom=0.26, wspace=0.32) - save_figure(fig, args.outdir / "fig5_qft_residue_controls.pdf") + save_figure(fig, args.outdir / "fig5_qft_residue_controls.png") if __name__ == "__main__": diff --git a/scripts/fig6_renyi.py b/scripts/fig6_renyi.py index 1637079..1a13863 100644 --- a/scripts/fig6_renyi.py +++ b/scripts/fig6_renyi.py @@ -48,7 +48,7 @@ def main() -> None: parser.add_argument("--zoom-points", type=int, default=100) parser.add_argument("--zoom-samples", type=int, default=1000) parser.add_argument("--seed", type=int, default=20250604) - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig6") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig6") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) N = 1 << args.n @@ -62,7 +62,7 @@ def main() -> None: ) write_rows(args.outdir / "fig6_renyi_summary.csv", rows, rows[0].keys()) write_rows(args.outdir / "fig6_renyi_zoom_summary.csv", zoom, zoom[0].keys()) - plot_fig6(args.outdir, args.outdir / "fig6_renyi.pdf", n=args.n) + plot_fig6(args.outdir, args.outdir / "fig6_renyi.png", n=args.n) if __name__ == "__main__": diff --git a/scripts/fig7_partitions.py b/scripts/fig7_partitions.py index 5e9f414..8b00fc8 100644 --- a/scripts/fig7_partitions.py +++ b/scripts/fig7_partitions.py @@ -27,7 +27,7 @@ def main() -> None: parser.add_argument("--samples", type=int, default=1000) parser.add_argument("--seed", type=int, default=20250604) parser.add_argument("--bins", type=int, default=100) - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "fig7") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig7") args = parser.parse_args() args.outdir.mkdir(parents=True, exist_ok=True) m = args.m if args.m is not None else PEAK_M[args.n] @@ -75,7 +75,7 @@ def main() -> None: }, ] write_rows(args.outdir / "fig7_partition_summary.csv", summary_rows, summary_rows[0].keys()) - plot_fig7(args.outdir, args.outdir / "fig7_partitions.pdf", n=args.n, bins=args.bins) + plot_fig7(args.outdir, args.outdir / "fig7_partitions.png", n=args.n, bins=args.bins) if __name__ == "__main__": diff --git a/scripts/final_scientific_validation.py b/scripts/final_scientific_validation.py index 5d2eab9..c7eb6e3 100644 --- a/scripts/final_scientific_validation.py +++ b/scripts/final_scientific_validation.py @@ -1,251 +1,216 @@ #!/usr/bin/env python3 -"""Independent checks for the final subset-state manuscript candidate.""" +"""Validate exact small-system mathematics and consistency of retained CSV evidence. + +Prints Markdown without changing the repository. This check is not a peak-search +rerun, an asymptotic theorem, a novelty assessment, or a publication certificate. +""" from __future__ import annotations -import csv +import argparse import math -from collections import defaultdict from pathlib import Path +import sys import numpy as np -from scipy.special import digamma ROOT = Path(__file__).resolve().parents[1] - - -def entropy_bits(rho: np.ndarray, tol: float = 1e-14) -> float: - vals = np.linalg.eigvalsh(rho).real - vals = vals[vals > tol] - vals = vals / vals.sum() - return float(-np.sum(vals * np.log2(vals))) - - -def h_shannon(probs: np.ndarray) -> float: - p = probs[probs > 0] - return float(-np.sum(p * np.log2(p))) if p.size else 0.0 - - -def exact_mean_rho(n: int, M: int) -> np.ndarray: - d = 1 << (n // 2) - N = 1 << n - beta = (M - 1) / (d * (N - 1)) - return (1 / d - beta) * np.eye(d) + beta * np.ones((d, d)) - - -def exact_avg_purity(n: int, M: int) -> float: - d = 1 << (n // 2) - N = 1 << n - return ( - 1 / M - + 2 * (d - 1) * (M - 1) / (M * (N - 1)) - + (d - 1) ** 2 * (M - 1) * (M - 2) * (M - 3) - / (M * (N - 1) * (N - 2) * (N - 3)) - ) - - -def exhaustive_n4_checks() -> dict[str, float]: - n = 4 - N = 1 << n - d = 1 << (n // 2) - m = n // 2 - rho_sum = np.zeros((N + 1, d, d), dtype=float) - purity_sum = np.zeros(N + 1, dtype=float) - counts = np.zeros(N + 1, dtype=np.int64) - max_residue_violation = {1: -math.inf, 2: -math.inf} - max_entropy_routine_diff = 0.0 - - labels = np.arange(N, dtype=np.uint32) - batch_size = 4096 - for lo in range(1, 1 << N, batch_size): - hi = min(1 << N, lo + batch_size) - masks = np.arange(lo, hi, dtype=np.uint32) - bits = ((masks[:, None] >> labels[None, :]) & 1).astype(float) - Ms = bits.sum(axis=1).astype(np.int64) - X = bits.reshape(-1, d, d) - rho = np.einsum('bai,baj->bij', X, X) / Ms[:, None, None] - evals = np.linalg.eigvalsh(rho).real - positive = np.where(evals > 1e-14, evals, 1.0) - entropy = -np.sum(np.where(evals > 1e-14, evals * np.log2(positive), 0.0), axis=1) - if lo == 1: - entropy_direct = np.asarray([entropy_bits(r) for r in rho[:128]]) - max_entropy_routine_diff = max( - max_entropy_routine_diff, - float(np.max(np.abs(entropy[:128] - entropy_direct))), - ) - purity = np.sum(evals * evals, axis=1) - - np.add.at(rho_sum, Ms, rho) - purity_sum += np.bincount(Ms, weights=purity, minlength=N + 1) - counts += np.bincount(Ms, minlength=N + 1) - - for t in (1, 2): - modulus = 1 << t - residue_counts = np.stack( - [bits[:, (labels % modulus) == r].sum(axis=1) for r in range(modulus)], - axis=1, - ) - probs = residue_counts / Ms[:, None] - p_safe = np.where(probs > 0, probs, 1.0) - H = -np.sum(np.where(probs > 0, probs * np.log2(p_safe), 0.0), axis=1) - bound = m - t + H - max_residue_violation[t] = max( - max_residue_violation[t], - float(np.max(entropy - bound)), - ) - - max_mean_rho_error = 0.0 - max_purity_error = 0.0 - for M in range(1, N + 1): - empirical_rho = rho_sum[M] / counts[M] - empirical_purity = purity_sum[M] / counts[M] - max_mean_rho_error = max( - max_mean_rho_error, - float(np.max(np.abs(empirical_rho - exact_mean_rho(n, M)))), - ) - max_purity_error = max( - max_purity_error, - abs(empirical_purity - exact_avg_purity(n, M)), - ) - - return { - "supports_enumerated": float((1 << N) - 1), - "max_mean_rho_error": max_mean_rho_error, - "max_average_purity_error": max_purity_error, - "max_residue_bound_violation_t1": max_residue_violation[1], - "max_residue_bound_violation_t2": max_residue_violation[2], - "max_entropy_routine_difference": max_entropy_routine_diff, - } - -def page_entropy(n: int) -> float: - d = 1 << (n // 2) - return float((digamma(d * d + 1) - digamma(d + 1) - (d - 1) / (2 * d)) / math.log(2)) - - -def table_fit_checks() -> dict[str, float]: - rows = np.asarray( - [ - (10, 107, 4.072), - (12, 276, 5.108), - (14, 716, 6.143), - (16, 1873, 7.176), - (18, 4934, 8.196), - (20, 13091, 9.215), - (22, 34771, 10.231), - (24, 93018, 11.242), - (26, 250660, 12.251), - (28, 672556, 13.258), - (30, 1836685, 14.263), - ], - dtype=float, - ) - n, M, S = rows.T - slope_S, intercept_S = np.polyfit(n, S, 1) - slope_M, intercept_M = np.polyfit(n, np.log2(M), 1) - page = np.asarray([page_entropy(int(x)) for x in n]) - gaps = page - S - fractions = M / np.power(2.0, n) - assert np.all(np.diff(gaps) < 0), "Page gaps are not strictly decreasing" - assert np.all(np.diff(fractions) < 0), "support fractions are not strictly decreasing" - return { - "S_slope": float(slope_S), - "S_intercept": float(intercept_S), - "log2M_slope": float(slope_M), - "log2M_intercept": float(intercept_M), - "page_gap_n10": float(gaps[0]), - "page_gap_n30": float(gaps[-1]), - "support_fraction_n10": float(fractions[0]), - "support_fraction_n30": float(fractions[-1]), - } - - -def dense_ansatz_equivalence() -> float: - n = 14 - N = 1 << n +sys.path.insert(0, str(ROOT)) + +from subset_states import core, tables +from scripts.fig2_peak_scaling import fit_line +from scripts.validate_residue_results import ( + close, finite, markdown_report, read_rows, require, residue_checks, write_report, +) + + +def exhaustive_checks(n_values: tuple[int, ...] = (2, 4)) -> dict[str, float | int]: + """Independently enumerate supports and compare the production implementations.""" + errors = {name: 0.0 for name in ( + "coefficient_matrix", "entropy", "residue_ceiling", "mean_spectrum", "average_purity", + "diagonal_entropy", "entropy_lower_bound", "qft_amplitude", "qft_entropy", + )} + supports_enumerated = 0 + max_bound_violation = 0.0 + for n in n_values: + require(n in (2, 4), "exhaustive checks are deliberately limited to n=2 and n=4") + N, d = 1 << n, 1 << (n // 2) + rho_sum = np.zeros((N + 1, d, d)) + purity_sum = np.zeros(N + 1) + diagonal_sum = np.zeros(N + 1) + entropy_sum = np.zeros(N + 1) + counts = np.zeros(N + 1, dtype=int) + labels = np.arange(N, dtype=np.uint32) + # Batch eigensolvers provide an independent route from the production SVD. + for lo in range(1, 1 << N, 4096): + masks = np.arange(lo, min(1 << N, lo + 4096), dtype=np.uint32) + bits = ((masks[:, None] >> labels[None, :]) & 1).astype(float) + sizes = bits.sum(axis=1).astype(int) + matrices = bits.reshape(-1, d, d) / np.sqrt(sizes[:, None, None]) + rho = np.einsum("bai,baj->bij", matrices, matrices) + eigenvalues = np.linalg.eigvalsh(rho) + safe = np.where(eigenvalues > 1e-14, eigenvalues, 1.0) + entropies = -np.sum(np.where(eigenvalues > 1e-14, eigenvalues * np.log2(safe), 0), axis=1) + diagonal = np.diagonal(rho, axis1=1, axis2=2) + safe_diag = np.where(diagonal > 0, diagonal, 1.0) + diagonal_entropies = -np.sum(diagonal * np.log2(safe_diag), axis=1) + np.add.at(rho_sum, sizes, rho) + purity_sum += np.bincount(sizes, weights=np.sum(rho * rho, axis=(1, 2)), minlength=N + 1) + diagonal_sum += np.bincount(sizes, weights=diagonal_entropies, minlength=N + 1) + entropy_sum += np.bincount(sizes, weights=entropies, minlength=N + 1) + counts += np.bincount(sizes, minlength=N + 1) + for index, size in enumerate(sizes): + support = np.flatnonzero(bits[index]) + production_matrix = core.matrix_from_support(n, support) + matrix_error = float(np.max(np.abs(production_matrix - matrices[index]))) + require(math.isfinite(matrix_error), "non-finite production coefficient matrix") + errors["coefficient_matrix"] = max(errors["coefficient_matrix"], matrix_error) + errors["entropy"] = max(errors["entropy"], close( + core.entropy_from_support(n, support), float(entropies[index]), "production entropy")) + for t in range(n // 2 + 1): + population = np.bincount(support % (1 << t), minlength=1 << t) + probs = population[population > 0] / size + bound = n / 2 - t - float(np.sum(probs * np.log2(probs))) + errors["residue_ceiling"] = max(errors["residue_ceiling"], close( + core.residue_class_entropy_ceiling(n, support, t), bound, "production residue ceiling")) + max_bound_violation = max(max_bound_violation, float(entropies[index]) - bound) + if n == 2: + # Explicit DFT checks sign and normalization, independently of FFT. + phases = np.exp(2j * np.pi * np.outer(np.arange(N), support) / N) + direct_state = phases.sum(axis=1) / math.sqrt(N * size) + actual_state = core.qft_state_from_support(n, support) + amplitude_error = float(np.max(np.abs(actual_state - direct_state))) + require(math.isfinite(amplitude_error), "non-finite production QFT") + errors["qft_amplitude"] = max(errors["qft_amplitude"], amplitude_error) + c = direct_state.reshape(d, d) + eig = np.linalg.eigvalsh(c.conj().T @ c) + positive = eig[eig > 1e-14] + direct_entropy = float(-np.sum(positive * np.log2(positive))) + errors["qft_entropy"] = max(errors["qft_entropy"], close( + core.entropy_from_state_vector(n, actual_state), direct_entropy, "production QFT entropy")) + supports_enumerated += len(masks) + for size in range(1, N + 1): + require(counts[size] == math.comb(N, size), f"n={n}, M={size}: enumeration count") + mean_rho = rho_sum[size] / counts[size] + uniform, orthogonal = core.fixed_cardinality_mean_spectrum(n, size) + predicted_rho = orthogonal * np.eye(d) + (uniform - orthogonal) * np.ones((d, d)) / d + error = float(np.max(np.abs(predicted_rho - mean_rho))) + require(math.isfinite(error), "non-finite production mean spectrum") + errors["mean_spectrum"] = max(errors["mean_spectrum"], error) + close(core.mean_matrix_uniform_eigenvalue(n, size), uniform, "production uniform eigenvalue") + mean_purity = float(purity_sum[size] / counts[size]) + errors["average_purity"] = max(errors["average_purity"], close( + core.fixed_cardinality_average_purity(n, size), mean_purity, "production average purity")) + errors["diagonal_entropy"] = max(errors["diagonal_entropy"], close( + core.hypergeometric_occupancy_approximation(n, size), float(diagonal_sum[size] / counts[size]), + "production diagonal entropy")) + lower = core.average_entropy_lower_bound_from_purity(n, size) + errors["entropy_lower_bound"] = max(errors["entropy_lower_bound"], close( + lower, -math.log2(mean_purity), "production purity entropy bound")) + max_bound_violation = max(max_bound_violation, lower - float(entropy_sum[size] / counts[size])) + for name, error in errors.items(): + require(error < 5e-12, f"{name} maximum error {error} exceeds tolerance") + require(max_bound_violation < 5e-12, f"entropy bound violated by {max_bound_violation}") + return {"supports_enumerated": supports_enumerated, + **{f"max_{name}_error": value for name, value in errors.items()}, + "max_entropy_bound_violation": max_bound_violation} + + +def independent_page_entropy(n: int) -> float: + """Page expression using harmonic sums/expansion, independently of digamma.""" d = 1 << (n // 2) - max_diff = 0.0 - for M in range(1, N): - lam = 1 / d + (d - 1) * (M - 1) / (d * (N - 1)) - old = ( - (1 - lam) * (math.log(d) - math.log(1 - lam) - 0.5) - - lam * math.log(lam) - ) / math.log(2) - h2 = -lam * math.log2(lam) - (1 - lam) * math.log2(1 - lam) - new = h2 + (1 - lam) * (math.log2(d) - 1 / (2 * math.log(2))) - max_diff = max(max_diff, abs(old - new)) - return max_diff - - -def residue_checks() -> dict[str, float]: - path = ROOT / "data" / "residue_matched_summary.csv" - with path.open(newline="") as f: - rows = list(csv.DictReader(f)) - - by_key = {(int(r["k"]), int(r["matched_low_bits"])): r for r in rows} - strongest = [(1, 1), (2, 2), (3, 3)] - expected = { - (1, 1): (0.124881, 0.114442, 0.885607, 0.894136), - (2, 2): (0.230201, 0.212232, 0.841422, 0.851975), - (3, 3): (0.111500, 0.103991, 0.910577, 0.916102), - } - max_claim_error = 0.0 - for key in strongest: - r = by_key[key] - vals = ( - float(r["position_residual_deficit"]), - float(r["fourier_residual_deficit"]), - float(r["cardinality_deficit_reduction_position"]), - float(r["cardinality_deficit_reduction_fourier"]), - ) - max_claim_error = max(max_claim_error, max(abs(a - b) for a, b in zip(vals, expected[key]))) - assert int(r["position_null_count_at_or_below_structured"]) == 0 - assert int(r["fourier_null_count_at_or_below_structured"]) == 0 - - prime = by_key[(1, 1)] - forced_gap = float(prime["forced_gap_from_balanced_max_bits"]) - ceiling = float(prime["entropy_ceiling_bits"]) - return { - "max_residue_claim_rounding_error": max_claim_error, - "prime_parity_ceiling_bits": ceiling, - "prime_forced_gap_bits": forced_gap, - "all_six_strongest_controls_below_all_1000_nulls": 1.0, - } - - -def main() -> None: - results = { - "exhaustive_n4": exhaustive_n4_checks(), - "table_fits": table_fit_checks(), - "dense_ansatz": {"max_old_new_difference": dense_ansatz_equivalence()}, - "residue_controls": residue_checks(), - } - - lines = ["FINAL SCIENTIFIC VALIDATION", "=" * 29, ""] - for section, values in results.items(): - lines.append(section) - lines.append("-" * len(section)) - for key, value in values.items(): - lines.append(f"{key}: {value:.16g}") - lines.append("") - - # Hard acceptance thresholds. - ex = results["exhaustive_n4"] - assert ex["max_mean_rho_error"] < 5e-13 - assert ex["max_average_purity_error"] < 5e-13 - assert ex["max_residue_bound_violation_t1"] < 5e-13 - assert ex["max_residue_bound_violation_t2"] < 5e-13 - assert results["dense_ansatz"]["max_old_new_difference"] < 5e-13 - tf = results["table_fits"] - assert abs(tf["S_slope"] - 0.5093) < 1e-12 - assert abs(tf["S_intercept"] + 0.9900909090909096) < 1e-12 - assert abs(tf["log2M_slope"] - 0.7035409513877945) < 1e-12 - assert abs(tf["log2M_intercept"] + 0.35773436814817394) < 1e-12 - - lines.append("STATUS: PASS") - out = ROOT / "validation" / "FINAL_SCIENTIFIC_VALIDATION.txt" - out.parent.mkdir(parents=True, exist_ok=True) - out.write_text("\n".join(lines) + "\n") - print(out.read_text()) + def harmonic(number: int) -> float: + if number < 32: + return math.fsum(1 / k for k in range(1, number + 1)) + x = 1.0 / number + return (math.log(number) + 0.5772156649015328606 + x / 2 - x**2 / 12 + + x**4 / 120 - x**6 / 252 + x**8 / 240 - x**10 / 132) + return (harmonic(d * d) - harmonic(d) - (d - 1) / (2 * d)) / math.log(2) + + +def table_fit_checks(root: Path = ROOT) -> dict[str, float | int]: + rows = read_rows(root / "data/table_i_peaks.csv", {"n", "M_n", "S_n"}) + require([int(row["n"]) for row in rows] == list(range(10, 31, 2)), "Table I n grid is incomplete or duplicated") + table = np.asarray([(int(row["n"]), int(row["M_n"]), finite(row, "S_n")) for row in rows], dtype=float) + require(np.array_equal(table, np.asarray([[r["n"], r["M_n"], r["S_n"]] + for r in tables.read_table_i(root / "data/table_i_peaks.csv")])), "production Table I parser disagrees") + require(np.array_equal(table, tables.table_i_array()), "Table I CSV and production defaults disagree") + n, sizes, entropies = table.T + require(np.all((sizes >= 1) & (sizes <= 2**n)), "Table I support sizes out of range") + require(np.all((entropies >= 0) & (entropies <= n / 2)), "Table I entropy out of range") + page = np.asarray([independent_page_entropy(int(value)) for value in n]) + for ni, value in zip(n, page): + close(core.exact_page_entropy_bits(int(ni)), float(value), "production Page entropy") + derived = read_rows(root / "outputs/fig2/fig2_table_with_page.csv", { + "n", "M_n", "log2_M_n", "S_n", "Page_exact_bits", "Page_minus_S_n"}) + require(len(derived) == len(rows), "derived Table I row count mismatch") + max_error = 0.0 + for row, ni, size, entropy, page_value in zip(derived, n, sizes, entropies, page): + for field, value in {"n": ni, "M_n": size, "log2_M_n": math.log2(size), "S_n": entropy, + "Page_exact_bits": page_value, "Page_minus_S_n": page_value - entropy}.items(): + max_error = max(max_error, close(finite(row, field), float(value), f"derived Table I {field}")) + fit_fields = {"slope", "intercept", "r_value", "r_squared", "p_value", "slope_stderr", "intercept_stderr", "residual_std"} + fits = read_rows(root / "outputs/fig2/fig2_linear_fit_summary.csv", {"quantity"} | fit_fields) + by_quantity = {row["quantity"]: row for row in fits} + require(len(fits) == 2 and set(by_quantity) == {"log2_M_n", "S_n"}, "fit quantities missing or duplicated") + results: dict[str, float | int] = {"table_rows_checked": len(rows)} + for quantity, values in (("log2_M_n", np.log2(sizes)), ("S_n", entropies)): + slope, intercept = np.polyfit(n, values, 1) + production = fit_line(n, values) + close(production["slope"], float(slope), f"independent {quantity} slope") + close(production["intercept"], float(intercept), f"independent {quantity} intercept") + for field in fit_fields: + # Relative tolerance is needed for tiny p-values; do not accept zero in their place. + expected = production[field] + max_error = max(max_error, close(finite(by_quantity[quantity], field), expected, + f"stored {quantity} fit {field}", atol=max(abs(expected) * 1e-8, 1e-30))) + results[f"{quantity}_slope"] = float(slope) + results[f"{quantity}_intercept"] = float(intercept) + gaps = page - entropies + require(np.all(np.diff(gaps) < 0), "recorded Page gaps are not decreasing") + require(np.all(np.diff(sizes / 2**n) < 0), "recorded support fractions are not decreasing") + results["max_derived_table_or_fit_error"] = max_error + return results + + +def dense_ansatz_checks() -> dict[str, float | int]: + max_error, tested = 0.0, 0 + for n in (2, 4, 8, 14): + N, d = 1 << n, 1 << (n // 2) + for size in range(1, N + 1): + lam = (N - size + d * (size - 1)) / (d * (N - 1)) + if size == N: + independent = 0.0 + else: + h2 = -lam * math.log2(lam) - (1 - lam) * math.log2(1 - lam) + independent = h2 + (1 - lam) * (math.log2(d) - 1 / (2 * math.log(2))) + max_error = max(max_error, close(core.dense_bulk_approximation(n, size), independent, + "production dense-bulk ansatz", atol=5e-13)) + tested += 1 + return {"parameter_pairs_checked": tested, "max_formula_error": max_error} + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output", type=Path, help="save the report to a new .md file") + args = parser.parse_args() + try: + # Check files first so malformed or stale evidence fails promptly. + results = {"Retained Table I consistency": table_fit_checks(), + "Exhaustive small systems": exhaustive_checks(), + "Dense-bulk formula implementation": dense_ansatz_checks(), + "Residue-control evidence": residue_checks()} + report = markdown_report("Scientific sanity checks", results, + "Exhaustive checks cover every nonempty support at n=2 and n=4 against production routines. " + "Table I checks read the actual retained CSV and its derived outputs; they do not rerun the " + "peak searches or validate an asymptotic law. The residue checks reconstruct all 12,000-row " + "statistics and replay three seeded supports per group (36 total). Formula agreement does " + "not establish the dense-bulk ansatz's approximation accuracy. Novelty remains a separate question.") + write_report(report, args.output) + except (ValueError, OSError, KeyError, TypeError) as exc: + print(f"# Scientific sanity checks\n\n**Status: FAIL**\n\n{exc}", file=sys.stderr) + return 1 + return 0 if __name__ == "__main__": - main() + raise SystemExit(main()) diff --git a/scripts/peak_scaling_verification.py b/scripts/peak_scaling_verification.py index 254e98b..6996c96 100644 --- a/scripts/peak_scaling_verification.py +++ b/scripts/peak_scaling_verification.py @@ -42,7 +42,7 @@ def read_schedule(path: Path) -> dict[int, dict[str, float | int]]: } -def plot_one(n: int, rows: list[dict], fit: dict, out_pdf: Path) -> None: +def plot_one(n: int, rows: list[dict], fit: dict, out_path: Path) -> None: apply_journal_style() fig, ax = plt.subplots(figsize=(4.7, 3.6)) m = np.asarray([row["m"] for row in rows], dtype=float) @@ -59,7 +59,7 @@ def plot_one(n: int, rows: list[dict], fit: dict, out_pdf: Path) -> None: ax.set_ylabel(r"$S_{N,M}$") ax.set_title(fr"local peak check, $n={n}$") ax.legend(frameon=False) - save_figure(fig, out_pdf) + save_figure(fig, out_path) def main() -> None: @@ -74,7 +74,7 @@ def main() -> None: parser.add_argument("--span", type=float, default=None) parser.add_argument("--seed", type=int, default=20250605) parser.add_argument("--dry-run", action="store_true") - parser.add_argument("--outdir", type=Path, default=ROOT / "outputs" / "peak_verification") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "peak_verification") args = parser.parse_args() table = read_table_i(args.table) @@ -131,7 +131,7 @@ def main() -> None: fit["S_peak_minus_table_S_n"] = float(fit["S_peak"] - job["table_S_n"]) write_rows(args.outdir / f"peak_verification_n{job['n']}_samples.csv", rows, rows[0].keys()) write_rows(args.outdir / f"peak_verification_n{job['n']}_fit.csv", [fit], fit.keys()) - plot_one(job["n"], rows, fit, args.outdir / f"peak_verification_n{job['n']}.pdf") + plot_one(job["n"], rows, fit, args.outdir / f"peak_verification_n{job['n']}.png") summary.append(fit) write_rows(args.outdir / "peak_verification_summary.csv", summary, summary[0].keys()) diff --git a/scripts/plot_fig1_from_csv.py b/scripts/plot_fig1_from_csv.py index c461f68..3d28001 100644 --- a/scripts/plot_fig1_from_csv.py +++ b/scripts/plot_fig1_from_csv.py @@ -17,7 +17,7 @@ def main() -> None: parser.add_argument("--data-dir", type=Path, default=ROOT / "outputs" / "fig1") parser.add_argument("--out", type=Path, default=None) args = parser.parse_args() - out = args.out if args.out is not None else args.data_dir / "fig1_concentration.pdf" + out = args.out if args.out is not None else ROOT / "generated" / "figures" / "fig1" / "fig1_concentration.png" plot_fig1(args.data_dir, out) diff --git a/scripts/plot_fig2_from_csv.py b/scripts/plot_fig2_from_csv.py index d8c2d61..57084ba 100644 --- a/scripts/plot_fig2_from_csv.py +++ b/scripts/plot_fig2_from_csv.py @@ -17,7 +17,7 @@ def main() -> None: parser.add_argument("--data-dir", type=Path, default=ROOT / "outputs" / "fig2") parser.add_argument("--out", type=Path, default=None) args = parser.parse_args() - out = args.out if args.out is not None else args.data_dir / "fig2_peak_scaling.pdf" + out = args.out if args.out is not None else ROOT / "generated" / "figures" / "fig2" / "fig2_peak_scaling.png" plot_fig2(args.data_dir, out) diff --git a/scripts/plot_fig3_from_csv.py b/scripts/plot_fig3_from_csv.py index bcbec5d..31bd527 100644 --- a/scripts/plot_fig3_from_csv.py +++ b/scripts/plot_fig3_from_csv.py @@ -18,7 +18,7 @@ def main() -> None: parser.add_argument("--out", type=Path, default=None) parser.add_argument("--bins", type=int, default=500) args = parser.parse_args() - out = args.out if args.out is not None else args.data_dir / "fig3_spectral_bulk.pdf" + out = args.out if args.out is not None else ROOT / "generated" / "figures" / "fig3" / "fig3_spectral_bulk.png" plot_fig3(args.data_dir, out, bins=args.bins) diff --git a/scripts/plot_fig4_from_csv.py b/scripts/plot_fig4_from_csv.py index 7954de5..03c649b 100644 --- a/scripts/plot_fig4_from_csv.py +++ b/scripts/plot_fig4_from_csv.py @@ -17,7 +17,7 @@ def main() -> None: parser.add_argument("--data-dir", type=Path, default=ROOT / "outputs" / "fig4") parser.add_argument("--out", type=Path, default=None) args = parser.parse_args() - out = args.out if args.out is not None else args.data_dir / "fig4_approximation.pdf" + out = args.out if args.out is not None else ROOT / "generated" / "figures" / "fig4" / "fig4_approximation.png" plot_fig4(args.data_dir, out) diff --git a/scripts/plot_fig6_from_csv.py b/scripts/plot_fig6_from_csv.py index 937bf50..96003f9 100644 --- a/scripts/plot_fig6_from_csv.py +++ b/scripts/plot_fig6_from_csv.py @@ -17,7 +17,7 @@ def main() -> None: parser.add_argument("--data-dir", type=Path, default=ROOT / "outputs" / "fig6") parser.add_argument("--out", type=Path, default=None) args = parser.parse_args() - out = args.out if args.out is not None else args.data_dir / "fig6_renyi.pdf" + out = args.out if args.out is not None else ROOT / "generated" / "figures" / "fig6" / "fig6_renyi.png" plot_fig6(args.data_dir, out) diff --git a/scripts/plot_fig7_from_csv.py b/scripts/plot_fig7_from_csv.py index 2124011..c4c32ca 100644 --- a/scripts/plot_fig7_from_csv.py +++ b/scripts/plot_fig7_from_csv.py @@ -18,7 +18,7 @@ def main() -> None: parser.add_argument("--out", type=Path, default=None) parser.add_argument("--bins", type=int, default=100) args = parser.parse_args() - out = args.out if args.out is not None else args.data_dir / "fig7_partitions.pdf" + out = args.out if args.out is not None else ROOT / "generated" / "figures" / "fig7" / "fig7_partitions.png" plot_fig7(args.data_dir, out, bins=args.bins) diff --git a/scripts/plot_peak_verification_from_csv.py b/scripts/plot_peak_verification_from_csv.py index 36cc614..7e304d4 100644 --- a/scripts/plot_peak_verification_from_csv.py +++ b/scripts/plot_peak_verification_from_csv.py @@ -16,7 +16,7 @@ def main() -> None: args = parser.parse_args() samples = args.data_dir / f"peak_verification_n{args.n}_samples.csv" fit = args.data_dir / f"peak_verification_n{args.n}_fit.csv" - out = args.out or args.data_dir / f"peak_verification_n{args.n}_from_csv.pdf" + out = args.out or ROOT / "generated" / "figures" / "peak_verification" / f"peak_verification_n{args.n}_from_csv.png" plot_peak_search(samples, fit, out) if __name__ == "__main__": diff --git a/scripts/regenerate_fig5_baseline.py b/scripts/regenerate_fig5_baseline.py index 3d7986c..9ac71de 100644 --- a/scripts/regenerate_fig5_baseline.py +++ b/scripts/regenerate_fig5_baseline.py @@ -1,29 +1,56 @@ #!/usr/bin/env python3 -"""Regenerate the n=14 random position/Fourier baseline and arithmetic points.""" +"""Regenerate the random position/Fourier baseline and arithmetic points. + +The n=14 default is expensive. New CSVs go to generated/full/fig5. +""" from __future__ import annotations -import argparse, csv, sys + +import argparse from pathlib import Path -import numpy as np -ROOT=Path(__file__).resolve().parents[1] -sys.path.insert(0,str(ROOT)) -from subset_states.core import entropy_from_state_vector, entropy_from_support, qft_state_from_support, summary_stats -from subset_states.experiments import almost_prime_union_supports, m_grid, random_subset_qft_samples - -def write(path, rows): - path.parent.mkdir(parents=True,exist_ok=True) - with path.open('w',newline='') as f: - w=csv.DictWriter(f,fieldnames=list(rows[0].keys()));w.writeheader();w.writerows(rows) - -def main(): - p=argparse.ArgumentParser();p.add_argument('--n',type=int,default=14);p.add_argument('--points',type=int,default=100);p.add_argument('--samples',type=int,default=100);p.add_argument('--seed',type=int,default=20250604);p.add_argument('--outdir',type=Path,default=ROOT/'data');a=p.parse_args() - rows=[] - for off,m in enumerate(m_grid(1,1< None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--n", type=int, default=14) + parser.add_argument("--points", type=int, default=100) + parser.add_argument("--samples", type=int, default=100) + parser.add_argument("--seed", type=int, default=20250604) + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig5") + args = parser.parse_args() + rows = [] + for offset, m in enumerate(m_grid(1, 1 << args.n, args.points)): + position, fourier = random_subset_qft_samples(args.n, int(m), args.samples, seed=args.seed + offset) + ps, fs = summary_stats(position), summary_stats(fourier) + rows.append({ + "m": int(m), "sample_count": args.samples, + "position_mean": ps.mean, "position_std": ps.std, "position_sem": ps.sem, + "qft_mean": fs.mean, "qft_std": fs.std, "qft_sem": fs.sem, + "delta_qft_minus_position": fs.mean - ps.mean, + }) + if offset % 10 == 0: + print(f"baseline {offset + 1}/{args.points}") + unions = [] + for k, support in almost_prime_union_supports(args.n): + unions.append({ + "k": k, "m": int(support.size), + "position_entropy": entropy_from_support(args.n, support), + "qft_entropy": entropy_from_state_vector(args.n, qft_state_from_support(args.n, support)), + }) + write_rows(args.outdir / "fig5_random_qft_summary.csv", rows, rows[0].keys()) + write_rows(args.outdir / "fig5_almost_prime_unions.csv", unions, unions[0].keys()) + + +if __name__ == "__main__": + main() diff --git a/scripts/reproduce_publication_figures.py b/scripts/reproduce_publication_figures.py index f85a8fc..bdab436 100644 --- a/scripts/reproduce_publication_figures.py +++ b/scripts/reproduce_publication_figures.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 -"""Convenience driver for publication figures. +"""Redraw all seven figures from released CSV, or opt into new computations. -Default mode regenerates the fast deterministic figures (2 and 5) and verifies -that all released vector figures are present. ``--full`` launches every -sampling script with its publication defaults and can be computationally costly. +Default: generated/figures. --smoke: small new runs in generated/smoke. +--full: original sampling defaults in generated/full (potentially expensive). +No mode writes into the released data/ or outputs/ trees. """ from __future__ import annotations + import argparse from pathlib import Path import subprocess @@ -14,52 +15,113 @@ ROOT = Path(__file__).resolve().parents[1] FIGURE_FILES = { - 1: "fig1/fig1_concentration.pdf", - 2: "fig2/fig2_peak_scaling.pdf", - 3: "fig3/fig3_spectral_bulk.pdf", - 4: "fig4/fig4_approximation.pdf", - 5: "fig5/fig5_qft_residue_controls.pdf", - 6: "fig6/fig6_renyi.pdf", - 7: "fig7/fig7_partitions.pdf", + 1: "fig1/fig1_concentration.png", + 2: "fig2/fig2_peak_scaling.png", + 3: "fig3/fig3_spectral_bulk.png", + 4: "fig4/fig4_approximation.png", + 5: "fig5/fig5_qft_residue_controls.png", + 6: "fig6/fig6_renyi.png", + 7: "fig7/fig7_partitions.png", +} +CSV_INPUTS = { + 1: ("fig1_summary.csv", "fig1_zoom_summary.csv"), + 2: ("fig2_table_with_page.csv",), + 3: ("fig3_spectrum.csv", "fig3_spectrum_summary.csv"), + 4: ("fig4_summary.csv", "fig4_zoom_summary.csv"), + 5: ("fig5_random_qft_summary.csv", "fig5_almost_prime_unions.csv", "residue_matched_summary.csv"), + 6: ("fig6_renyi_summary.csv", "fig6_renyi_zoom_summary.csv"), + 7: ("fig7_partition_samples.csv", "fig7_partition_summary.csv"), } -def run(script: str, *args: str) -> None: - command = [sys.executable, str(ROOT / "scripts" / script), *args] - print("+", " ".join(command)) - subprocess.run(command, check=True, cwd=ROOT) +def validate_csv_inputs(released_root: Path, data_root: Path) -> None: + """Fail before any drawing if even one required released table is absent.""" + missing = [] + for number, names in CSV_INPUTS.items(): + folder = data_root if number == 5 else released_root / f"fig{number}" + missing.extend(str(folder / name) for name in names if not (folder / name).is_file()) + if missing: + raise FileNotFoundError("missing released CSV inputs:\n" + "\n".join(missing)) + + +def validate_output_root(outdir: Path, *protected: Path) -> None: + """Reject destinations that could overwrite released inputs or figures.""" + target = outdir.resolve() + for folder in protected: + source = folder.resolve() + if target == source or source in target.parents or target in source.parents: + raise ValueError(f"output directory must be separate from released evidence: {folder}") + + +def build_commands( + mode: str, + outdir: Path, + *, + released_root: Path = ROOT / "outputs", + data_root: Path = ROOT / "data", +) -> list[list[str]]: + """Build explicit input/output commands so no child relies on output defaults.""" + commands: list[list[str]] = [] + + def add(script: str, *args: str | Path) -> None: + commands.append([sys.executable, str(ROOT / "scripts" / script), *map(str, args)]) + + if mode == "redraw": + for number, filename in FIGURE_FILES.items(): + if number == 5: + add("fig5_qft_residue_controls.py", "--data-dir", data_root, "--outdir", outdir / "fig5") + else: + add(f"plot_fig{number}_from_csv.py", "--data-dir", released_root / f"fig{number}", "--out", outdir / filename) + return commands + if mode not in {"smoke", "full"}: + raise ValueError(f"unknown figure mode: {mode}") + + small_grid = ["--n", "6", "--points", "5", "--samples", "2", "--zoom-points", "4", "--zoom-samples", "2", "--zoom-stop", "32"] if mode == "smoke" else [] + add("fig1_concentration.py", *small_grid, "--outdir", outdir / "fig1") + add("fig2_peak_scaling.py", "--table", data_root / "table_i_peaks.csv", "--outdir", outdir / "fig2") + spectrum = ["--n", "8", "--m", "40", "--bins", "20"] if mode == "smoke" else [] + add("fig3_spectral.py", *spectrum, "--outdir", outdir / "fig3") + add("fig4_approximation.py", *small_grid, "--outdir", outdir / "fig4") + baseline = ["--n", "6", "--points", "5", "--samples", "2"] if mode == "smoke" else [] + nulls = ["--n", "6", "--samples", "2"] if mode == "smoke" else [] + add("regenerate_fig5_baseline.py", *baseline, "--outdir", outdir / "fig5") + add("run_residue_controls.py", *nulls, "--outdir", outdir / "fig5") + add("fig5_qft_residue_controls.py", "--data-dir", outdir / "fig5", "--outdir", outdir / "fig5") + add("fig6_renyi.py", *small_grid, "--outdir", outdir / "fig6") + partitions = ["--n", "6", "--m", "20", "--samples", "3"] if mode == "smoke" else [] + add("fig7_partitions.py", *partitions, "--outdir", outdir / "fig7") + return commands def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("--full", action="store_true", help="run every publication computation; expensive") - parser.add_argument("--smoke", action="store_true", help="run reduced-size computation checks") + parser = argparse.ArgumentParser(description=__doc__) + modes = parser.add_mutually_exclusive_group() + modes.add_argument("--full", action="store_true", help="run every figure computation with original defaults; expensive") + modes.add_argument("--smoke", action="store_true", help="run reduced-size computations, including Figure 5 nulls") + parser.add_argument("--outdir", type=Path, help="generated destination; must be separate from released evidence") + parser.add_argument("--released-dir", type=Path, default=ROOT / "outputs", help="released figure CSV tree") + parser.add_argument("--data-dir", type=Path, default=ROOT / "data", help="released Figure 5 CSV and peak-table inputs") args = parser.parse_args() + args.released_dir = args.released_dir.resolve() + args.data_dir = args.data_dir.resolve() + mode = "full" if args.full else "smoke" if args.smoke else "redraw" + outdir = (args.outdir or ROOT / "generated" / ("figures" if mode == "redraw" else mode)).resolve() + try: + validate_output_root(outdir, ROOT / "outputs", ROOT / "data", args.released_dir, args.data_dir) + if mode == "redraw": + validate_csv_inputs(args.released_dir, args.data_dir) + elif not (args.data_dir / "table_i_peaks.csv").is_file(): + raise FileNotFoundError(f"missing peak-table input: {args.data_dir / 'table_i_peaks.csv'}") + except (ValueError, FileNotFoundError) as exc: + parser.error(str(exc)) - if args.full: - for script in [ - "fig1_concentration.py", "fig2_peak_scaling.py", "fig3_spectral.py", - "fig4_approximation.py", "regenerate_fig5_baseline.py", - "run_residue_controls.py", "fig5_qft_residue_controls.py", - "fig6_renyi.py", "fig7_partitions.py", - ]: - run(script) - elif args.smoke: - run("fig1_concentration.py", "--n", "6", "--points", "5", "--samples", "2", "--zoom-points", "4", "--zoom-samples", "2", "--zoom-stop", "32", "--outdir", str(ROOT / "outputs" / "smoke" / "fig1")) - run("fig2_peak_scaling.py") - run("fig3_spectral.py", "--n", "8", "--m", "40", "--bins", "20", "--outdir", str(ROOT / "outputs" / "smoke" / "fig3")) - run("fig4_approximation.py", "--n", "6", "--points", "5", "--samples", "2", "--zoom-stop", "32", "--zoom-points", "4", "--zoom-samples", "2", "--outdir", str(ROOT / "outputs" / "smoke" / "fig4")) - run("fig5_qft_residue_controls.py") - run("fig6_renyi.py", "--n", "6", "--points", "5", "--samples", "2", "--zoom-stop", "32", "--zoom-points", "4", "--zoom-samples", "2", "--outdir", str(ROOT / "outputs" / "smoke" / "fig6")) - run("fig7_partitions.py", "--n", "6", "--m", "20", "--samples", "3", "--outdir", str(ROOT / "outputs" / "smoke" / "fig7")) - else: - run("fig2_peak_scaling.py") - run("fig5_qft_residue_controls.py") - - missing = [str(ROOT / "outputs" / rel) for rel in FIGURE_FILES.values() if not (ROOT / "outputs" / rel).exists()] + for command in build_commands(mode, outdir, released_root=args.released_dir, data_root=args.data_dir): + print("+", " ".join(command), flush=True) + subprocess.run(command, check=True, cwd=ROOT) + missing = [str(outdir / rel) for rel in FIGURE_FILES.values() if not (outdir / rel).is_file()] if missing: - raise SystemExit("missing released figure files:\n" + "\n".join(missing)) - print("All seven released figure PDFs are present.") + raise SystemExit("missing generated figure files:\n" + "\n".join(missing)) + print(f"Generated all seven PNG figures in {outdir} ({mode}).") if __name__ == "__main__": diff --git a/scripts/run_residue_controls.py b/scripts/run_residue_controls.py index 1a1bede..c000119 100644 --- a/scripts/run_residue_controls.py +++ b/scripts/run_residue_controls.py @@ -96,7 +96,7 @@ def main() -> None: parser.add_argument("--matched-bits", type=int, nargs="+", default=[0, 1, 2, 3]) parser.add_argument("--samples", type=int, default=1000) parser.add_argument("--seed", type=int, default=2026081701) - parser.add_argument("--outdir", type=Path, default=ROOT / "data") + parser.add_argument("--outdir", type=Path, default=ROOT / "generated" / "full" / "fig5") args = parser.parse_args() if args.n <= 0 or args.n % 2: diff --git a/scripts/validate_residue_results.py b/scripts/validate_residue_results.py index 81ffaae..4a6ea0f 100644 --- a/scripts/validate_residue_results.py +++ b/scripts/validate_residue_results.py @@ -1,76 +1,275 @@ #!/usr/bin/env python3 +"""Check retained residue-control evidence without rewriting it. + +This validates the recorded n=14, k=1..3, t=0..3, 1000-sample experiment. +All raw-row statistics are checked; only a stated prefix is replayed from seeds. +""" from __future__ import annotations -import csv, json, math, sys -from itertools import combinations + +import argparse +import csv +import json +import math +from collections import defaultdict from pathlib import Path +import sys + import numpy as np -ROOT=Path(__file__).resolve().parents[1];sys.path.insert(0,str(ROOT)) -from subset_states.core import entropy_from_support, matrix_from_support + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +from subset_states import core from subset_states.experiments import almost_prime_union_supports +from scripts.run_residue_controls import sample_matched_support + + +class ValidationError(ValueError): + """An explicit acceptance failure, including when Python uses -O.""" + + +def require(condition: bool, message: str) -> None: + if not condition: + raise ValidationError(message) + + +def close(actual: float, expected: float, label: str, *, atol: float = 2e-11) -> float: + require(math.isfinite(actual) and math.isfinite(expected), f"{label}: non-finite value") + error = abs(actual - expected) + require(error <= atol, f"{label}: {actual:.16g} != {expected:.16g} (error {error:.3g})") + return error + + +def read_rows(path: Path, required: set[str]) -> list[dict[str, str]]: + with path.open(newline="", encoding="utf-8") as handle: + reader = csv.DictReader(handle) + names = reader.fieldnames or [] + require(len(names) == len(set(names)), f"{path}: duplicate columns") + require(required <= set(names), f"{path}: missing columns {sorted(required - set(names))}") + rows = list(reader) + require(bool(rows), f"{path}: no data rows") + for index, row in enumerate(rows, 2): + require(None not in row and all(value is not None for value in row.values()), + f"{path}:{index}: malformed CSV row") + for field in required: + require(row[field] != "", f"{path}:{index}: empty {field}") + return rows + + +def finite(row: dict[str, str], field: str) -> float: + value = float(row[field]) + require(math.isfinite(value), f"{field}: non-finite value") + return value + + +def shannon(counts: np.ndarray) -> float: + p = counts[counts > 0] / counts.sum() + return float(-np.sum(p * np.log2(p))) + + +def independent_entropy(n: int, support: np.ndarray, *, fourier: bool = False) -> float: + vector = np.zeros(1 << n, dtype=complex) + vector[support] = 1 / math.sqrt(len(support)) + if fourier: + # Opposite-sign QFT conjugates these real input amplitudes and preserves entropy. + vector = np.fft.fft(vector, norm="ortho") + matrix = vector.reshape(1 << (n // 2), -1) + values = np.linalg.eigvalsh(matrix.conj().T @ matrix) + require(float(values.min()) >= -2e-12, "independent density matrix is not positive") + close(float(values.sum()), 1.0, "independent density matrix trace") + values = values[values > 1e-14] + return float(-np.sum(values * np.log2(values))) + + +def independent_almost_prime_supports(n: int) -> dict[int, np.ndarray]: + # Trial division is independent of the production sieve. + counts = np.zeros(1 << n, dtype=int) + for number in range(2, 1 << n): + remainder, factor = number, 2 + while factor * factor <= remainder: + while remainder % factor == 0: + counts[number] += 1 + remainder //= factor + factor += 1 + if remainder > 1: + counts[number] += 1 + return {k: np.flatnonzero((counts >= 1) & (counts <= k)) for k in (1, 2, 3)} + + +def residue_checks(root: Path = ROOT, *, replay_samples: int = 3) -> dict[str, float | int]: + require(0 <= replay_samples <= 1000, "replay_samples must lie in [0, 1000]") + metadata = {"n", "k", "M", "matched_low_bits", "modulus", "seed"} + stat_names = {"mean", "std", "sem", "q025", "median", "q975", "min", "max"} + summary_fields = metadata | { + "samples", "residue_counts", "residue_entropy_bits", "entropy_ceiling_bits", + "forced_gap_from_balanced_max_bits", "paired_null_fourier_minus_position_mean", + "paired_null_fourier_minus_position_std", + } + for basis in ("position", "fourier"): + summary_fields |= {f"null_{basis}_{stat}" for stat in stat_names} + summary_fields |= {f"structured_{basis}_entropy", f"{basis}_residual_deficit", + f"{basis}_standardized_deficit", f"{basis}_null_count_at_or_below_structured", + f"cardinality_deficit_reduction_{basis}"} + summary = read_rows(root / "data/residue_matched_summary.csv", summary_fields) + raw = read_rows(root / "data/residue_matched_samples.csv", metadata | { + "sample", "position_entropy", "fourier_entropy", "fourier_minus_position"}) + bounds = read_rows(root / "data/residue_entropy_bounds.csv", metadata - {"seed"} | { + "residue_counts", "residue_probabilities", "residue_entropy_bits", "entropy_ceiling_bits", + "forced_gap_from_balanced_max_bits", "structured_position_entropy", "ceiling_minus_structured_entropy"}) + key = lambda row: (int(row["n"]), int(row["k"]), int(row["matched_low_bits"])) + expected = {(14, k, t) for k in (1, 2, 3) for t in range(4)} + by_key = {key(row): row for row in summary} + bound_by_key = {key(row): row for row in bounds} + require(len(summary) == len(by_key) == 12 and set(by_key) == expected, + "summary must contain each of the 12 recorded groups exactly once") + require(len(bounds) == len(bound_by_key) == 12 and set(bound_by_key) == expected, + "bounds must contain each of the 12 recorded groups exactly once") + grouped: dict[tuple[int, int, int], list[dict[str, str]]] = defaultdict(list) + for row in raw: + grouped[key(row)].append(row) + require(set(grouped) == expected, "raw group keys disagree with the recorded experiment") + + supports = independent_almost_prime_supports(14) + production_supports = dict(almost_prime_union_supports(14)) + structured = {} + for k, support in supports.items(): + require(np.array_equal(support, production_supports[k]), f"k={k}: production support sieve") + structured[k] = (independent_entropy(14, support), independent_entropy(14, support, fourier=True)) + close(core.entropy_from_support(14, support), structured[k][0], f"k={k}: production entropy") + close(core.entropy_from_state_vector(14, core.qft_state_from_support(14, support)), + structured[k][1], f"k={k}: production Fourier entropy") + + max_error, max_replay_error, replayed = 0.0, 0.0, 0 + for group in sorted(expected): + n, k, t = group + row, bound = by_key[group], bound_by_key[group] + label = f"n={n}, k={k}, t={t}" + support, q = supports[k], 1 << t + target = np.bincount(support % q, minlength=q) + count, seed = int(row["samples"]), int(row["seed"]) + require(count == 1000, f"{label}: expected 1000 recorded samples") + require(seed == 2026081701 + 1000 * k + 37 * t, f"{label}: recorded seed schedule") + require(int(row["M"]) == len(support) and int(row["modulus"]) == q, f"{label}: support metadata") + require(json.loads(row["residue_counts"]) == target.tolist(), f"{label}: residue populations") + group_rows = grouped[group] + require(len(group_rows) == count, f"{label}: sample count mismatch") + require(sorted(int(r["sample"]) for r in group_rows) == list(range(count)), + f"{label}: duplicate or missing sample IDs") + group_rows.sort(key=lambda r: int(r["sample"])) + for sample_row in group_rows: + require(all(int(sample_row[field]) == int(row[field]) for field in metadata), + f"{label}: raw metadata mismatch") + position = np.array([finite(r, "position_entropy") for r in group_rows]) + fourier = np.array([finite(r, "fourier_entropy") for r in group_rows]) + differences = np.array([finite(r, "fourier_minus_position") for r in group_rows]) + require(np.max(np.abs(differences - (fourier - position))) < 2e-11, + f"{label}: paired raw differences") + H = shannon(target) + ceiling = n / 2 - t + H + close(core.residue_class_entropy_ceiling(n, support, t), ceiling, f"{label}: production ceiling") + for field, value in { + "residue_entropy_bits": H, "entropy_ceiling_bits": ceiling, + "forced_gap_from_balanced_max_bits": n / 2 - ceiling, + "structured_position_entropy": structured[k][0], + }.items(): + max_error = max(max_error, close(finite(row, field), value, f"{label}: {field}")) + max_error = max(max_error, close(finite(bound, field), value, f"{label}: bounds {field}")) + require(all(int(bound[field]) == int(row[field]) for field in metadata - {"seed"}), + f"{label}: bounds metadata") + require(json.loads(bound["residue_counts"]) == target.tolist(), f"{label}: bounds populations") + probabilities = np.asarray(json.loads(bound["residue_probabilities"]), dtype=float) + require(probabilities.shape == target.shape and np.all(np.isfinite(probabilities)), + f"{label}: bounds probabilities shape or finiteness") + require(np.max(np.abs(probabilities - target / len(support))) < 2e-12, + f"{label}: bounds probabilities") + close(finite(bound, "ceiling_minus_structured_entropy"), ceiling - structured[k][0], + f"{label}: ceiling slack") + require(structured[k][0] <= ceiling + 2e-11 and float(position.max()) <= ceiling + 2e-11, + f"{label}: position residue ceiling violated") + for basis, values, entropy in zip(("position", "fourier"), (position, fourier), structured[k]): + require(np.all((values >= -2e-11) & (values <= n / 2 + 2e-11)), f"{label}: entropy range") + close(finite(row, f"structured_{basis}_entropy"), entropy, f"{label}: structured {basis}") + sd = float(values.std(ddof=1)) + require(sd > 0, f"{label}: zero null variance") + statistics = dict(mean=float(values.mean()), std=sd, sem=sd / math.sqrt(count), + q025=float(np.quantile(values, .025)), median=float(np.median(values)), + q975=float(np.quantile(values, .975)), min=float(values.min()), max=float(values.max())) + for stat, value in statistics.items(): + field = f"null_{basis}_{stat}" + max_error = max(max_error, close(finite(row, field), value, f"{label}: {field}")) + residual = statistics["mean"] - entropy + close(finite(row, f"{basis}_residual_deficit"), residual, f"{label}: {basis} residual") + close(finite(row, f"{basis}_standardized_deficit"), residual / sd, + f"{label}: {basis} standardized deficit", atol=2e-8) + below = int(np.count_nonzero(values <= entropy)) + require(int(row[f"{basis}_null_count_at_or_below_structured"]) == below, + f"{label}: {basis} tail count mismatch") + require(below == 0, f"{label}: recorded all-samples-above-structured claim fails") + baseline = finite(by_key[(n, k, 0)], f"{basis}_residual_deficit") + require(baseline != 0, f"{label}: zero cardinality baseline") + close(finite(row, f"cardinality_deficit_reduction_{basis}"), 1 - residual / baseline, + f"{label}: {basis} deficit reduction") + close(finite(row, "paired_null_fourier_minus_position_mean"), float(differences.mean()), f"{label}: paired mean") + close(finite(row, "paired_null_fourier_minus_position_std"), float(differences.std(ddof=1)), f"{label}: paired std") + + rng = np.random.default_rng(seed) + for sample in range(replay_samples): + sampled = sample_matched_support(n, target, q, rng) + require(len(sampled) == len(support) and len(np.unique(sampled)) == len(sampled), + f"{label}: sampler cardinality or uniqueness") + require(np.all((sampled >= 0) & (sampled < (1 << n))), f"{label}: sampler label range") + require(np.array_equal(np.bincount(sampled % q, minlength=q), target), f"{label}: sampler populations") + for basis, actual, recorded in ( + ("position", core.entropy_from_support(n, sampled), position[sample]), + ("fourier", core.entropy_from_state_vector(n, core.qft_state_from_support(n, sampled)), fourier[sample]), + ): + max_replay_error = max(max_replay_error, close(actual, recorded, f"{label}, sample={sample}: replay {basis}")) + replayed += 1 + return {"groups_checked": len(summary), "raw_rows_checked": len(raw), + "max_summary_error": max_error, "seed_replayed_supports": replayed, + "max_seed_replay_entropy_error": max_replay_error} + + +def markdown_report(title: str, sections: dict[str, dict[str, float | int]], scope: str) -> str: + lines = [f"# {title}", "", "**Status: PASS for the checks listed below.**", "", scope, ""] + for name, values in sections.items(): + lines.extend([f"## {name}", "", "| Check | Result |", "| --- | ---: |"]) + lines.extend(f"| {key.replace('_', ' ')} | {value:.12g} |" for key, value in values.items()) + lines.append("") + return "\n".join(lines) + + +def write_report(text: str, output: Path | None) -> None: + if output is not None: + destination = output.resolve() + require(destination.suffix.lower() == ".md", "--output must name a Markdown (.md) file") + require(not destination.exists(), "refusing to overwrite an existing file") + for name in ("data", "outputs", "subset_states", "scripts", "tests"): + require(not destination.is_relative_to(ROOT / name), "refusing to write inside source or evidence directories") + destination.parent.mkdir(parents=True, exist_ok=True) + with destination.open("x", encoding="utf-8") as handle: + handle.write(text) + print(text) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output", type=Path, help="save the report to a new .md file") + parser.add_argument("--replay-samples", type=int, default=3, help="seed-replay prefix per group (1..1000; default 3)") + args = parser.parse_args() + try: + require(1 <= args.replay_samples <= 1000, "--replay-samples must lie in [1, 1000]") + results = residue_checks(replay_samples=args.replay_samples) + report = markdown_report("Residue-control validation", {"Recorded experiment": results}, + "Checks all 12,000 raw rows against summaries and bounds, recomputes the three structured states, " + "and replays the stated number of matched supports. This is not a full rerun unless all 1,000 " + "samples per group are requested; it does not establish an arithmetic mechanism or novelty.") + write_report(report, args.output) + except (ValueError, OSError, KeyError, TypeError) as exc: + print(f"# Residue-control validation\n\n**Status: FAIL**\n\n{exc}", file=sys.stderr) + return 1 + return 0 + -def H(counts): - c=np.asarray(counts,dtype=float);p=c[c>0]/c.sum();return float(-np.sum(p*np.log2(p))) if p.size else 0.0 - -def direct_entropy(n,support): - omega=matrix_from_support(n,support);rho=omega.conj().T@omega - w=np.linalg.eigvalsh(rho).real;w=w[w>1e-14];w=w/w.sum();return float(-np.sum(w*np.log2(w))) - -def main(): - out=[];n=4;N=1<>i&1),dtype=np.int64) - S=entropy_from_support(n,s);max_direct=max(max_direct,abs(S-direct_entropy(n,s))) - for t in (1,2): - q=1<1e-10 or max_direct>1e-10 or single_class_violation>1e-10 or max_mean_err>1e-12 or max_std_err>1e-12 or not all_counts or not all_below: raise SystemExit(1) -if __name__=='__main__':main() +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/subset_states/core.py b/subset_states/core.py index 1624240..49ed444 100644 --- a/subset_states/core.py +++ b/subset_states/core.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from itertools import combinations from math import log2, sqrt +from numbers import Integral, Real from typing import Iterable, Sequence import numpy as np @@ -22,18 +23,48 @@ class SummaryStats: maximum: float +def _validate_positive_n(n: int) -> None: + if isinstance(n, (bool, np.bool_)) or not isinstance(n, Integral) or n <= 0: + raise ValueError(f"n must be a positive integer; received n={n}.") + + def _validate_even_n(n: int) -> None: - if n <= 0 or n % 2 != 0: + _validate_positive_n(n) + if n % 2 != 0: raise ValueError(f"n must be a positive even integer; received n={n}.") def _validate_support_size(n: int, m: int, *, allow_zero: bool = False) -> None: N = 1 << n lower = 0 if allow_zero else 1 - if not (lower <= m <= N): + if isinstance(m, (bool, np.bool_)) or not isinstance(m, Integral) or not (lower <= m <= N): raise ValueError(f"m must satisfy {lower} <= m <= 2**n={N}; received m={m}.") +def _validated_support(n: int, support: ArrayLike) -> NDArray[np.int64]: + """Validate before conversion so fractional or unsigned labels cannot wrap.""" + + _validate_positive_n(n) + labels = np.asarray(support) + if labels.ndim != 1 or labels.size == 0: + raise ValueError("support must be a nonempty one-dimensional array of integer basis labels.") + if labels.dtype.kind not in "iu": + raise ValueError("support labels must be integers.") + N = 1 << n + if np.any(labels < 0) or np.any(labels >= N): + raise ValueError(f"support labels must lie in [0, {N - 1}].") + if np.unique(labels).size != labels.size: + raise ValueError("support contains duplicate basis labels.") + if np.any(labels > np.iinfo(np.int64).max): + raise ValueError("support labels exceed the supported int64 range.") + return labels.astype(np.int64, copy=False) + + +def _validate_atol(atol: float) -> None: + if not isinstance(atol, Real) or not np.isfinite(atol) or atol < 0: + raise ValueError("atol must be a finite nonnegative real number.") + + def natural_right_bits(n: int) -> tuple[int, ...]: """Return the natural right subsystem: the low-order n/2 bits.""" @@ -42,6 +73,8 @@ def natural_right_bits(n: int) -> tuple[int, ...]: def _left_bits(n: int, right_bits: Sequence[int]) -> tuple[int, ...]: + if any(isinstance(bit, (bool, np.bool_)) or not isinstance(bit, Integral) for bit in right_bits): + raise ValueError("right_bits must contain integer bit positions.") right = set(right_bits) if len(right) != len(right_bits): raise ValueError("right_bits contains repeated bit positions.") @@ -53,8 +86,7 @@ def _left_bits(n: int, right_bits: Sequence[int]) -> tuple[int, ...]: def random_subset(n: int, m: int, rng: np.random.Generator) -> NDArray[np.int64]: """Sample a uniformly random subset of {0, ..., 2**n - 1} of size m.""" - if n <= 0: - raise ValueError("n must be positive.") + _validate_positive_n(n) _validate_support_size(n, m) return np.sort(rng.choice(1 << n, size=m, replace=False).astype(np.int64)) @@ -79,22 +111,17 @@ def matrix_from_support( ) -> NDArray: """Return the bipartite coefficient matrix for an equal-amplitude support. - With ``normalize=True``, each occupied entry equals 1/sqrt(M), so the reduced - density matrix of the right subsystem is ``C.conj().T @ C``. Set + The first position in each subsystem's bit list is its least significant + bit. With ``normalize=True``, each occupied entry equals 1/sqrt(M). For + coefficients C[a, b], the right reduced state is ``C.T @ C.conj()`` + (here C is real). Set ``normalize=False`` to obtain the binary support-incidence matrix. """ _validate_even_n(n) - support_arr = np.asarray(support, dtype=np.int64) - if support_arr.ndim != 1: - raise ValueError("support must be a one-dimensional array of basis labels.") - if support_arr.size == 0: - raise ValueError("support must contain at least one basis label.") - N = 1 << n - if np.any(support_arr < 0) or np.any(support_arr >= N): - raise ValueError(f"support labels must lie in [0, {N - 1}].") - if np.unique(support_arr).size != support_arr.size: - raise ValueError("support contains duplicate basis labels.") + support_arr = _validated_support(n, support) + if normalize and np.dtype(dtype).kind not in "fc": + raise ValueError("normalized coefficients require a floating-point or complex dtype.") right = tuple(right_bits) if right_bits is not None else natural_right_bits(n) if len(right) != n // 2: @@ -114,28 +141,42 @@ def matrix_from_state_vector( state: ArrayLike, right_bits: Sequence[int] | None = None, ) -> NDArray: - """Return the bipartite coefficient matrix for an arbitrary state vector.""" + """Return C[a, b] in the same basis order as :func:`matrix_from_support`. + + The first position in each subsystem's bit list is its least significant + bit. The right reduced state is ``C.T @ C.conj()``; ``C.conj().T @ C`` + is its transpose and has the same spectrum, but generally different entries. + The vector need not be normalized. + """ _validate_even_n(n) vector = np.asarray(state) N = 1 << n if vector.shape != (N,): raise ValueError(f"state must have shape ({N},); received {vector.shape}.") + if vector.dtype.kind not in "biufc" or not np.all(np.isfinite(vector)): + raise ValueError("state must contain finite numeric amplitudes.") right = tuple(right_bits) if right_bits is not None else natural_right_bits(n) if len(right) != n // 2: raise ValueError(f"balanced bipartition requires {n // 2} right bits.") left = _left_bits(n, right) - left_axes = [n - 1 - bit for bit in left] - right_axes = [n - 1 - bit for bit in right] + # Reshape traverses axes from most to least significant within each index. + left_axes = [n - 1 - bit for bit in reversed(left)] + right_axes = [n - 1 - bit for bit in reversed(right)] tensor = vector.reshape((2,) * n) return np.transpose(tensor, left_axes + right_axes).reshape(1 << len(left), 1 << len(right)) def spectrum_from_matrix(matrix: ArrayLike, *, atol: float = 1e-14) -> NDArray[np.float64]: - """Return the non-zero eigenvalues of C†C using a stable SVD.""" + """Return normalized non-zero reduced-state eigenvalues using a stable SVD.""" + _validate_atol(atol) mat = np.asarray(matrix) + if mat.ndim != 2 or mat.size == 0: + raise ValueError("matrix must be a nonempty two-dimensional array.") + if mat.dtype.kind not in "biufc" or not np.all(np.isfinite(mat)): + raise ValueError("matrix must contain finite numeric coefficients.") singular_values = np.linalg.svd(mat, compute_uv=False) eigvals = np.real_if_close(singular_values * singular_values).astype(np.float64) eigvals[eigvals < atol] = 0.0 @@ -152,18 +193,41 @@ def renyi_entropy_from_spectrum( *, atol: float = 1e-14, ) -> float: - """Return the Rényi entropy in bits. order=1 gives von Neumann entropy.""" + """Return the Rényi entropy in bits; order=1 gives von Neumann entropy. - p = np.asarray(eigvals, dtype=np.float64) + A finite, nonnegative spectrum is normalized after entries at or below + ``atol`` are removed. Negative roundoff no smaller than ``-atol`` is allowed. + The order must be positive; positive infinity gives the min-entropy. + """ + + _validate_atol(atol) + if not isinstance(order, Real) or np.isnan(order) or order <= 0: + raise ValueError("Rényi order must be a positive real number or positive infinity.") + p = np.asarray(eigvals) + if p.ndim != 1 or p.size == 0 or p.dtype.kind not in "biuf": + raise ValueError("spectrum must be a nonempty one-dimensional array of real eigenvalues.") + p = p.astype(np.float64) + if not np.all(np.isfinite(p)) or np.any(p < -atol): + raise ValueError("spectrum must be finite and nonnegative within atol.") p = p[p > atol] + if p.size == 0: + raise ValueError("density-matrix spectrum has zero trace at the requested atol.") + # Scaling first avoids overflow when normalizing a finite input spectrum. + p = p / p.max() p = p / p.sum() - if np.isclose(order, 1.0): + if order == 1.0: return float(-np.sum(xlogy(p, p)) / np.log(2.0)) if np.isinf(order): return float(-np.log2(np.max(p))) - if order <= 0: - raise ValueError("Rényi order must be positive.") - return float(np.log2(np.sum(p**order)) / (1.0 - order)) + log_p = np.log(p) + if abs(order - 1.0) < 0.1: + # log(sum(p**order)) near one, without subtracting nearly equal numbers. + delta = np.sum(p * np.expm1((order - 1.0) * log_p)) + return float(np.log1p(delta) / ((1.0 - order) * np.log(2.0))) + log_max = np.max(log_p) + with np.errstate(over="ignore"): + tail = logsumexp(order * (log_p - log_max)) + return float((order / (1.0 - order) * log_max + tail / (1.0 - order)) / np.log(2.0)) def entropy_from_support( @@ -192,13 +256,13 @@ def qft_state_from_support(n: int, support: ArrayLike) -> NDArray[np.complex128] """Return the positive-exponent QFT of an equal-amplitude subset state. NumPy's ``ifft(..., norm='ortho')`` implements the convention - exp(+2πijk/N)/sqrt(N), matching the manuscript definition. For the real + exp(+2πijk/N)/sqrt(N), matching the research notes. For the real input states used here, switching the sign only complex-conjugates the output and therefore leaves all reported entropies unchanged. """ + support_arr = _validated_support(n, support) N = 1 << n - support_arr = np.asarray(support, dtype=np.int64) vector = np.zeros(N, dtype=np.complex128) vector[support_arr] = 1.0 / sqrt(support_arr.size) return np.fft.ifft(vector, norm="ortho") @@ -297,9 +361,9 @@ def hypergeometric_occupancy_approximation(n: int, m: int) -> float: """ _validate_even_n(n) - if m <= 0: + _validate_support_size(n, m, allow_zero=True) + if m == 0: return 0.0 - _validate_support_size(n, m) d = 1 << (n // 2) N = 1 << n w_min = max(0, m - (N - d)) @@ -326,7 +390,7 @@ def fixed_cardinality_average_purity(n: int, m: int) -> float: """Exact ensemble-average purity for the balanced fixed-cardinality ensemble. For N=2**n=d**2 and a support chosen uniformly among all M-element subsets, - this returns E[Tr(rho_R**2)] as derived in the manuscript. + this returns E[Tr(rho_R**2)] as derived in the research notes. """ _validate_even_n(n) @@ -356,17 +420,12 @@ class r modulo 2**t, then S <= n/2 - t + H(p). The case t=1 is the """ _validate_even_n(n) + if isinstance(matched_low_bits, (bool, np.bool_)) or not isinstance(matched_low_bits, Integral): + raise ValueError("matched_low_bits must be an integer.") t = int(matched_low_bits) if not (0 <= t <= n // 2): raise ValueError(f"matched_low_bits must lie in [0, {n // 2}].") - support_arr = np.asarray(support, dtype=np.int64) - if support_arr.ndim != 1 or support_arr.size == 0: - raise ValueError("support must be a nonempty one-dimensional array.") - N = 1 << n - if np.any(support_arr < 0) or np.any(support_arr >= N): - raise ValueError(f"support labels must lie in [0, {N - 1}].") - if np.unique(support_arr).size != support_arr.size: - raise ValueError("support contains duplicate basis labels.") + support_arr = _validated_support(n, support) modulus = 1 << t counts = np.bincount(support_arr % modulus, minlength=modulus).astype(float) probabilities = counts[counts > 0] / support_arr.size diff --git a/subset_states/csv_plotting.py b/subset_states/csv_plotting.py index c790b09..60f1f93 100644 --- a/subset_states/csv_plotting.py +++ b/subset_states/csv_plotting.py @@ -70,7 +70,7 @@ def _fit_line(x: np.ndarray, y: np.ndarray) -> dict: } -def plot_fig1(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None) -> None: +def plot_fig1(data_dir: str | Path, out_path: str | Path, *, n: int | None = None) -> None: """Plot the two averaging procedures with explicit entropy units.""" data_dir = Path(data_dir) @@ -121,10 +121,10 @@ def draw(axis, rows, markersize: float = 2.5): inset.set_xlabel(r"$M$", labelpad=1) inset.set_ylabel("bits", labelpad=1) inset.legend().remove() - save_figure(fig, out_pdf) + save_figure(fig, out_path) -def plot_fig2(data_dir: str | Path, out_pdf: str | Path, *, write_fit_summary: bool = True) -> None: +def plot_fig2(data_dir: str | Path, out_path: str | Path, *, write_fit_summary: bool = False) -> None: """Plot Table-I scaling, retaining all n=10,...,30 points.""" data_dir = Path(data_dir) @@ -143,7 +143,7 @@ def plot_fig2(data_dir: str | Path, out_pdf: str | Path, *, write_fit_summary: b fit_S = _fit_line(n, S_n) if write_fit_summary: fit_rows = [{"quantity": "log2_M_n", **fit_logM}, {"quantity": "S_n", **fit_S}] - write_rows(data_dir / "fig2_linear_fit_summary_from_csv.csv", fit_rows, fit_rows[0].keys()) + write_rows(Path(out_path).parent / "fig2_linear_fit_summary_from_csv.csv", fit_rows, fit_rows[0].keys()) apply_journal_style() fig, ax = plt.subplots(figsize=(4.7, 3.6)) @@ -172,10 +172,10 @@ def plot_fig2(data_dir: str | Path, out_pdf: str | Path, *, write_fit_summary: b ax.set_xticks([10, 15, 20, 25, 30]) ax.set_ylim(0, max(log2_M.max(), page.max()) + 1) ax.legend(frameon=False, loc="upper left") - save_figure(fig, out_pdf) + save_figure(fig, out_path) -def plot_fig3(data_dir: str | Path, out_pdf: str | Path, *, bins: int = 500) -> None: +def plot_fig3(data_dir: str | Path, out_path: str | Path, *, bins: int = 500) -> None: """Plot the spectral bulk and compare three isolated-mode estimates.""" data_dir = Path(data_dir) @@ -221,7 +221,7 @@ def plot_fig3(data_dir: str | Path, out_pdf: str | Path, *, bins: int = 500) -> inset.set_xlabel("isolated eigenvalue", labelpad=1) inset.tick_params(axis="y", labelsize=6.8) inset.tick_params(axis="x", labelsize=6.8) - save_figure(fig, out_pdf) + save_figure(fig, out_path) def _draw_fig4(axis, rows: Sequence[dict], n: int, label_data: bool) -> None: @@ -243,7 +243,7 @@ def _draw_fig4(axis, rows: Sequence[dict], n: int, label_data: bool) -> None: axis.plot(m, dense, "--", label=r"dense bulk $T_{N,M}$" if label_data else None) -def plot_fig4(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None) -> None: +def plot_fig4(data_dir: str | Path, out_path: str | Path, *, n: int | None = None) -> None: """Plot numerical data with corrected fixed-cardinality approximations.""" data_dir = Path(data_dir) @@ -267,10 +267,10 @@ def plot_fig4(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None inset.set_ylim(max(0, n / 2 - 3), n / 2) inset.set_xlabel(r"$M$", labelpad=1) inset.set_ylabel("bits", labelpad=1) - save_figure(fig, out_pdf) + save_figure(fig, out_path) -def plot_fig5(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None) -> None: +def plot_fig5(data_dir: str | Path, out_path: str | Path, *, n: int | None = None) -> None: """Compare deterministic arithmetic supports with the random null distribution. The shaded regions are one ensemble standard deviation. They represent the @@ -325,7 +325,7 @@ def plot_fig5(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None ax.set_xlim(0, 1 << n) ax.set_ylim(0, n / 2) ax.legend(frameon=False, loc="lower center", bbox_to_anchor=(0.5, -0.46), ncol=2) - save_figure(fig, out_pdf) + save_figure(fig, out_path) def _order_key(value) -> float: @@ -365,7 +365,7 @@ def _draw_fig6(axis, rows: Sequence[dict]) -> list: return handles -def plot_fig6(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None) -> None: +def plot_fig6(data_dir: str | Path, out_path: str | Path, *, n: int | None = None) -> None: data_dir = Path(data_dir) rows = read_csv_rows(data_dir / "fig6_renyi_summary.csv") zoom = read_csv_rows(data_dir / "fig6_renyi_zoom_summary.csv") @@ -392,7 +392,7 @@ def plot_fig6(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None labels = [r"$S^{(1)}$", r"$S^{(2)}$", r"$S^{(\infty)}$"] fig.legend(handles=handles, labels=labels, frameon=False, ncol=3, loc="lower center") fig.subplots_adjust(hspace=0.45, bottom=0.12) - save_figure(fig, out_pdf) + save_figure(fig, out_path) def _families(rows: Sequence[dict]) -> list[str]: @@ -404,7 +404,7 @@ def _families(rows: Sequence[dict]) -> list[str]: return seen -def plot_fig7(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None, bins: int = 100) -> None: +def plot_fig7(data_dir: str | Path, out_path: str | Path, *, n: int | None = None, bins: int = 100) -> None: """Plot both bipartition distributions on a common entropy scale.""" data_dir = Path(data_dir) @@ -462,7 +462,7 @@ def plot_fig7(data_dir: str | Path, out_pdf: str | Path, *, n: int | None = None ax.legend(frameon=False, loc="upper right") axes[-1].set_xlabel("entropy (bits)") fig.subplots_adjust(hspace=0.30) - save_figure(fig, out_pdf) + save_figure(fig, out_path) def _n_from_fig8_path(path: Path) -> int: @@ -474,7 +474,7 @@ def _n_from_fig8_path(path: Path) -> int: def plot_fig8( data_dir: str | Path, - out_pdf: str | Path, + out_path: str | Path, *, n_values: Sequence[int] | None = None, bins: int = 120, @@ -526,10 +526,10 @@ def plot_fig8( ax.set_title(rf"$n={n}$, $M={M}$") ax.legend(frameon=False) fig.subplots_adjust(hspace=0.55) - save_figure(fig, out_pdf) + save_figure(fig, out_path) -def plot_peak_search(samples_csv: str | Path, fit_csv: str | Path, out_pdf: str | Path) -> None: +def plot_peak_search(samples_csv: str | Path, fit_csv: str | Path, out_path: str | Path) -> None: samples = read_csv_rows(samples_csv) fit_rows = read_csv_rows(fit_csv) if not fit_rows: @@ -554,4 +554,4 @@ def plot_peak_search(samples_csv: str | Path, fit_csv: str | Path, out_pdf: str ax.set_xlabel(r"$\log_2 M$") ax.set_ylabel("entropy (bits)") ax.legend(frameon=False) - save_figure(fig, out_pdf) + save_figure(fig, out_path) diff --git a/subset_states/plotting.py b/subset_states/plotting.py index 55df510..1c0290a 100644 --- a/subset_states/plotting.py +++ b/subset_states/plotting.py @@ -41,8 +41,8 @@ def apply_journal_style() -> None: "ytick.labelsize": 8, "lines.linewidth": 1.15, "axes.prop_cycle": cycler(color=COOL_PALETTE), - "pdf.fonttype": 42, - "ps.fonttype": 42, + "text.usetex": False, + "savefig.dpi": 300, "savefig.bbox": "tight", } ) @@ -52,6 +52,4 @@ def save_figure(fig, path: str | Path) -> None: path = Path(path) path.parent.mkdir(parents=True, exist_ok=True) fig.savefig(path) - if path.suffix.lower() == ".pdf": - fig.savefig(path.with_suffix(".png"), dpi=300) plt.close(fig) diff --git a/tests/test_figure_workflow.py b/tests/test_figure_workflow.py new file mode 100644 index 0000000..8bc87d7 --- /dev/null +++ b/tests/test_figure_workflow.py @@ -0,0 +1,95 @@ +"""Regression checks for evidence-safe figure reproduction.""" +from __future__ import annotations + +import importlib.util +from pathlib import Path +import shutil +import subprocess +import sys +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[1] +SCRIPT = ROOT / "scripts" / "reproduce_publication_figures.py" +SPEC = importlib.util.spec_from_file_location("figure_workflow", SCRIPT) +workflow = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(workflow) + + +def option(command: list[str], name: str) -> Path: + return Path(command[command.index(name) + 1]) + + +class FigureWorkflowTests(unittest.TestCase): + def test_every_mode_separates_outputs_and_fig5_consumes_its_new_data(self): + with tempfile.TemporaryDirectory() as directory: + destination = Path(directory) / "new" + for mode in ("redraw", "smoke", "full"): + with self.subTest(mode=mode): + commands = workflow.build_commands(mode, destination) + for command in commands: + flag = "--out" if "--out" in command else "--outdir" + self.assertTrue(option(command, flag).is_relative_to(destination)) + if mode == "redraw": + self.assertEqual(len(commands), 7) + self.assertEqual(len({Path(command[1]).stem for command in commands}), 7) + self.assertTrue(all("from_csv" in command[1] or "fig5_qft_residue_controls" in command[1] for command in commands)) + else: + by_script = {Path(command[1]).name: command for command in commands} + plot = by_script["fig5_qft_residue_controls.py"] + for producer in ("regenerate_fig5_baseline.py", "run_residue_controls.py"): + self.assertEqual(option(by_script[producer], "--outdir"), option(plot, "--data-dir")) + self.assertLess(commands.index(by_script[producer]), commands.index(plot)) + + def test_existing_pngs_do_not_hide_a_missing_csv(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + released, data, out = root / "released", root / "data", root / "new" + for number, names in workflow.CSV_INPUTS.items(): + folder = data if number == 5 else released / f"fig{number}" + folder.mkdir(parents=True, exist_ok=True) + for name in names: + (folder / name).write_text("placeholder\n") + missing = released / "fig4" / "fig4_zoom_summary.csv" + missing.unlink() + for filename in workflow.FIGURE_FILES.values(): + path = out / filename + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(b"old figure") + result = subprocess.run([sys.executable, str(SCRIPT), "--released-dir", str(released), "--data-dir", str(data), "--outdir", str(out)], capture_output=True, text=True) + self.assertNotEqual(result.returncode, 0) + self.assertIn(str(missing), result.stderr) + self.assertNotIn("+ ", result.stdout) + self.assertTrue(all((out / name).read_bytes() == b"old figure" for name in workflow.FIGURE_FILES.values())) + + def test_evidence_destination_and_symlink_alias_are_rejected(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + evidence = root / "released" + evidence.mkdir() + alias = root / "alias" + alias.symlink_to(evidence, target_is_directory=True) + for destination in (root, evidence, evidence / "fig1", alias / "fig1"): + with self.subTest(destination=destination), self.assertRaises(ValueError): + workflow.validate_output_root(destination, evidence) + workflow.validate_output_root(root / "generated", evidence) + + def test_figure_two_redraw_keeps_input_directory_read_only(self): + from subset_states.csv_plotting import plot_fig2 + + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + source = root / "released" + source.mkdir() + name = "fig2_table_with_page.csv" + shutil.copy2(ROOT / "outputs" / "fig2" / name, source / name) + before = (source / name).read_bytes() + destination = root / "generated" / "figure.png" + plot_fig2(source, destination) + self.assertEqual(list(source.iterdir()), [source / name]) + self.assertEqual((source / name).read_bytes(), before) + self.assertTrue(destination.read_bytes().startswith(b"\x89PNG\r\n\x1a\n")) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_input_validation.py b/tests/test_input_validation.py new file mode 100644 index 0000000..e6160a1 --- /dev/null +++ b/tests/test_input_validation.py @@ -0,0 +1,139 @@ +from __future__ import annotations + +from decimal import Decimal, localcontext +from itertools import permutations +import unittest + +import numpy as np + +from subset_states.core import ( + fixed_cardinality_mean_spectrum, + hypergeometric_occupancy_approximation, + matrix_from_state_vector, + matrix_from_support, + qft_state_from_support, + renyi_entropy_from_spectrum, + residue_class_entropy_ceiling, + spectrum_from_matrix, +) + + +class SupportValidationTests(unittest.TestCase): + def test_support_apis_reject_malformed_labels_before_casting(self) -> None: + invalid = ( + [], [[1, 2]], 1, [1, 1], [-1], [16], [1.5], [1.0], + [True], [1j], [np.nan], [np.inf], ["1"], + np.asarray([2**64 - 1], dtype=np.uint64), + ) + functions = ( + lambda support: matrix_from_support(4, support), + lambda support: qft_state_from_support(4, support), + lambda support: residue_class_entropy_ceiling(4, support, 1), + ) + for support in invalid: + for function in functions: + with self.subTest(support=support, function=function): + with self.assertRaises(ValueError): + function(support) + + def test_qft_accepts_odd_qubit_count_and_preserves_norm(self) -> None: + support = np.asarray([0, 3, 7], dtype=np.uint64) + state = qft_state_from_support(3, support) + np.testing.assert_allclose(np.vdot(state, state), 1.0, atol=1e-14) + + def test_integer_parameters_are_not_silently_truncated(self) -> None: + for n in (0, -2, 4.0, True): + with self.subTest(n=n), self.assertRaises(ValueError): + qft_state_from_support(n, [0]) + for m in (1.5, True, -1): + for function in (fixed_cardinality_mean_spectrum, hypergeometric_occupancy_approximation): + with self.subTest(m=m, function=function), self.assertRaises(ValueError): + function(4, m) + for t in (1.5, True, -1, 3): + with self.subTest(t=t), self.assertRaises(ValueError): + residue_class_entropy_ceiling(4, [0, 1], t) + + def test_normalized_integer_dtype_cannot_silently_erase_amplitudes(self) -> None: + with self.assertRaises(ValueError): + matrix_from_support(4, [0, 1], dtype=int) + binary = matrix_from_support(4, [0, 1], normalize=False, dtype=int) + self.assertEqual(binary.sum(), 2) + + +class CoefficientMatrixTests(unittest.TestCase): + def test_vector_and_support_use_identical_basis_order(self) -> None: + support = [1, 4, 9, 15] + state = np.zeros(16) + state[support] = 1 / np.sqrt(len(support)) + for right in permutations(range(4), 2): + with self.subTest(right=right): + np.testing.assert_array_equal( + matrix_from_state_vector(4, state, right), + matrix_from_support(4, support, right), + ) + + def test_complex_coefficients_and_partial_trace_in_computational_basis(self) -> None: + state = np.arange(16) + 1j * np.arange(16)[::-1] ** 2 + state = state / np.linalg.norm(state) + expected_matrix = state.reshape(4, 4) + matrix = matrix_from_state_vector(4, state) + np.testing.assert_array_equal(matrix, expected_matrix) + expected_rho = np.zeros((4, 4), dtype=complex) + for a in range(4): + for b in range(4): + for c in range(4): + expected_rho[b, c] += state[4 * a + b] * state[4 * a + c].conjugate() + np.testing.assert_allclose(matrix.T @ matrix.conj(), expected_rho, atol=1e-15) + self.assertGreater(np.max(abs(matrix.conj().T @ matrix - expected_rho)), 0.01) + expected_spectrum = np.linalg.eigvalsh(expected_rho) + expected_spectrum = expected_spectrum[expected_spectrum > 1e-14] + np.testing.assert_allclose(spectrum_from_matrix(matrix), expected_spectrum, atol=1e-14) + + def test_partitions_and_state_values_are_validated(self) -> None: + for right in ((0, 0), (0, 4), (0, 1.5), (0, True)): + for function, data in ((matrix_from_state_vector, np.ones(16)), (matrix_from_support, [0])): + with self.subTest(right=right, function=function), self.assertRaises(ValueError): + function(4, data, right) + for state in (np.ones((4, 4)), np.full(16, np.nan), np.full(16, np.inf)): + with self.subTest(state=state), self.assertRaises(ValueError): + matrix_from_state_vector(4, state) + + +class SpectrumValidationTests(unittest.TestCase): + def test_invalid_spectra_and_orders_are_rejected(self) -> None: + for spectrum in ([], [0, 0], [-0.1, 1.1], [np.nan, 1], [np.inf, 1], [[0.5, 0.5]], [1j]): + with self.subTest(spectrum=spectrum), self.assertRaises(ValueError): + renyi_entropy_from_spectrum(spectrum) + for order in (0, -1, -np.inf, np.nan, 1j): + with self.subTest(order=order), self.assertRaises(ValueError): + renyi_entropy_from_spectrum([0.25, 0.75], order) + + def test_tolerated_roundoff_and_positive_infinite_order(self) -> None: + self.assertAlmostEqual(renyi_entropy_from_spectrum([-1e-16, 0.5, 0.5]), 1) + self.assertAlmostEqual(renyi_entropy_from_spectrum([0.25, 0.75], np.inf), -np.log2(0.75)) + + def test_finite_orders_do_not_underflow_or_collapse_to_order_one(self) -> None: + self.assertAlmostEqual(renyi_entropy_from_spectrum([0.5, 0.5], 2000), 1) + p = np.asarray([0.2, 0.8]) + order = 1.0 + 1e-6 + with localcontext() as context: + context.prec = 60 + alpha = Decimal.from_float(order) + expected = (Decimal("0.2") ** alpha + Decimal("0.8") ** alpha).ln() / ((1 - alpha) * Decimal(2).ln()) + computed = renyi_entropy_from_spectrum(p, order) + self.assertAlmostEqual(computed, float(expected), places=11) + self.assertGreater(abs(computed - renyi_entropy_from_spectrum(p, 1)), 1e-8) + self.assertAlmostEqual(renyi_entropy_from_spectrum(p, 1 + 1e-12), renyi_entropy_from_spectrum(p), places=11) + + def test_invalid_matrices_and_cutoffs_are_rejected(self) -> None: + for matrix in ([], [1, 2], np.zeros((2, 2)), [[np.nan]], [[np.inf]]): + with self.subTest(matrix=matrix), self.assertRaises(ValueError): + spectrum_from_matrix(matrix) + for atol in (-1, np.nan, np.inf): + for function, argument in ((spectrum_from_matrix, [[1]]), (renyi_entropy_from_spectrum, [1])): + with self.subTest(atol=atol, function=function), self.assertRaises(ValueError): + function(argument, atol=atol) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_validation.py b/tests/test_validation.py new file mode 100644 index 0000000..cc2eb07 --- /dev/null +++ b/tests/test_validation.py @@ -0,0 +1,172 @@ +"""Adversarial checks for scientific validators and evidence preservation.""" +from __future__ import annotations + +import contextlib +import csv +import io +import os +from pathlib import Path +import shutil +import subprocess +import sys +import tempfile +import unittest +from unittest import mock + +import numpy as np + +from scripts import final_scientific_validation as scientific +from scripts import validate_residue_results as residue + +ROOT = Path(__file__).resolve().parents[1] + + +class ValidationTests(unittest.TestCase): + def setUp(self) -> None: + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + self.root = Path(self.temporary.name) + + def copy_file(self, relative: str) -> Path: + path = self.root / relative + path.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(ROOT / relative, path) + return path + + def table_fixture(self) -> Path: + path = self.copy_file("data/table_i_peaks.csv") + self.copy_file("outputs/fig2/fig2_table_with_page.csv") + self.copy_file("outputs/fig2/fig2_linear_fit_summary.csv") + return path + + def residue_fixture(self) -> None: + for name in ("residue_matched_summary.csv", "residue_matched_samples.csv", "residue_entropy_bounds.csv"): + self.copy_file("data/" + name) + + @staticmethod + def mutate(path: Path, mutation) -> None: + with path.open(newline="") as handle: + reader = csv.DictReader(handle) + fields, rows = reader.fieldnames, list(reader) + mutation(rows) + with path.open("w", newline="") as handle: + writer = csv.DictWriter(handle, fieldnames=fields) + writer.writeheader() + writer.writerows(rows) + + def test_retained_table_and_derived_csv_agree(self) -> None: + self.table_fixture() + result = scientific.table_fit_checks(self.root) + self.assertEqual(result["table_rows_checked"], 11) + + def test_changed_table_value_is_not_hidden_by_constants(self) -> None: + path = self.table_fixture() + self.mutate(path, lambda rows: rows[0].update(S_n="4.073")) + with self.assertRaisesRegex(residue.ValidationError, "CSV and production defaults"): + scientific.table_fit_checks(self.root) + + def test_changed_derived_fit_is_rejected(self) -> None: + self.table_fixture() + path = self.root / "outputs/fig2/fig2_linear_fit_summary.csv" + self.mutate(path, lambda rows: rows[0].update(slope="0.75")) + with self.assertRaisesRegex(residue.ValidationError, "stored log2_M_n fit slope"): + scientific.table_fit_checks(self.root) + + def test_zero_cannot_replace_tiny_fit_p_value(self) -> None: + self.table_fixture() + path = self.root / "outputs/fig2/fig2_linear_fit_summary.csv" + self.mutate(path, lambda rows: rows[0].update(p_value="0")) + with self.assertRaisesRegex(residue.ValidationError, "p_value"): + scientific.table_fit_checks(self.root) + + def test_exhaustive_check_calls_production_formula(self) -> None: + result = scientific.exhaustive_checks((2,)) + self.assertEqual(result["supports_enumerated"], 15) + with mock.patch.object(scientific.core, "fixed_cardinality_average_purity", return_value=0.5): + with self.assertRaisesRegex(residue.ValidationError, "production average purity"): + scientific.exhaustive_checks((2,)) + + def test_nonfinite_production_output_is_rejected(self) -> None: + with mock.patch.object(scientific.core, "entropy_from_support", return_value=float("nan")): + with self.assertRaisesRegex(residue.ValidationError, "non-finite"): + scientific.exhaustive_checks((2,)) + + def test_all_recorded_residue_statistics_and_seed_prefix(self) -> None: + self.residue_fixture() + result = residue.residue_checks(self.root, replay_samples=1) + self.assertEqual(result["raw_rows_checked"], 12000) + self.assertEqual(result["seed_replayed_supports"], 12) + + def test_nonfinite_raw_entropy_is_rejected(self) -> None: + self.residue_fixture() + path = self.root / "data/residue_matched_samples.csv" + self.mutate(path, lambda rows: rows[0].update(position_entropy="nan")) + with self.assertRaisesRegex(residue.ValidationError, "non-finite"): + residue.residue_checks(self.root, replay_samples=0) + + def test_duplicate_sample_cannot_silently_replace_a_missing_sample(self) -> None: + self.residue_fixture() + path = self.root / "data/residue_matched_samples.csv" + self.mutate(path, lambda rows: rows[1].update(sample=rows[0]["sample"])) + with self.assertRaisesRegex(residue.ValidationError, "duplicate or missing sample"): + residue.residue_checks(self.root, replay_samples=0) + + def test_missing_group_cannot_shrink_validation_scope(self) -> None: + self.residue_fixture() + path = self.root / "data/residue_matched_summary.csv" + self.mutate(path, lambda rows: rows.pop()) + with self.assertRaisesRegex(residue.ValidationError, "12 recorded groups"): + residue.residue_checks(self.root, replay_samples=0) + + def test_summary_quantile_is_reconstructed_from_raw_samples(self) -> None: + self.residue_fixture() + path = self.root / "data/residue_matched_summary.csv" + self.mutate(path, lambda rows: rows[0].update(null_position_q025="5.0")) + with self.assertRaisesRegex(residue.ValidationError, "null_position_q025"): + residue.residue_checks(self.root, replay_samples=0) + + def test_replay_uses_production_sampler(self) -> None: + self.residue_fixture() + with mock.patch.object(residue, "sample_matched_support", return_value=np.array([0])): + with self.assertRaisesRegex(residue.ValidationError, "sampler cardinality"): + residue.residue_checks(self.root, replay_samples=1) + + def test_optimized_cli_still_rejects_corrupt_data(self) -> None: + path = self.table_fixture() + self.mutate(path, lambda rows: rows[0].update(S_n="nan")) + code = ( + "from pathlib import Path; import sys; " + "from scripts import final_scientific_validation as m; " + "original=m.table_fit_checks; root=Path(sys.argv[1]); " + "m.table_fit_checks=lambda: original(root); sys.argv=['validator']; " + "raise SystemExit(m.main())" + ) + for flag in ("-O", "-OO"): + with self.subTest(flag=flag): + process = subprocess.run([sys.executable, flag, "-c", code, str(self.root)], + cwd=ROOT, env={**os.environ, "OPENBLAS_NUM_THREADS": "1", "OMP_NUM_THREADS": "1"}, + capture_output=True, text=True, check=False) + self.assertEqual(process.returncode, 1, process.stderr) + self.assertIn("Status: FAIL", process.stderr) + self.assertIn("non-finite", process.stderr) + + def test_report_defaults_to_stdout_and_never_overwrites(self) -> None: + report = "# Test report\n\nChecked.\n" + with contextlib.redirect_stdout(io.StringIO()) as output: + residue.write_report(report, None) + self.assertEqual(output.getvalue().strip(), report.strip()) + path = self.root / "report.md" + with contextlib.redirect_stdout(io.StringIO()): + residue.write_report(report, path) + self.assertEqual(path.read_text(), report) + with self.assertRaisesRegex(residue.ValidationError, "overwrite"): + residue.write_report("changed", path) + self.assertEqual(path.read_text(), report) + with self.assertRaisesRegex(residue.ValidationError, "Markdown"): + residue.write_report(report, self.root / "report.txt") + with self.assertRaisesRegex(residue.ValidationError, "evidence directories"): + residue.write_report(report, ROOT / "data/new-validation-report.md") + + +if __name__ == "__main__": + unittest.main() diff --git a/validation/FINAL_SCIENTIFIC_VALIDATION.txt b/validation/FINAL_SCIENTIFIC_VALIDATION.txt deleted file mode 100644 index a94227e..0000000 --- a/validation/FINAL_SCIENTIFIC_VALIDATION.txt +++ /dev/null @@ -1,35 +0,0 @@ -FINAL SCIENTIFIC VALIDATION -============================= - -exhaustive_n4 -------------- -supports_enumerated: 65535 -max_mean_rho_error: 2.067790383364354e-14 -max_average_purity_error: 8.881784197001252e-16 -max_residue_bound_violation_t1: 0 -max_residue_bound_violation_t2: -0 -max_entropy_routine_difference: 5.551115123125783e-16 - -table_fits ----------- -S_slope: 0.5093 -S_intercept: -0.9900909090909144 -log2M_slope: 0.7035409513877944 -log2M_intercept: -0.3577343681481748 -page_gap_n10: 0.207474201201169 -page_gap_n30: 0.01565248033929123 -support_fraction_n10: 0.1044921875 -support_fraction_n30: 0.00171054620295763 - -dense_ansatz ------------- -max_old_new_difference: 2.664535259100376e-15 - -residue_controls ----------------- -max_residue_claim_rounding_error: 3.951718681866057e-07 -prime_parity_ceiling_bits: 6.006491631063628 -prime_forced_gap_bits: 0.9935083689363715 -all_six_strongest_controls_below_all_1000_nulls: 1 - -STATUS: PASS diff --git a/validation/REFERENCE_FINAL_SCIENTIFIC_VALIDATION.txt b/validation/REFERENCE_FINAL_SCIENTIFIC_VALIDATION.txt deleted file mode 100644 index a94227e..0000000 --- a/validation/REFERENCE_FINAL_SCIENTIFIC_VALIDATION.txt +++ /dev/null @@ -1,35 +0,0 @@ -FINAL SCIENTIFIC VALIDATION -============================= - -exhaustive_n4 -------------- -supports_enumerated: 65535 -max_mean_rho_error: 2.067790383364354e-14 -max_average_purity_error: 8.881784197001252e-16 -max_residue_bound_violation_t1: 0 -max_residue_bound_violation_t2: -0 -max_entropy_routine_difference: 5.551115123125783e-16 - -table_fits ----------- -S_slope: 0.5093 -S_intercept: -0.9900909090909144 -log2M_slope: 0.7035409513877944 -log2M_intercept: -0.3577343681481748 -page_gap_n10: 0.207474201201169 -page_gap_n30: 0.01565248033929123 -support_fraction_n10: 0.1044921875 -support_fraction_n30: 0.00171054620295763 - -dense_ansatz ------------- -max_old_new_difference: 2.664535259100376e-15 - -residue_controls ----------------- -max_residue_claim_rounding_error: 3.951718681866057e-07 -prime_parity_ceiling_bits: 6.006491631063628 -prime_forced_gap_bits: 0.9935083689363715 -all_six_strongest_controls_below_all_1000_nulls: 1 - -STATUS: PASS diff --git a/validation/RELEASE_VALIDATION.txt b/validation/RELEASE_VALIDATION.txt deleted file mode 100644 index 13a1241..0000000 --- a/validation/RELEASE_VALIDATION.txt +++ /dev/null @@ -1,17 +0,0 @@ -PUBLICATION RELEASE VALIDATION -============================== - -Date: 2026-08-18 -Python: 3.13.5 - -Checks completed: -- source compilation: PASS -- unit and regression tests: PASS -- independent final scientific validation: PASS -- Figure 2 regeneration: PASS -- Figure 5 redraw from released data: PASS -- all seven final PDF figures present: PASS - -This package is an overlay release candidate. Existing historical output CSVs in -the GitHub repository should be preserved by uploading over the current branch -rather than deleting the repository contents first. diff --git a/validation/SCIENTIFIC_SANITY_CHECKS.md b/validation/SCIENTIFIC_SANITY_CHECKS.md new file mode 100644 index 0000000..126e86e --- /dev/null +++ b/validation/SCIENTIFIC_SANITY_CHECKS.md @@ -0,0 +1,49 @@ +# Scientific sanity checks + +**Status: PASS for the checks listed below.** + +Exhaustive checks cover every nonempty support at n=2 and n=4 against production routines. Table I checks read the actual retained CSV and its derived outputs; they do not rerun the peak searches or validate an asymptotic law. The residue checks reconstruct all 12,000-row statistics and replay three seeded supports per group (36 total). Formula agreement does not establish the dense-bulk ansatz's approximation accuracy. Novelty remains a separate question. + +## Retained Table I consistency + +| Check | Result | +| --- | ---: | +| table rows checked | 11 | +| log2 M n slope | 0.703540951388 | +| log2 M n intercept | -0.357734368148 | +| S n slope | 0.5093 | +| S n intercept | -0.990090909091 | +| max derived table or fit error | 3.5527136788e-15 | + +## Exhaustive small systems + +| Check | Result | +| --- | ---: | +| supports enumerated | 65550 | +| max coefficient matrix error | 0 | +| max entropy error | 1.7763568394e-15 | +| max residue ceiling error | 0 | +| max mean spectrum error | 2.06779038336e-14 | +| max average purity error | 1.11022302463e-15 | +| max diagonal entropy error | 2.68673971959e-14 | +| max entropy lower bound error | 2.44249065418e-15 | +| max qft amplitude error | 2.77555756156e-16 | +| max qft entropy error | 3.33066907388e-16 | +| max entropy bound violation | 3.20342650381e-16 | + +## Dense-bulk formula implementation + +| Check | Result | +| --- | ---: | +| parameter pairs checked | 16660 | +| max formula error | 2.6645352591e-15 | + +## Residue-control evidence + +| Check | Result | +| --- | ---: | +| groups checked | 12 | +| raw rows checked | 12000 | +| max summary error | 3.5527136788e-15 | +| seed replayed supports | 36 | +| max seed replay entropy error | 2.6645352591e-15 | diff --git a/validation/evidence_sha256.json b/validation/evidence_sha256.json new file mode 100644 index 0000000..be5c05c --- /dev/null +++ b/validation/evidence_sha256.json @@ -0,0 +1,57 @@ +{ + "algorithm": "sha256", + "baseline_commit": "4cb99f109194124f500d75dd065ff43581a2682d", + "files": { + "LICENSE": "a69dda1ec276c8e819c340aacbdf4eb8d66ffeffcbd023f2cf6bc0b5bfc71d64", + "data/fig5_almost_prime_unions.csv": "177e0d34dc25db06e37bb6bd0597be186f3a2c6fa06c49852bd3ed1249a73418", + "data/fig5_random_qft_summary.csv": "dc9fad6dd669ff309622966b63648fc909b8b2eec86cb81469ad8332c14b84ca", + "data/peak_verification_schedule.csv": "d527a7661297d573083879e73bd313e2bf5470ea21ec8515cf5611bde19831f4", + "data/residue_entropy_bounds.csv": "58732b3b16d2596d61f2c87ed4956badba36e5ac5b25ebcbc93c248cd7023e7b", + "data/residue_matched_samples.csv": "f6a12c9bed9bb2a03523ed9a8dc5f275122f86664b047ce27179d24d50cf5f31", + "data/residue_matched_summary.csv": "43e35efeb054e216928d319243c1107efe5707ca1e3e9c8780f4380593ebdee3", + "data/table_i_peaks.csv": "2412f162f2b6901202423f85ee777be95682b2cc43e311bb52a651df193aecae", + "outputs/fig1/fig1_concentration.png": "28b0af1283a69ec4aa2bac97ba5925376255f98fab463ce8599974be9967de59", + "outputs/fig1/fig1_raw.csv": "25c35027366bd376527fb12b365ad7f92211d606862d47b503337b6d8da63455", + "outputs/fig1/fig1_summary.csv": "e898e2f2db35a1dcdcde87b485b842cb0717d8f80b776e90b9ade9d19e4b1d44", + "outputs/fig1/fig1_zoom_raw.csv": "12d1b735b183a828df9dc21f80d3014e0509f2435d46a24a270cf6a792cd69aa", + "outputs/fig1/fig1_zoom_summary.csv": "d91c629336ba0011f77dbbd2fe621065a49bb4de78c29dd5e81b51ffa01fca1a", + "outputs/fig2/fig2_linear_fit_summary.csv": "9884ed618dbb393fa43aab7e8cf28fd0b24c4fb8fc18c1b1e34b2911fab4707f", + "outputs/fig2/fig2_peak_scaling.png": "ca22d149b1eb819cf1c18eb983167eaab572ee168820b5ee0b38e263ca622691", + "outputs/fig2/fig2_table_with_page.csv": "c2dcc97bd9ad5976e8a16c9fd103eaa99ba3b481abd1ea73a886bf89e4857f59", + "outputs/fig3/fig3_spectral_bulk.png": "58b84b12b53d3b7f96b183f3713b11d137d1cc5892f91be61be43958eacd542e", + "outputs/fig3/fig3_spectrum.csv": "cf8ace7de5818d52fea0d3c206eaf0c17963d939274b56c9e695a975cf3e8db8", + "outputs/fig3/fig3_spectrum_summary.csv": "bf3ed56ac1bdfeb6c6e40ed31478fa5f7d85f431b2061c6383f46f58336be7f2", + "outputs/fig4/fig4_approximation.png": "8fd16588599ec014fc53010945c1b56794bd022f6edbd6b829a5fbf8d4b51037", + "outputs/fig4/fig4_summary.csv": "bc400df3c29622bee9ee13da4c48898746c303d75c4e2e87fffe40fab7f65935", + "outputs/fig4/fig4_zoom_summary.csv": "de98ae3f86dd5a37d397031e6f19451b12924e73d6a9b5d5bbff832eecb1fd11", + "outputs/fig5/fig5_almost_prime_unions.csv": "f3abe84233aa7d8453503e0be79fb6198de457da97f556dc163ed78847faa937", + "outputs/fig5/fig5_qft_residue_controls.png": "e9ec19a64d04a914ff771f90e61a35a942adcb761cf12723548c9060029c6f7a", + "outputs/fig5/fig5_random_qft_summary.csv": "c08ac235b3e9472aceaef3c636d50d4ad1c4db7f246797e043e9e3b1a4d86a70", + "outputs/fig6/fig6_renyi.png": "33ee3b47ad429647999c7ee3bbf2ca5f36d30c94cf5fd697c29b5ffb0a213a4b", + "outputs/fig6/fig6_renyi_summary.csv": "7f8e64c047c5427c659dfff73fa219927d7478468dd925aac72cf90a3f9f60e0", + "outputs/fig6/fig6_renyi_zoom_summary.csv": "540ac3a7b46293ad7103d3c79d694c4a83ec206cd2ff3e551d270f7e16ecf90f", + "outputs/fig7/fig7_partition_samples.csv": "6ce8e29a5cb4d0139d2e9e1200688fd9be186a92de9e4e9da08faaf76e73f9a7", + "outputs/fig7/fig7_partition_summary.csv": "5afc21d65aeaa0ae2eb8410d445e4960bede0f184ae3d90a52ee874a7e7dd425", + "outputs/fig7/fig7_partitions.png": "3e01bb55f826dd5b059354d63962689f8a48c42456a9cccac8cd66ff13830b6e", + "outputs/peak_verification/peak_verification_n10.png": "35d856494c607b153dee58c0570a0a9360784727f6319d8dbd001bc4f91a9a81", + "outputs/peak_verification/peak_verification_n10_fit.csv": "5b76e14c4a7e0731ac4ae22f79ef2a7fed96f0837fed45e479ec9661cba1c292", + "outputs/peak_verification/peak_verification_n10_samples.csv": "e9526315250aae7327ac4624929add981ddffc57ef809c4a7effaafe876498a4", + "outputs/peak_verification/peak_verification_n12.png": "4903c423ee0055169cc46daff9e5a76b00a65a664491ae476b1a19236ff5c295", + "outputs/peak_verification/peak_verification_n12_fit.csv": "48fb372e58be43cc916885343c7ea2924ad23a5d10dbd827dd00271becd7def0", + "outputs/peak_verification/peak_verification_n12_samples.csv": "cc4584c5cf0f8d925098f04d9c8324d364332dd1f1b1a9c5f53167f477b54a1f", + "outputs/peak_verification/peak_verification_n14.png": "ea2b6feb1e100dca65e1003ef6d8c55cf86186d00837f3483509da596d3f7b89", + "outputs/peak_verification/peak_verification_n14_fit.csv": "a8f1d30d5b62bed9cedb777950e59fc7d87d350ad96e9eca55864fbf460a58ec", + "outputs/peak_verification/peak_verification_n14_samples.csv": "112cd6bbf8253052cc2ca7b748007fa7fd5a7a84cc88e6ff038f325f84226cc1", + "outputs/peak_verification/peak_verification_n16.png": "a4941f80388b274ffc30d3f1198f1706b20491f40873c4498776b6d9a9c48933", + "outputs/peak_verification/peak_verification_n16_fit.csv": "cb9686603168d755e72b940c5fc153b6e56929bba0053edf03e112cc39974d77", + "outputs/peak_verification/peak_verification_n16_samples.csv": "4e9bf5383a0cb7e5ee778304460c07f9af59640d1b6a46b0491de1aec20ae78c", + "outputs/peak_verification/peak_verification_n18.png": "47d2e59c22d11d3e250909ff1d2d7b162e03073b30ed1c4eb56e3daa1e91326c", + "outputs/peak_verification/peak_verification_n18_fit.csv": "7f576cb540caf8cd7953d0db4c02b6e68715d35c60589922011223d4708c7c9a", + "outputs/peak_verification/peak_verification_n18_samples.csv": "b149f773f7ad582e886bc44566b2d406385068a1363899d52183406e3724d9a1", + "outputs/peak_verification/peak_verification_n20.png": "1192700001850167069c8ef752dcc1a26b45a3b28cc331b2d9376283fca12779", + "outputs/peak_verification/peak_verification_n20_fit.csv": "6ff25aa3fb955e39ae8f1a5be04f1f3b516839ddfbb65e68b8177dd1a8902fe0", + "outputs/peak_verification/peak_verification_n20_samples.csv": "81bfc8a7ff9496b566ac5eaa5f444aced13c11d2c5e751b99c21d275566bac80", + "outputs/peak_verification/peak_verification_summary.csv": "176b037441c910c6da0bc2edfd37a2f8302afc308cc82bfd6e56baf1368175b2", + "outputs/peak_verification/peak_verification_summary.png": "91093b361683327f39dbd9bfa0f981dc1e52d51b5684d78f2756ca5062f3e16e" + } +}