diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2213b5..0d8df36 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,5 +41,20 @@ jobs: run: python photon/census.py - name: report the ampoule from the committed tallies (no OpenMC, no network) run: python ampoule/report.py + - name: compile the instance onto the measured vessel and close its timing + run: python ampoule/compile.py - name: rebuild index.html run: python build_html.py + - name: run the tests (prose against computed numbers, links, style, physics, the manifest) + run: pip install pytest && python -m pytest -q tests + - name: verify that every number, table and vector figure came back byte for byte + run: | + changed=$(git status --porcelain --untracked-files=all | grep -v -i '\.png$' || true) + if [ -n "$changed" ]; then + echo "the tree is not the same after regeneration:"; echo "$changed" + git --no-pager diff --stat -- . ':(exclude)*.png' + echo "what moved in the text outputs:" + git --no-pager diff -- '*.md' '*.csv' '*.txt' '*.json' '*.cff' | head -300 + exit 1 + fi + echo "the tree is the same after regeneration" diff --git a/.gitignore b/.gitignore index 9d91966..1c627f7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ neutron/data/ neutron/work/ photon/cache/ ampoule/work/ +.venv/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fcc5b5d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,37 @@ +# Changelog + +Every release of this repository is archived on Zenodo under the concept DOI [10.5281/zenodo.21330486](https://doi.org/10.5281/zenodo.21330486); the version DOI of each release is on its Zenodo record. + +## 1.1.0: the second edition + +The founding edition stated the theory, evaluated its criterion against the nuclear data record, and specified the device. This edition computes the machine: the keystone in the neutron sector in real neutron transport, the photon sector keystone searched for in ENSDF, the sealed vessel in real photon transport, and the compiler run on what that transport measured. It also makes the repository's oldest promise, that every number regenerates from public data, into a checked one. + +### New results + +- **The neutron gate, computed** ([neutron/](neutron/)). The two region subcritical gate of theory Section 4 built in OpenMC with the official ENDF/B-VIII.0 library, calibrated first against three ICSBEP handbook criticals: the fission matrix and its eigenvalue check, a drain of 1.49 fission neutrons per driver neutron with the gate open, the transfer curves of two absorbers, superposition to 0.6 percent, level restoration to a total variation of 0.002 across a thermal to 14 MeV input range, the clock (Λ = 106 µs, 1/Λ = 9.4 kHz), and the temperature coefficient that prices the sector's only veto. The convergence trap of weakly coupled regions is on the record with its remedy. +- **The photon keystone, searched** ([photon/](photon/)). Every gateway of the 415 isomers that hold a bit for a second, in observed and allowed classes, with its release cascade; the level restoring pairs of theory Section 2 counted (12470 candidates, none the data can resolve, all behind the areal density wall); the veto gateway that gives isomers the inhibition the neutron sector lacks (214 isomers); the NEEC class as the Phase B1 target list. +- **The ampoule, transported** ([ampoule/](ampoule/)). The sealed vessel of the machine and build notes in OpenMC photon transport, driven by its own ⁹⁰Sr and ⁹⁰Y beta spectra: the photon budget, the site rates in plastic and CsI, the collar's transfer curve, the 64 × 64 Green's function and the septum's effect on it, the boundary count, the energy budget and the dose outside. The notes are amended where the numbers say so. +- **The vessel, compiled** ([ampoule/compile.py](ampoule/compile.py), [figure 18](figures/fig18_compiled.svg)). The compiler of theory Section 11 run on the measured Green's function: the fabric read as solid angle times an interaction probability; Way B placing the twin's instance on the vessel's lattice and the fabric's unaperturable couplings burying it, with the collar pass as the last compilation step; the 64 site law checked against an exact transfer matrix at 3.3 sweeps per independent sample; and the timing closure, every weight a photon current, which prices the vessel as built at 0.34 independent samples per second against the 38,462 the machine note priced on proposals alone, with the ladder of measured and catalogue levers between the two. Theory Section 11.5 and the reset ledger of Section 3.1 gain the synapse term; the machine note, the build note and the ENIAC ledger are amended. + +### The repository as an instrument + +- `reproduce.py` runs every step in the CI's order and, with `--check`, fails unless every number, table and vector figure came back byte for byte. The CI now runs the same check on every push. +- `tests/`: the documents' headline numbers read back from the files that compute them (the class of drift the 1.0.1 erratum corrected), every internal link resolved, the house style enforced (no dashes in prose, isotopes as superscripts, no edition notes inside the documents), the instruments checked against things that are not themselves (the beta spectra against ICRP 107, the transfer matrix against enumeration, the sampler against its exact law, the adjoint against finite differences, the committed fission matrix against the committed eigenvalue), and the committed inputs against a manifest. +- `requirements.txt` is pinned. Under the pin the numbers reproduce byte for byte on macOS and Linux; the vector figures do too, now that the two that did not (a cancellation in the Siegert integrand, an embedded raster in the ampoule figure) are drawn in a platform independent form. Raster PNGs are regenerated but not compared. +- `Dockerfile`: the OpenMC 0.16.0 environment of the two transport directories, the image the neutron README referred to, for the x86-64 platform conda-forge builds it on. +- `data-manifest.sha256` and [DATA.md](DATA.md): every committed input with its digest and its source; the two compressed tables are written without a timestamp so they reproduce. +- [GLOSSARY.md](GLOSSARY.md): the terms the work coins, each with the place it is defined. +- The finite difference check of the adjoint compiler uses a step where truncation rather than rounding dominates the residual, and reports the bound the residual satisfies (below 10⁻⁷) rather than digits that depend on which BLAS inverted the matrix, so it reads the same on every platform. +- `CITATION.cff` carries the version. + +### Corrections + +- Hyphenated isotope designations in the transport documents are written as superscripts (²⁵²Cf), as the rest of the work does. + +## 1.0.1: error corrections (2026-08-01) + +- The ¹⁸⁰ᵐTa excitation energy corrected to the NUBASE2020 evaluated value, 75.3 keV, and the leverage figure derived from it, 0.075. The curated candidate table carried the superseded 77.1 keV value while the generated catalogue already read 75.3. + +## 1.0.0: the founding release (2026-07-13) + +The theory: the model, the gate set, the physical limits, the complexity ceiling, and the whole feasibility question concentrated into one falsifiable component, the keystone gate, judged by three inequalities. The criterion run against every isomer in NUBASE2020 and evaluated against ENSDF. The routine gates verified to Monte Carlo precision, the digital twin run decay by decay against exact enumeration, the compiler three ways, the degree checker. The reference transistor at three scales with its datasheet, the sealed ampoule with its build note, the valve, the component inventory, the metabolism and the ENIAC ledger. Seven executable instruments, a CI that recomputes every number, and a Zenodo archive. diff --git a/CITATION.cff b/CITATION.cff index d578774..7cb79b6 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,4 +1,5 @@ cff-version: 1.2.0 +version: 1.1.0 message: "If you use or build on this theory, please cite it as below." title: "Nuclear Compute: Power, Logic, Memory, and Interconnect in One Radioactive Medium" authors: diff --git a/DATA.md b/DATA.md new file mode 100644 index 0000000..331e2b3 --- /dev/null +++ b/DATA.md @@ -0,0 +1,33 @@ +# Data: where every input comes from + +Every number in this repository descends from public nuclear data through the scripts in the tree. The inputs the scripts read are either committed here, so that everything reproduces offline, or fetched from an official archive by a script that verifies what it fetched. This page names each one. The committed inputs are listed with their SHA-256 digests in [data-manifest.sha256](data-manifest.sha256), and a test fails if any of them changes without the manifest. + +## Committed inputs + +| file | what it is | source | read by | +|---|---|---|---| +| `gates/data/nubase_4.mas20.txt` | NUBASE2020, the evaluation of nuclear and decay properties of every known nuclide and isomer | Kondev, Wang, Huang, Naimi, Audi, Chin. Phys. C 45, 030001 (2021); IAEA AMDC | `gates/isomer_screen.py`, `photon/ensdf.py` | +| `gates/data/decay_g_*.csv` | decay radiation (gamma) tables for the curated candidate isomers, from ENSDF | IAEA Live Chart of Nuclides, `fields=decay_rads` | `gates/isomer_screen.py` | +| `photon/levels.json.gz` | the adopted levels and gammas of the 544 nuclides carrying an isomer that holds a bit for at least a second, packed | IAEA Live Chart of Nuclides (ENSDF), fetched and packed by `photon/ensdf.py` | `photon/census.py` | +| `neutron/tallies.json`, `neutron/benchmarks.json` | the raw tallies of the two region gate protocol and the three handbook benchmarks, with Monte Carlo uncertainties | OpenMC 0.16.0 with ENDF/B-VIII.0, run by `neutron/gate.py` and `neutron/benchmarks.py` | `neutron/report.py` | +| `ampoule/tallies.json`, `ampoule/calibration.json` | the raw tallies of the vessel in photon transport, and the instrument's calibration against XCOM, the exponential and the thick target rule | OpenMC 0.16.0 with ENDF/B-VIII.0 photoatomic data, run by `ampoule/model.py` and `ampoule/calibrate.py` | `ampoule/report.py`, `ampoule/compile.py` | + +## Fetched inputs + +| what | source | fetched by | verified how | +|---|---|---|---| +| the ENDF/B-VIII.0 library in OpenMC's HDF5 form (the files the two transport directories use, about 2 GB of a 3.4 GB archive) | openmc.org, the official distribution | `neutron/data.py`, streamed once into `neutron/data/` (ignored by git) or `NC_DATA_DIR` | `python neutron/data.py --verify`, and the three ICSBEP handbook criticals in `neutron/benchmarks.py` | +| the raw level and gamma CSVs behind `photon/levels.json.gz` | IAEA Live Chart of Nuclides | `photon/ensdf.py`, cached in `photon/cache/` (ignored by git) | the packed file is committed; the census reproduces from it offline | + +## Reference values quoted from the literature + +Handbook eigenvalues and the JEFF-3.1 results on the same cases are from OECD/NEA JEFF Report 21, Appendix 2, with geometries as transcribed in the MIT CRPG benchmark collection. NIST XCOM attenuation coefficients, the ICRP 107 beta mean energies and the ICRP 116 dose coefficients are carried inside the scripts and tally files that use them, with their citations. The ²²⁹Th transition frequency, the NEEC and IGE literature, and the probabilistic hardware benchmark are cited in the [README](README.md) references. + +## Reproducing everything + +``` +pip install -r requirements.txt +python reproduce.py --check +``` + +runs every step in the order the CI does and reports whether every number, table and vector figure came back byte for byte. The OpenMC runs that regenerate the two tally sets are in `.github/workflows/openmc.yml` and, for a local machine, the [Dockerfile](Dockerfile). diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9939690 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenMC environment of neutron/ and ampoule/: the same OpenMC 0.16.0 +# from conda-forge that the openmc.yml workflow installs, with the Python +# packages every other script in the repository needs. The nuclear data is +# not in the image; neutron/data.py streams the official ENDF/B-VIII.0 +# archive into a directory you mount at /data (about 2 GB, once). conda-forge +# builds OpenMC 0.16.0 for x86-64 only, so the image is pinned to that +# platform; on an Apple silicon Mac Docker runs it under emulation, slowly, +# and the emulated BLAS spins unless its threads are pinned, so add +# -e OPENBLAS_NUM_THREADS=1 to docker run there (on an x86-64 host leave +# the threads alone: OpenMC uses them). The transport runs themselves are +# best left to an x86-64 machine or to .github/workflows/openmc.yml. +# +# docker build -t nuclear-compute . +# docker run --rm -v "$PWD:/repo" -v "$HOME/nc-data:/data" nuclear-compute \ +# bash -c "python neutron/data.py --verify && python neutron/gate.py --quick && python neutron/report.py" +# +# Everything that needs no OpenMC runs in the same image too: +# +# docker run --rm -v "$PWD:/repo" nuclear-compute python reproduce.py +FROM --platform=linux/amd64 mambaorg/micromamba:1.5.10 +ARG MAMBA_DOCKERFILE_ACTIVATE=1 +RUN micromamba install -y -n base -c conda-forge \ + python=3.12 "openmc=0.16.0=*nompi*" numpy matplotlib h5py markdown pytest \ + && micromamba clean --all --yes +ENV NC_DATA_DIR=/data +WORKDIR /repo +CMD ["python", "reproduce.py"] diff --git a/GLOSSARY.md b/GLOSSARY.md new file mode 100644 index 0000000..00f6a29 --- /dev/null +++ b/GLOSSARY.md @@ -0,0 +1,46 @@ +# Glossary + +The terms this work coins or uses in a fixed sense, each with the place it is defined. The physics is in those places; this page is the index to it. + +| term | meaning | where | +|---|---|---| +| nuclear compute | the model of computation in which a radiation field and the nuclear states it drives are the processor, the memory and the interconnect, and the decay of the same medium is the power supply; *nuclear computing* is the field, *Nuclear Compute* the work | [README](README.md), the thesis and the nomenclature | +| the two governing equations | radiation transport with field dependent cross sections (the wiring and the weighted sum) coupled to nuclear kinetics with a field triggered release term (the gate and the memory) | [README](README.md), the dynamics | +| the synapse | the linear part of transport with cross sections frozen: φ_out = 𝒢 φ_in, the Green's function as a weight matrix | [README](README.md), the gate set; [theory 5.3](theory/THEORY.md) | +| the routine gates | coincidence AND (a multiplier), scattering MUX (a weighted add), absorption NOT (a complement), and the saturable soft threshold: all demonstrated physics, none with gain | [README](README.md), the gate set; [transport](transport/) | +| the keystone | the triggered release gate with gain: an isomer released by a control field with more usable quanta out than control quanta in; the one component of the model not demonstrated in a compact state | [README](README.md), the keystone gate criterion | +| the keystone criterion | three inequalities: the leak condition η > ½, the amplification condition Γ > 1, and the rate condition R_trig ≳ f_gate; existence is the first two, usefulness the third | [README](README.md); [theory 1](theory/THEORY.md) | +| the areal density wall | the requirement N_A > 1/(β σ_trig) that a slab gate places on inverted nuclei per cm², which every level restoring candidate in ENSDF meets by orders of magnitude | [theory 1.1](theory/THEORY.md); [photon](photon/) | +| level restoration | a gate's output being of the kind and energy that trigger the next gate, with the released energy and not the input setting the output scale; self restoring (fission), convertible (heterogeneous isomer pairs) or terminal | [theory 2](theory/THEORY.md) | +| the convertible class | pairs of isomers whose release lines and gateway absorptions are mutually resonant; counted in ENSDF as 12470 candidates the data cannot resolve and none that survive the areal density wall | [theory 2](theory/THEORY.md); [photon](photon/) | +| a gateway | a level above an isomer that a photon or a captured electron can lift it into; observed where ENSDF lists the line, allowed where spin and parity permit it and the line is unobserved | [photon](photon/README.md) | +| the NEEC class | releasing gateways within 30 keV of their isomer, whose triggers are electron capture resonances; 34 in the chart, the Phase B1 target list | [photon](photon/results.md) | +| the veto gateway | a second releasing gateway whose cascade bypasses the signal line, so that opening it empties the register without producing the signal: inhibition native to isomers | [photon](photon/results.md); [theory 2](theory/THEORY.md) | +| the neutron sector | the keystone as it already exists: a subcritical multiplying region is a triggered release gate with gain 1/(1 − k), coupled regions are the synapse with gain on the diagonal, fission neutrons are level restoring | [theory 4](theory/THEORY.md); [neutron](neutron/) | +| the photon sector | the same criterion applied to isomers triggered by photons or electrons, where gain is unproven and the miniaturisation program lives | [README](README.md), the central tension | +| the fission matrix | Avery's coupling coefficients K_ij, fission neutrons born in region i per fission neutron born in region j, computed one generation at a time; its dominant eigenvalue tests the two region reduction | [neutron](neutron/results.md) | +| the tilt mode | the antisymmetric mode of two weakly coupled regions, whose dominance ratio approaches one as the coupling weakens and which the Shannon entropy is nearly blind to | [neutron](neutron/results.md), Section 3.1 | +| the precision law | b bits of a rate cost 2²ᵇ counts (Poisson, Cramér Rao); throughput is bought with activity | [README](README.md), physical limits; [theory 5.6](theory/THEORY.md) | +| the throughput law | a network sharing an event budget λ sustains at most λ/2²ᵇ gate evaluations per second at b bits | [README](README.md), physical limits | +| ops per decay | the figure of merit: computation extracted per event that was going to be paid for anyway, against C_eval and not C_in alone | [README](README.md), energy honesty; [theory 3.1](theory/THEORY.md) | +| the pile up ceiling | activity must be spread over n ≳ λ τ_d interaction sites or events merge | [theory 3.2](theory/THEORY.md) | +| the digital twin | the Tier 1 machine run decay by decay in software: thinned Poisson proposals, the frozen Green's function as the weighted sum, the soft threshold as the acceptance, checked against the exact Boltzmann law | [simulator](simulator/) | +| the Bernstein construction | feed forward universality without the keystone: any continuous function on [0, 1] as a Bernstein polynomial of thinning, coincidence and MUX | [theory 6](theory/THEORY.md) | +| coincidence degree | the power of the activity a signal scales with: a thinned stream has degree 1, a coincidence adds degrees, MUX and absorption preserve them | [theory 7](theory/THEORY.md) | +| degree homogeneity | the theorem that a decision comparing like degree signals is invariant under global scaling of the activity, so a sealed machine slows without becoming wrong; the design rule is compare like degree only with like | [theory 7](theory/THEORY.md); [transport/degree_check.py](transport/degree_check.py) | +| the isolation lemma | every fan out is a fresh thinning, never a copy, and then error does not compound with depth; only the bill does | [theory 10.1](theory/THEORY.md) | +| the boundary | the skin of the machine: outputs as counts, currents and spectra, inputs as apertures, Doppler drives, Zeeman maps and beams; the no penetration principle | [theory 8](theory/THEORY.md) | +| energy division multiplexing | distinct emission lines as orthogonal channels through one window; the computed channel plan | [gates/edm_channels.md](gates/edm_channels.md) | +| the reference transistor | the unit of the machine at three scales with one pinout: the benchtop cell, the crystal cell and the neutron gate, with gate, source, drain, channel and body | [transistor](transistor/README.md) | +| the valve | a resonant absorber foil in a beam from its matched parent, gated by a coil or a Doppler drive: a field effect pass transistor at 14.4 keV, available from catalogues | [transistor/VALVE.md](transistor/VALVE.md) | +| the gain bandwidth theorem | M × 1/τ_switch = 1/Λ for the subcritical gate: the op amp law from reactor kinetics, 9.4 kHz measured for the solution tanks | [transistor](transistor/README.md); [neutron](neutron/results.md) | +| the ampoule | the sealed machine: five shells, no penetrations, powered, clocked and randomised by its own inventory, programmed through the wall by fields, read by its glow | [transistor/SEALED.md](transistor/SEALED.md) | +| the nuclear lamp | a parent isotope that decays into the working transition emits the daughter's line at natural width: bandwidth ratio one, the fix for the broadband lamp that cannot write | [theory 9](theory/THEORY.md) | +| the addressed long retention write | the open problem of a state that is parent fed, gradient addressable and long lived at once | [theory 9.4](theory/THEORY.md), Open Problem 6 | +| the compiler | the algorithm from a target weight matrix to a material layout, three ways: Way A adjoint descent, Way B the crossbar, Way C self calibration through the wall | [theory 11](theory/THEORY.md); [transport/compiler_demo.py](transport/compiler_demo.py) | +| the fabric | the Green's function a vessel offers before any instance is placed on it; for the transported ampoule, solid angle times an interaction probability | [ampoule/compile_results.md](ampoule/compile_results.md) | +| the collar pass | subtracting the predictable mean of the fabric's crosstalk from every bias through the collar openings, the compiler's last pass on a diffusive shell | [ampoule/compile_results.md](ampoule/compile_results.md) | +| timing closure | the pricing of every weight as a photon current and every read as 2²ᵇ of those photons; the vessel's sample rate as built | [ampoule/compile_results.md](ampoule/compile_results.md); [theory 11.5](theory/THEORY.md) | +| the ENIAC ledger | every component with its lever, its ceiling and whose industrial curve improves it | [transistor/SCALING.md](transistor/SCALING.md) | +| the kill criteria | the falsifiable failure conditions of the roadmap: A for the stochastic tier, B for the keystone, C for Tier 2 coherence | [README](README.md), the roadmap | +| a claim and its test | the form every issue in this repository takes: one falsifiable sentence and the measurement, calculation or dataset that settles it | [.github/ISSUE_TEMPLATE](.github/ISSUE_TEMPLATE/claim-and-test.md) | diff --git a/README.md b/README.md index a13eeed..6736ffe 100644 --- a/README.md +++ b/README.md @@ -309,7 +309,7 @@ Every component except one is either routine nuclear physics or recently demonst | [simulator/](simulator/) | the digital twin: a Tier 1 machine run decay by decay, validated against exact enumeration, with decays per sample and energy per sample measured | | [neutron/](neutron/) | the keystone at reactor scale, computed: the two region subcritical gate in OpenMC with the official ENDF/B-VIII.0 library, calibrated against three ICSBEP handbook criticals; gain, the fission matrix and its eigenvalue check, transfer curves under two absorbers, the truth tables, the superposition check, level restoration spectra, the clock and gain bandwidth product, and the temperature coefficient that prices the veto | | [photon/](photon/) | the photon keystone searched for in ENSDF: every gateway of every isomer that holds a bit for a second, in observed and allowed classes, with its release cascade; every level restoring coincidence within rotor reach and the areal density wall each one meets; every isomer with a signal gateway and a veto gateway; the NEEC class ranked | -| [ampoule/](ampoule/) | the sealed machine in real photon transport: the vessel of the build note in OpenMC with ENDF/B-VIII.0 photoatomic data and its own beta spectra, calibrated against XCOM and the thick target rule; the photon budget, site rates in plastic and in CsI, pile up, the collar's transfer curve, the 64 × 64 Green's function and what the septum does to it, the boundary count rate, the energy budget, and the dose outside | +| [ampoule/](ampoule/) | the sealed machine in real photon transport: the vessel of the build note in OpenMC with ENDF/B-VIII.0 photoatomic data and its own beta spectra, calibrated against XCOM and the thick target rule; the photon budget, site rates in plastic and in CsI, pile up, the collar's transfer curve, the 64 × 64 Green's function and what the septum does to it, the boundary count rate, the energy budget, and the dose outside; then the compiler run on that Green's function (Way B and the collar pass, the crosstalk it cannot remove, the exact law at 64 sites by transfer matrix) and the timing closure that prices every synapse as a photon rate and the vessel's sample rate as built | | [transistor/](transistor/) | the reference transistor: one pinout at three scales, the valve, the datasheet with characteristic curves and maximum ratings; with four accompanying notes: [SEALED.md](transistor/SEALED.md) (the machine), [EMBODIMENT.md](transistor/EMBODIMENT.md) (the build, at assembly grade), [VALVE.md](transistor/VALVE.md) (the logic), [COMPONENTS.md](transistor/COMPONENTS.md) (the full inventory of a working computer, missing pieces simulated), [POWER.md](transistor/POWER.md) (the metabolism), and [SCALING.md](transistor/SCALING.md) (the trajectory) | --- @@ -371,7 +371,7 @@ Where this all goes is the subject of [transistor/SCALING.md](transistor/SCALING ## The keystone, computed: the neutron gate at k below one -The claim that the keystone already exists in the neutron sector has, until now, been arithmetic on library constants and a citation to a 1958 paper. It is now a calculation. [neutron/](neutron/) builds the reference transistor's third scale in OpenMC with the official ENDF/B-VIII.0 library: two 72 litre tanks of 4.9 percent enriched uranyl fluoride solution (the composition of a handbook criticality benchmark, so every atom density is published), each at k ≈ 0.901 alone, standing 3 cm of water apart in a water bath, with an absorber that can be lowered between them and a Cf-252 point source in one tank. Before the gate is computed the same code and data reproduce three handbook criticals ([neutron/results.md](neutron/results.md), Section 0), so the instrument is calibrated the way a criticality safety calculation is. +The claim that the keystone already exists in the neutron sector has, until now, been arithmetic on library constants and a citation to a 1958 paper. It is now a calculation. [neutron/](neutron/) builds the reference transistor's third scale in OpenMC with the official ENDF/B-VIII.0 library: two 72 litre tanks of 4.9 percent enriched uranyl fluoride solution (the composition of a handbook criticality benchmark, so every atom density is published), each at k ≈ 0.901 alone, standing 3 cm of water apart in a water bath, with an absorber that can be lowered between them and a ²⁵²Cf point source in one tank. Before the gate is computed the same code and data reproduce three handbook criticals ([neutron/results.md](neutron/results.md), Section 0), so the instrument is calibrated the way a criticality safety calculation is. Every number below carries a Monte Carlo uncertainty, and every configuration is strictly subcritical. @@ -379,7 +379,7 @@ Every number below carries a Monte Carlo uncertainty, and every configuration is - **A trap the architecture walks into by construction.** A gate is built to couple its regions weakly, and weak coupling drives the dominance ratio of the eigenvalue problem toward one: 0.957 to 0.983 here, so the tilt between the two tanks decays by one or two percent per generation while sampling noise re excites it just as fast. The geometry is mirror symmetric, so the true fission share is exactly half per tank, yet the fission banks stood off by up to 0.070 while the Shannon entropy sat flat to a part in a thousand: entropy watches the shape inside each tank and is nearly blind to the tilt between them. The first version of this calculation shipped a fission matrix that was wrong in a way that looked entirely reasonable, and only the control run caught it. The fix is a mirror rather than more batches, running the half geometry with a reflective plane so the tilt mode cannot exist, and the correction is visible in the physics: a tank's self multiplication went from a non monotonic 0.8924, 0.9030, 0.8977 to a flat 0.8946, 0.8964, 0.8943, which is what an absorber placed *between* two tanks must do to what each tank does to its own neutrons, namely almost nothing. Any photon sector network of many weakly coupled cells inherits this in a sharper form. - **The transistor.** One driver neutron entering tank A becomes **1.49 fission neutrons born in tank B**, across the gap, with the gate open: the output exceeds the input, so the gate has gain. A 1 mm cadmium sheet cuts the coupling by 1.7× and the drain to 0.92; a 2 cm boron carbide blade by 2.6× and to 0.67. The contrast is 2.2, not a MOSFET's million, and the neutron budget says why: what crosses 3 cm of water is still largely fast, and a thin absorber is a filter, not a barrier. - **Linearity, and the honest AND.** Two drivers together deliver the sum of what each delivers alone to 0.6 percent, which is counting noise: transport is linear while its cross sections are frozen, exactly as the Green's function reading requires. The coincidence AND is therefore a perceptron AND, a threshold on a weighted sum, with the threshold still at the boundary. -- **Level restoration.** Driven through the water from A, by Cf-252 at its own axis, or by a 14.1 MeV line, tank B emits the same fission spectrum to a total variation distance of 0.002. Inputs spanning thermal to 14 MeV, one output: the self restoring class of the theory supplement, measured. The photon sector cannot buy this at any price, because an isomer cascade emits its own lines and not its trigger's. +- **Level restoration.** Driven through the water from A, by ²⁵²Cf at its own axis, or by a 14.1 MeV line, tank B emits the same fission spectrum to a total variation distance of 0.002. Inputs spanning thermal to 14 MeV, one output: the self restoring class of the theory supplement, measured. The photon sector cannot buy this at any price, because an isomer cascade emits its own lines and not its trigger's. - **The clock.** Generation time Λ = 106 µs, prompt switching time Λ/(1 - k) = 1.22 ms, gain bandwidth product 1/Λ = **9.4 kHz**: the op amp law of the transistor note, with laboratory grade constants in it. - **The veto, priced.** Warming the pair by 56 K costs -25 pcm/K (-13 Doppler and scattering law, -13 expansion of the liquid), a 14 percent modulation of the gain; halving the gain would need about 343 K, which water at atmospheric pressure cannot do. @@ -419,12 +419,28 @@ The machine the theory can seal today is therefore a rate coded sampler whose ph --- +## The vessel, compiled: what a gigabecquerel buys + +The compiler of the theory (Section 11) had run only on a toy fabric, and Open Problem 4 asked for it to be run on a real geometry. [ampoule/](ampoule/) now has one: the 64 × 64 Green's function of the transported vessel is the fabric, the digital twin's instance restricted to the vessel's own lattice (eight rings of eight sites, ring bonds and axial bonds) is the program, and [ampoule/compile.py](ampoule/compile.py) does with them what a compiler does, in [ampoule/compile_results.md](ampoule/compile_results.md): it places the instance, reports what the fabric adds that was not asked for, and closes the timing. + +- **The fabric is geometry.** Every measured coupling is the solid angle a 2 mm cell subtends at its neighbour times a 3 percent chance that the photon interacts in 2 mm of plastic, the same probability for the ring, axial and diagonal classes. CsI cells raise the receiving end by the measured 31× to an interaction probability of one, the ceiling; after that a coupling is solid angle alone. +- **Way B places the instance and the fabric buries it.** Apertures on the 120 intended bonds compile the instance exactly, but the 60 couplings each site receives from the diagonal and far classes pass no aperture, and in weight units they sum to 7.9× the instance. Sampled, that law saturates: every site sits at occupancy 1.00 where the instance wanted 0.58. The collar has one more pass, since the mean of the crosstalk is a bias and the collar sets biases, and after it the residual fluctuation is still 3.1× the drive the instance wanted. A diffusive shell cannot carry a nearest neighbour instance; the sight lines of the build note's channel plates are load bearing, and the next transport must include them. +- **The law at 64 sites is checked, not assumed.** The lattice's topology makes the exact Boltzmann law a transfer matrix over 256 ring states, and the twin at 64 sites reproduces it to counting noise, at 3.3 sweeps per independent sample against 3.2 at 8 sites: the cost of a sample in sweeps does not grow with the machine. +- **Timing closure: every weight is a photon rate.** A nearest neighbour bond carries 16.3 photons per second with CsI cells (0.0169 with plastic), so a 4 bit read of a site's fan in takes 881 ms and an 8 bit read four minutes; the recurrence loop of the transistor note runs 34× slower than in the benchtop cell because its input is scattered light and the cell's is a beam. The vessel as built draws **0.34 independent samples per second** at 4 bits with CsI cells, 1.1×10⁵ short of the 38,462 the machine note priced, which counted proposals and never priced the synapse. The vessel is proposal rich and synapse poor. +- **The ladder back.** Two measured levers and two catalogue levers separate the two figures: CsI at both ends (measured, 964× in current), cells packed face to face (148×, solid angle) and a terabecquerel core (1,000×, the licence tier of the ENIAC ledger) reach up to 51,143 samples per second at 4 bits, 1.3× the priced figure at the ceiling of the currents, with no new physics. At 8 bits every rung is 256× lower. + +![The vessel, compiled](figures/fig18_compiled.svg) + +What changes in the theory is one sentence and one number. The twin's 26 decays per sample priced the machine's proposals and assumed its weighted sums were known at each one; in matter the weighted sum is a count, the precision law prices it, and in this vessel it is the slow part by five orders of magnitude. The machine note's throughput is amended to what the transport and the compiler say it is, the reset ledger of the theory gains the synapse term, and the ENIAC ledger gains the row that carries it back. + +--- + ## Open problems and how to contribute 1. **Keystone:** propose or measure a compact state meeting the leak condition with β>1 *in a level restoring or convertible class* (theory, Section 2). *This is problem number one.* A concrete, computable subproblem: search ENSDF for heterogeneous pairs of isomers whose cascade lines and gateway lines are mutually resonant (gate A's output pumps gate B and vice versa); the search space is already tabulated in `/gates`. The computed neutron gate ([neutron/](neutron/)) adds a second requirement that the photon sector had not been asked for: the state must also supply a *signal controlled inhibition*, because the only one the neutron sector has is heat and it is worth a fraction of the gain. A gate with gain but no inversion is a linear amplifier with a comparator bolted to its boundary, and the machine it builds is the Bernstein machine of Section 6 with better numbers, not a logic family. 2. Tighten the throughput law for fan out reuse: when is a count "spent"? 3. A learning rule: aperture update Δα ∝ coincidence(pre,post) is Hebbian or STDP using the *same* coincidence primitive as the AND gate (Appendix B.4); formalize and simulate. -4. Transport level 𝒢 for a real geometry that implements a target weight matrix (signed weights via complementary channels). *The measurement half is done:* [ampoule/](ampoule/) has the 64 × 64 Green's function of the build note's compute shell, nearest neighbour weights of 3×10⁻⁵ per photon with 0.1% total fan out; what remains is to run the compiler of theory Section 11 on that geometry rather than on the toy fabric. +4. Transport level 𝒢 for a real geometry that implements a target weight matrix (signed weights via complementary channels). *Done, in [ampoule/](ampoule/):* the 64 × 64 Green's function of the build note's compute shell is measured, nearest neighbour weights of 3×10⁻⁵ per photon with 0.1% total fan out, and the compiler has been run on it, Way B with the collar pass, and the timing closed ([ampoule/compile_results.md](ampoule/compile_results.md)). What remains is the vessel the result asks for: a compute shell whose couplings are collimated sight lines rather than scattering, so that a nearest neighbour instance is not buried by the far couplings, and a boundary with enough distinguishable channels for Way C to see the shell it trims. 5. Tier 2: a concrete two qubit gate on nuclear spin or Mössbauer DOF with a room temperature error budget. 6. **The addressed long retention write.** The broadband route to self written memory is dead by a bandwidth ratio of 10¹⁸, and the narrowline route is now open in principle (nuclear lamps, radiogenic feeding, resonance addressing: theory Section 9); what remains is a state that is simultaneously *parent fed, gradient addressable, and long lived*. A concrete, computable search: scan the catalog in `/gates` for isomers with lifetime above seconds whose feeding parents emit Mössbauer class lines, and rank by the addressing sensitivity Γ/(dE/dB). 7. Measure realized bits per detected quantum for a pixelated spectroscopic boundary against the log_2(N_E N_x N_τ) ceiling of the boundary theory. The boundary's raw budget is now computed, 3.25 M/s detected in the build note's ring, 0.33× what it was priced at ([ampoule/](ampoule/)); the ceiling is still to be measured against it. diff --git a/ampoule/README.md b/ampoule/README.md index 218723a..eab9421 100644 --- a/ampoule/README.md +++ b/ampoule/README.md @@ -9,6 +9,8 @@ The ampoule of [transistor/SEALED.md](../transistor/SEALED.md) is the one machin | [`model.py`](model.py) | the vessel, shell by shell, its sources and tallies, and the stages below; writes `tallies.json` (needs OpenMC and the data) | | [`report.py`](report.py) | every derived number, `results.md`, and figure 17, from the two JSON files (numpy and matplotlib only) | | [`results.md`](results.md) | the numbers, regenerated by `report.py` | +| [`compile.py`](compile.py) | the compiler of theory Section 11 on the measured Green's function, the exact law at 64 sites, and the timing closure; writes `compile_results.md` and figure 18 (numpy and matplotlib only) | +| [`compile_results.md`](compile_results.md) | the vessel compiled, regenerated by `compile.py` | | `tallies.json`, `calibration.json` | the committed run, with uncertainties | ## The vessel as built @@ -48,12 +50,17 @@ The betas are handled by OpenMC's thick target bremsstrahlung treatment: an elec The design's power ledger holds; its proposal budget holds only with CsI cells; its boundary budget is a factor 3.0 optimistic; its two mechanical controls are analog because its light is hard; and its wall is a filter for the same reason. The ampoule is a rate coded sampler with small weights and a narrower mouth than it was priced with, and each of those words is now a number. +## The compilation + +[`compile.py`](compile.py) runs the compiler of theory Section 11 on the Green's function above and closes the vessel's timing ([`compile_results.md`](compile_results.md), figure 18). The fabric is solid angle times a 3 percent interaction probability. Way B places the twin's instance on the lattice's 120 bonds exactly, and the 60 couplings per site that pass no aperture then bury it, 7.9× the instance in weight units, with a fluctuation still 3.1× the drive after the collar takes out the mean. The 64 site law is checked against an exact transfer matrix at 3.3 sweeps per independent sample. And every weight is a photon current, 16.3 per second per nearest neighbour bond with CsI cells, which makes the vessel as built a 0.34 sample per second machine against the 38,462 priced on proposals, with a ladder of two measured levers and two licences back. + ## Running it ``` python3 calibrate.py # a minute python3 model.py # about ten minutes on a laptop; --quick for a tenth of the particles python3 report.py # seconds; numpy and matplotlib only +python3 compile.py # ten seconds; numpy and matplotlib only ``` Requires OpenMC 0.16 and the data that [`neutron/data.py`](../neutron/data.py) fetches, which now includes the photoatomic files and the natural isotopes of every element in the vessel. diff --git a/ampoule/compile.py b/ampoule/compile.py new file mode 100644 index 0000000..520a002 --- /dev/null +++ b/ampoule/compile.py @@ -0,0 +1,592 @@ +#!/usr/bin/env python3 +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +""" +The vessel, compiled: the compiler of theory Section 11 run on the measured +Green's function of the ampoule rather than on the toy fabric, and the +timing closure that the compilation forces into the open. + +Open Problem 4 asked for the transport level Green's function of a real +geometry and for the compiler to be run on it. /ampoule measured the +64 × 64 matrix; this script takes it as the fabric and does what a compiler +does: it places an instance on the fabric (Way B, apertures), reports what +the fabric cannot do (the crosstalk it adds), and then prices the one thing +the design notes never priced, the photon current on every synapse, because +in a rate coded machine a weight is a rate and the precision law says how +long each rate takes to read. Everything below descends from committed +tallies and the theory's own laws; nothing is fitted. + + the fabric the measured G, symmetrised, sorted into the lattice's + coupling classes, and read as geometry (solid angle) + times an interaction probability + the instance the digital twin's recipe restricted to the lattice's + bonds: an 8 azimuth by 8 height Ising problem, 64 sites, + ring bonds and axial bonds, Gaussian couplings, biases + Way B apertures T = G*/G_fab on the intended bonds; the + unintended couplings the fabric adds anyway, per site; + the septum as the only inhibitory lever, at its measured + factor + the law the 64 site twin run on the intended instance and on the + as built one, each checked against the exact Boltzmann + law by a transfer matrix over the eight rings (256 row + states), which the lattice's topology makes exact + timing closure the current on every synapse, I_kj ≤ G_kj r_j, from the + measured site rates in plastic and in CsI; the time to + read it to 4, 6 and 8 bits; the recurrence loop cadence + of the transistor note's control law; the independent + samples per second the vessel delivers as built against + the 38,462 per second the machine note priced; and the + ladder of measured levers between the two + +Outputs: ampoule/compile_results.md and figures/fig18_compiled.*; numpy +and matplotlib only, from the committed tallies.json. +""" +import json +import math +import os +import sys + +import numpy as np + +HERE = os.path.dirname(os.path.abspath(__file__)) +ROOT = os.path.dirname(HERE) +FIGS = os.path.join(ROOT, "figures") +OUT = [] + +N_AZ, N_Z = 8, 8 +N = N_AZ * N_Z +SEED = 90 # honours Sr-90, the core +PROPOSAL_BUDGET = 1e6 # per second across the sites, SEALED.md Section 8 +DECAYS_PER_SAMPLE = 26 # the twin's measured cost, simulator/results.md +PRICED_SAMPLES = PROPOSAL_BUDGET / DECAYS_PER_SAMPLE # 38,462 per second, sealed_results.md +BENCHTOP_LOOP_S = 2 ** 8 / 1e4 # the transistor note: 4 bits at 10⁴ per second +BITS = (4, 6, 8) + + +def say(s=""): + OUT.append(s) + + +def times(x): + if x < 10: + return f"{x:.2g}×" + if x < 1e4: + return f"{x:,.0f}×" + return f"{sci(x)}" + + +def hms(s): + """A duration in the unit a reader would use.""" + if s < 1: + return f"{s*1e3:.0f} ms" + if s < 120: + return f"{s:.2g} s" + if s < 7200: + return f"{s/60:.0f} min" + if s < 2 * 86400: + return f"{s/3600:.0f} h" + if s < 2 * 365.25 * 86400: + return f"{s/86400:.0f} d" + return f"{s/(365.25*86400):.1f} y" + + +def sci(x): + m, e = f"{x:.1e}".split("e") + return f"{m}×10{str(int(e)).translate(str.maketrans('0123456789-', '⁰¹²³⁴⁵⁶⁷⁸⁹⁻'))}" + + +def rate(x): + """Samples per second in the form a reader would write.""" + if x >= 1000: + return f"{x:,.0f}" + if x >= 1: + return f"{x:.3g}" + return f"{x:.2g}" + + +# --------------------------------------------------------------------------- +# the lattice +# --------------------------------------------------------------------------- +def coupling_class(j, k): + iz, ia = divmod(j, N_AZ) + kz, ka = divmod(k, N_AZ) + da = min(abs(ka - ia), N_AZ - abs(ka - ia)) + dz = abs(kz - iz) + if j == k: + return "self" + if da == 1 and dz == 0: + return "ring" + if da == 0 and dz == 1: + return "axis" + if da == 1 and dz == 1: + return "diagonal" + return "far" + + +CLASS = np.array([[coupling_class(j, k) for j in range(N)] for k in range(N)]) # CLASS[k, j] +INTENDED = (CLASS == "ring") | (CLASS == "axis") +UNINTENDED = (CLASS == "diagonal") | (CLASS == "far") + + +def instance(seed=SEED, sigma=1.4, bias=0.5): + """The twin's recipe (simulator/nuclear_ising.py) on the lattice's bonds.""" + rng = np.random.default_rng(seed) + W = np.zeros((N, N)) + for j in range(N): + for k in range(j + 1, N): + if INTENDED[k, j]: + W[j, k] = W[k, j] = rng.normal(0, sigma) + b = rng.normal(0, bias, N) + return W, b + + +# --------------------------------------------------------------------------- +# the exact law: a transfer matrix over the rings, along the axis +# --------------------------------------------------------------------------- +ROWS = ((np.arange(2 ** N_AZ)[:, None] >> np.arange(N_AZ)) & 1).astype(float) # 256 row states + + +def _lse0(M): + m = M.max(axis=0) + return m + np.log(np.exp(M - m[None, :]).sum(axis=0)) + + +def _lse1(M): + m = M.max(axis=1) + return m + np.log(np.exp(M - m[:, None]).sum(axis=1)) + + +def exact_law(W, b): + """log Z, the exact site marginals ⟨z_k⟩ and the exact mean of + E = ½ zᵀWz + bᵀz under p ∝ exp(E), for any W whose bonds stay within a + ring or between adjacent rings (the lattice instance does).""" + def sites(z): + return [z * N_AZ + a for a in range(N_AZ)] + + def logZ_marg(scale): + logw = [scale * (0.5 * np.einsum("si,ij,sj->s", ROWS, W[np.ix_(sites(z), sites(z))], ROWS) + + ROWS @ b[sites(z)]) for z in range(N_Z)] + T = [scale * (ROWS @ W[np.ix_(sites(z), sites(z + 1))] @ ROWS.T) for z in range(N_Z - 1)] + al = [None] * N_Z + al[0] = logw[0].copy() + for z in range(1, N_Z): + al[z] = _lse0(al[z - 1][:, None] + T[z - 1] + logw[z][None, :]) + be = [None] * N_Z + be[-1] = np.zeros(2 ** N_AZ) + for z in range(N_Z - 2, -1, -1): + be[z] = _lse1(T[z] + logw[z + 1][None, :] + be[z + 1][None, :]) + logZ = _lse0(al[-1][:, None])[0] + marg = np.zeros(N) + for z in range(N_Z): + p = np.exp(al[z] + be[z] - logZ) + marg[sites(z)] = ROWS.T @ p + return logZ, marg + + logZ, marg = logZ_marg(1.0) + h = 1e-4 + mean_E = (logZ_marg(1 + h)[0] - logZ_marg(1 - h)[0]) / (2 * h) # d log Z / d scale + return logZ, marg, mean_E + + +# --------------------------------------------------------------------------- +# the twin at 64 sites +# --------------------------------------------------------------------------- +def sigmoid(u): + return 1.0 / (1.0 + np.exp(-u)) + + +def run_chain(W, b, n_events, seed): + """The machine, one proposal per event (simulator/nuclear_ising.py).""" + rng = np.random.default_rng(seed) + z = rng.integers(0, 2, N).astype(float) + sites = rng.integers(0, N, n_events) + urand = rng.random(n_events) + burn = n_events // 5 + msum = np.zeros(N) + E = 0.5 * z @ W @ z + b @ z + etrace = np.empty(n_events - burn) + for t in range(n_events): + k = sites[t] + u = W[k] @ z + b[k] + new = 1.0 if urand[t] < sigmoid(u) else 0.0 + if new != z[k]: + E += (new - z[k]) * u # W_kk = 0 + z[k] = new + if t >= burn: + msum += z + etrace[t - burn] = E + return msum / (n_events - burn), etrace + + +def integrated_autocorr(x, c=6.0): + """Sokal's adaptive window, in events (simulator/nuclear_ising.py).""" + x = np.asarray(x) - np.mean(x) + n = len(x) + f = np.fft.rfft(x, 2 * n) + acf = np.fft.irfft(f * np.conjugate(f))[:n].real + acf /= acf[0] + tau = 1.0 + for m in range(1, n): + tau += 2.0 * acf[m] + if m >= c * tau: + break + return max(tau, 1.0) + + +# --------------------------------------------------------------------------- +def main(): + doc = json.load(open(os.path.join(HERE, "tallies.json"))) + runs, prov = doc["runs"], doc["provenance"] + G_raw = np.array(runs["synapse_open"]["G"]) + G_std = np.array(runs["synapse_open"]["std"]) + G_sep = np.array(runs["synapse_septum"]["G"]) + r_pl = np.array(runs["source"]["sites"]["total"][0]) # interactions per second per site, plastic + r_cs = np.array(runs["source_csi"]["sites"]["total"][0]) # the same with CsI cells + csi_ratio = r_cs.sum() / r_pl.sum() + lay = prov["site_layout"] + radius = lay["radius_cm"] + dz = abs(lay["z_cm"][1] - lay["z_cm"][0]) + cell = 0.2 # cm, the 2 mm cell of the build note + + say("# The vessel, compiled (regenerated by compile.py from tallies.json)\n") + say("The compiler of theory Section 11, run on the Green's function that /ampoule measured instead of " + "on the toy fabric of transport/compiler_demo.py, and the timing closure the compilation forces " + "into the open. Every number descends from the committed tallies, the twin's measured cost per " + "sample, and the precision law; the instance is the twin's recipe on the lattice's bonds.\n") + + # ---- 0. the fabric ---------------------------------------------------- + say("## 0. The fabric: the measured G, sorted into the lattice's coupling classes\n") + G = 0.5 * (G_raw + G_raw.T) + np.fill_diagonal(G, np.diag(G_raw)) + asym = np.abs(G_raw - G_raw.T) / np.maximum(0.5 * (G_raw + G_raw.T), 1e-12) + big = 0.5 * (G_raw + G_raw.T) > 1e-5 + rel = G_std / np.maximum(G_raw, 1e-12) + ring_rel = np.median(rel[CLASS == "ring"]) + say("Detailed balance needs a symmetric weight matrix, and a photon that crosses from j to k is as likely " + "as one crossing from k to j in a mirror symmetric lattice, so the measured matrix is symmetrised; " + f"the two triangles differ by a median {np.median(asym[big]):.0%} where the coupling exceeds 10⁻⁵, which " + f"is the {ring_rel:.0%} counting uncertainty of a nearest neighbour entry taken twice. The classes:\n") + say("| class | pairs | mean G_kj | solid angle Ω/4π of a 2 mm face at that distance | G ÷ (Ω/4π): the interaction probability it implies |") + say("|---|---|---|---|---|") + d_ring = 2 * radius * math.sin(math.pi / N_AZ) + d_axis = dz + d_diag = math.hypot(d_ring, d_axis) + omega = {"ring": cell * cell / (4 * math.pi * d_ring ** 2), + "axis": cell * cell / (4 * math.pi * d_axis ** 2), + "diagonal": cell * cell / (4 * math.pi * d_diag ** 2)} + means = {} + for c in ("self", "ring", "axis", "diagonal", "far"): + vals = G[CLASS == c] + means[c] = float(vals.mean()) + om = omega.get(c) + say(f"| {c} | {len(vals)} | {means[c]:.2e} | " + (f"{om:.2e}" if om else "") + " | " + + (f"{means[c]/om:.3f}" if om else "") + " |") + say("") + p_int = np.mean([means["ring"] / omega["ring"], means["axis"] / omega["axis"]]) + say(f"The fabric is geometry. A nearest neighbour coupling is the solid angle a 2 mm face subtends at " + f"{d_ring:.1f} cm around the ring or {d_axis:.0f} cm along the axis, times a {p_int:.1%} chance that the " + f"photon interacts in 2 mm of plastic, and the two classes give the same probability to a few percent. " + f"With CsI cells the sites interact {times(csi_ratio)} as often (the source stage, results.md), so the " + f"receiving end of every coupling rises by that factor and the interaction probability becomes " + f"{min(p_int*csi_ratio, 1):.2f}: CsI takes the receiver to its ceiling, one interaction per photon " + "that enters, and what remains of a coupling after that is solid angle alone.\n") + + # ---- 1. Way B: the instance on the fabric ----------------------------- + say("## 1. Way B: the instance placed on the fabric by apertures\n") + W, b = instance() + n_bonds = int(INTENDED.sum() // 2) + say(f"The instance is the digital twin's recipe restricted to the lattice's bonds: {N} sites, {n_bonds} bonds " + f"({int((CLASS == 'ring').sum()//2)} around the rings, {int((CLASS == 'axis').sum()//2)} along the axis), " + f"Gaussian couplings of standard deviation 1.4 and biases of 0.5, seed {SEED}. Way B compiles it by " + "division: an intended bond of magnitude |W_kj| rides the fabric's coupling G_kj through an aperture " + "T_kj = |W_kj| / (s G_kj) ≤ 1, where s, the weights per unit coupling, is set by the bond that needs " + "the fabric wide open, and the sign is a choice of excitatory or inhibitory channel (theory Section 5.3).\n") + ring_pairs = (CLASS == "ring") + s_scale = np.max(np.abs(W[ring_pairs]) / G[ring_pairs]) # weights per unit G: the tightest ring bond opens fully + T = np.zeros((N, N)) + T[INTENDED] = np.abs(W[INTENDED]) / (s_scale * G[INTENDED]) + say(f"- apertures on the {n_bonds} intended bonds: median transmission {np.median(T[INTENDED]):.2f}, all at or below 1 " + f"by construction; the ring bond that sets the scale is fully open and the axial bonds, on a coupling " + f"{means['axis']/means['ring']:.1f}× stronger, sit mostly closed") + Wab = W.copy() + Wab[UNINTENDED] = s_scale * G[UNINTENDED] # what the fabric adds anyway, all excitatory + per_site_in = np.array([G[k, INTENDED[k]].sum() for k in range(N)]) + per_site_un = np.array([G[k, UNINTENDED[k]].sum() for k in range(N)]) + ratio = per_site_un / per_site_in + w_in = np.array([np.abs(W[k, INTENDED[k]]).sum() for k in range(N)]) + w_un = np.array([Wab[k, UNINTENDED[k]].sum() for k in range(N)]) + say(f"- what the fabric adds that the instance did not ask for: every site also receives the {int(UNINTENDED[0].sum())} " + f"couplings of the diagonal and far classes, all excitatory and none behind an aperture, and in coupling " + f"units they sum to **{ratio.mean():.2f}×** its intended fan in (from {ratio.min():.2f}× to {ratio.max():.2f}× " + "across the sites). In weight units the imbalance is worse, because Way B closes most intended bonds " + f"to their targets while the unintended couplings stay wide open: a site's unintended weight sums to " + f"{w_un.mean():.1f} against an intended magnitude of {w_in.mean():.1f}, **{(w_un/w_in).mean():.1f}×** the " + "instance, and no choice of scale improves it, since the scale is already the smallest that fits the " + "strongest bond") + # the septum as the only inhibitory lever + srcs = runs["synapse_septum"]["sources"] + blocked, control = [], [] + for j in srcs: + _, ia = divmod(j, N_AZ) + if ia != 0: + continue + for kz in range(N_Z): + k1, k7 = kz * N_AZ + 1, kz * N_AZ + 7 + if G_raw[k1, j] > 0: + blocked.append(G_sep[k1, j] / G_raw[k1, j]) + if G_raw[k7, j] > 0: + control.append(G_sep[k7, j] / G_raw[k7, j]) + septum = float(np.mean(blocked)) + say(f"- the only lever against a coupling is the lead septum, measured at {septum:.2f} of the open value across " + f"the plane it sits in and {np.mean(control):.2f} on the unshielded side; a septum between two sectors halves " + "the far couplings that cross that plane and halves the intended ring bond that crosses it too, which is " + "the silence demand of the toy fabric (compiler_results.md) met in glass: the paths overlap, so nothing " + "in this vessel silences a pair without also dimming its neighbours\n") + + # ---- 2. the law: intended and as built, against the exact one --------- + say("## 2. The law the vessel samples: intended, as built, and exact\n") + logZ, marg, mean_E = exact_law(W, b) + n_events = 4_000_000 + m_int, etr = run_chain(W, b, n_events, SEED) + tau = integrated_autocorr(etr) + sweeps = tau / N + rms_int = float(np.sqrt(((m_int - marg) ** 2).mean())) + m_ab, etr_ab = run_chain(Wab, b, n_events, SEED + 1) + # the collar pass: the compiler knows the target law exactly, so it can subtract the mean of the + # crosstalk from every site's bias (the collar opening is the bias) and leave only its fluctuation + b_collar = b - np.array([(Wab[k] - W[k]) @ marg for k in range(N)]) + m_col, etr_col = run_chain(Wab, b_collar, n_events, SEED + 2) + rms_col = float(np.sqrt(((m_col - marg) ** 2).mean())) + max_col = float(np.abs(m_col - marg).max()) + # the fluctuation the collar cannot remove, against the drive the instance wanted, site by site + var = marg * (1 - marg) + fluct = np.sqrt(((Wab - W) ** 2) @ var) # std of the crosstalk term at each site + drive = np.sqrt((W ** 2) @ var) # std of the intended weighted sum at each site + say("The lattice has a topology the twin's 8 site instance did not: each ring of 8 couples only to the " + "next, so the exact Boltzmann law is a transfer matrix over 256 row states along the axis, and the " + "64 site machine can be checked against its exact law the way the 8 site one was checked against " + "enumeration.\n") + say("| run | what the sites see | mean energy | site marginals against the exact law (rms over 64 sites) | worst site |") + say("|---|---|---|---|---|") + say(f"| exact (transfer matrix) | the intended instance | {mean_E:.3f} | | |") + say(f"| twin, {n_events:,} proposals | the intended instance | {etr.mean():.3f} | {rms_int:.4f} | {np.abs(m_int - marg).max():.4f} |") + say(f"| twin, {n_events:,} proposals | the instance plus the fabric's crosstalk | {etr_ab.mean():.1f} | mean marginal {m_ab.mean():.2f} against {marg.mean():.2f}: saturated | |") + say(f"| twin, {n_events:,} proposals | the same, with the mean crosstalk taken out of every bias by the collar | {etr_col.mean():.3f} | **{rms_col:.3f}** | **{max_col:.3f}** |") + say("") + say(f"- the sampler at 64 sites reproduces its exact law to the counting noise of the run ({rms_int:.4f} rms on " + f"marginals that span 0 to 1), with an integrated autocorrelation time of **{tau:.0f} proposals, " + f"{sweeps:.1f} sweeps** of the lattice: the twin's 26 decays per sample at 8 sites were " + f"{26/8:.1f} sweeps, so the cost of an independent sample in sweeps is unchanged by an eightfold " + "larger machine") + say(f"- the same sampler on the as built weights, the instance plus what the fabric adds, does not sample a " + f"perturbed version of the intended law; it saturates. {int(UNINTENDED[0].sum())} open couplings of mean weight " + f"{Wab[UNINTENDED].mean():.2f} drive every site to a mean occupancy of {m_ab.mean():.2f} where the instance " + f"wanted {marg.mean():.2f}, and the energy runs to {etr_ab.mean():.0f} against {mean_E:.1f}. " + "Way B places the instance and the fabric buries it") + say(f"- the compiler has one more pass, and it is the collar. The crosstalk is a sum of many weak couplings, so " + "most of it is a constant the compiler can predict from the target law it already knows exactly, and a " + "constant drive is a bias, which is the collar opening. Subtracting the mean crosstalk from every site's " + f"bias leaves only its fluctuation, and that fluctuation is the verdict: site by site, treating the sites as independent, it has a standard " + f"deviation of {fluct.mean():.1f} in weight units against {drive.mean():.1f} for the drive the instance " + f"wanted, **{(fluct/drive).mean():.1f}×** the signal, so the sampled marginals still miss the intended law by " + f"{rms_col:.2f} rms and {max_col:.2f} at the worst site. What the collar cannot remove is what a diffusive " + "shell costs a nearest neighbour instance after the best compilation available to it, and the rest of " + "the way is collimation, not arithmetic\n") + + # ---- 3. timing closure ------------------------------------------------ + say("## 3. Timing closure: every weight is a photon rate\n") + say("A rate coded machine does not hold a weight, it counts one. The current on the synapse from j to k " + "is at most I_kj = G_kj r_j: the site's interaction rate r_j is the most it can send (one photon out " + "per interaction, the ceiling; the true fraction is the scatter share of the cell material, below " + "one), and G_kj is the fraction that arrives and interacts. The precision law then prices the read: " + "b bits of a rate cost 2^2b counts. With plastic cells the currents use the measured rates as they " + f"are; with CsI cells the sender interacts {times(csi_ratio)} as often and the receiver catches " + f"{times(csi_ratio)} as much, both measured, so a CsI coupling carries {times(csi_ratio**2)} the current.\n") + rows = [] + for label, r, recv in (("plastic cells", r_pl, 1.0), ("CsI cells", r_cs, csi_ratio)): + I = G * r[None, :] * recv # I[k, j] photons per second from j interacting in k + ring_I = float(I[CLASS == "ring"].mean()) + axis_I = float(I[CLASS == "axis"].mean()) + fanin = np.array([I[k, np.arange(N) != k].sum() for k in range(N)]) + rows.append((label, ring_I, axis_I, float(fanin.mean()), float(fanin.min()))) + say("| cells | ring bond current (photons/s) | axial bond current | fan in per site, mean (min) | " + + " | ".join(f"read the fan in to {bb} bits" for bb in BITS) + " |") + say("|---|---|---|---|" + "---|" * len(BITS)) + for label, ring_I, axis_I, fan_m, fan_min in rows: + say(f"| {label} | {ring_I:.3g} | {axis_I:.3g} | {fan_m:.3g} ({fan_min:.3g}) | " + + " | ".join(hms(2 ** (2 * bb) / fan_m) for bb in BITS) + " |") + say("") + _, ring_pl, _, fan_pl, _ = rows[0] + _, ring_cs, _, fan_cs, _ = rows[1] + say(f"- a nearest neighbour bond carries **{ring_pl:.3g} photons per second** with plastic cells and " + f"**{ring_cs:.3g}** with CsI: one photon every {hms(1/ring_pl)} and every {hms(1/ring_cs)}. Reading that " + f"single weight to 4 bits takes {hms(2**8/ring_pl)} and {hms(2**8/ring_cs)}; to 8 bits, " + f"{hms(2**16/ring_pl)} and {hms(2**16/ring_cs)}") + say(f"- the recurrence loop of the transistor note (count the fan in for T_loop = 2^2b / r, then reset the " + f"aperture to σ(u)) runs at T_loop = {hms(2**8/fan_cs)} per site at 4 bits with CsI cells and " + f"{hms(2**8/fan_pl)} with plastic, against the benchtop cell's {hms(BENCHTOP_LOOP_S)}: the sealed vessel " + f"updates a site {times((2**8/fan_cs)/BENCHTOP_LOOP_S)} more slowly than the cell you could build " + "this month, because the cell's input is a direct beam and the vessel's is scattered light\n") + + # the throughput as built + say("### The sample rate as built\n") + say("Every site integrates its fan in for one loop time and re sets its aperture; a sweep of the twin is " + f"one loop time of the vessel; an independent sample costs {sweeps:.1f} sweeps (Section 2). The machine " + f"note priced the vessel from its proposal budget alone, 10⁶ proposals per second at " + f"{DECAYS_PER_SAMPLE} decays per sample, {PRICED_SAMPLES:,.0f} independent samples per second. The " + "proposal budget is met with CsI cells (results.md). The synapse budget was never priced, and it binds.\n") + say("| cells | bits | loop time | independent samples per second, as built | against the priced 38,462 |") + say("|---|---|---|---|---|") + asbuilt = {} + for label, _, _, fan_m, _ in rows: + for bb in BITS: + T_loop = 2 ** (2 * bb) / fan_m + spr = 1.0 / (sweeps * T_loop) + asbuilt[(label, bb)] = spr + say(f"| {label} | {bb} | {hms(T_loop)} | {rate(spr)} | {times(PRICED_SAMPLES/spr)} short |") + say("") + short_cs4 = PRICED_SAMPLES / asbuilt[("CsI cells", 4)] + short_pl4 = PRICED_SAMPLES / asbuilt[("plastic cells", 4)] + say(f"The vessel as built draws about **{rate(asbuilt[('CsI cells', 4)])} independent samples per second** with " + f"CsI cells at 4 bit weights, {sci(short_cs4)} short of the figure the machine note printed, and " + f"{rate(asbuilt[('plastic cells', 4)])} per second with plastic, {sci(short_pl4)} short. The currents are ceilings, " + "so every rate in the table is a ceiling too. It is proposal " + "rich and synapse poor: a gigabecquerel makes a million proposals a second and delivers a few " + "hundred synapse photons a second to each site, and the sampler runs at the pace of the second " + "number. The 26 decays per sample of the twin counted proposals and assumed the weighted sum was " + "known at each one; in the vessel the weighted sum is the slow part.\n") + + # ---- 4. the ladder -------------------------------------------------- + say("## 4. The ladder: measured levers between the vessel as built and the vessel as priced\n") + omega_touch = 1.0 / 6.0 # a face of a cube touching its neighbour + geom = omega_touch / omega["ring"] + ladder = [("as built, plastic cells, 4 bits", asbuilt[("plastic cells", 4)], "the measured fabric and rates"), + ("CsI cells at both ends", asbuilt[("CsI cells", 4)], f"{times(csi_ratio)} measured on each end; the receiver at its ceiling"), + ("cells packed face to face", asbuilt[("CsI cells", 4)] * geom, + f"solid angle from {sci(omega['ring'])} to 1/6 of 4π: {times(geom)} by geometry"), + ("a terabecquerel core (industrial licence)", asbuilt[("CsI cells", 4)] * geom * 1e3, + "activity ×1,000: the source row of the ENIAC ledger, SCALING.md"), + ("priced in the machine note", PRICED_SAMPLES, "the proposal budget at 26 decays per sample")] + say("| rung | independent samples per second | the lever |") + say("|---|---|---|") + for name, r_, lever in ladder: + say(f"| {name} | {rate(r_)} | {lever} |") + say("") + say(f"Two of the four rungs are already measured in this repository and the other two are geometry and " + f"licensing: with CsI cells packed face to face and a terabecquerel core the vessel reaches up to " + f"{ladder[3][1]:,.0f} samples per second at 4 bit weights, {ladder[3][1]/PRICED_SAMPLES:.1f}× the " + "priced figure at the ceiling of the currents, so the machine note's number is within reach of catalogue " + "levers, on an industrial licence, at 4 bits, with no new physics, and within the factor of a few that " + "the scatter share of CsI takes off the ceiling. At 8 bits every rung is 256× lower. What the ladder does not contain is a " + "way to run a nearest neighbour instance without the crosstalk of Section 1: packing the cells " + "closer raises every coupling class together. The clean synapse wants collimation, the sight " + "lines of the build note's channel plates, which this vessel's transport did not include and " + "which the next one should.\n") + + say("## 5. What is not compiled here\n") + say("Way C, the trim through the wall by SPSA on Poisson counts of the glow, is not run on this vessel " + "because its observable is not there: the boundary ring reads 24 paddles and 4 CZT pixels, 28 " + "channels for 64 collar openings and 64 site rates, so the loss the trimmer needs is under " + "determined by a factor of two before any noise. The toy fabric had a port per weight; the vessel " + "does not. Giving the mouth enough distinguishable channels to see the shell it is trimming is " + "the boundary theory's ceiling (theory Section 8.1) turned into a design requirement, and it " + "belongs to the next vessel.\n") + say("*The compiler places the instance on the measured fabric and finds the fabric adds as much coupling " + "as it was asked for; the timing closure finds that every weight is a photon current of order one " + "per second, so the sealed vessel samples at a fraction of a sample per second where it was priced " + "at tens of thousands; and the ladder finds the priced figure two measured levers and two " + "catalogue levers away. Every one of those sentences is a number above.*") + + open(os.path.join(HERE, "compile_results.md"), "w").write("\n".join(OUT) + "\n") + print("\n".join(OUT[-8:])) + print("wrote ampoule/compile_results.md") + figure(G, means, omega, p_int, csi_ratio, marg, m_int, m_ab, m_col, rows, asbuilt, ladder, sweeps) + + +# --------------------------------------------------------------------------- +def figure(G, means, omega, p_int, csi_ratio, marg, m_int, m_ab, m_col, rows, asbuilt, ladder, sweeps): + import matplotlib + matplotlib.use("Agg") + import matplotlib.pyplot as plt + INK, BLUE, RED, GREEN, AMBER, PURPLE, GREY = ( + "#16213e", "#2563eb", "#dc2626", "#16a34a", "#d97706", "#7c3aed", "#94a3b8") + plt.rcParams.update({ + "figure.facecolor": "white", "axes.facecolor": "white", "savefig.facecolor": "white", + "axes.edgecolor": INK, "axes.labelcolor": INK, "text.color": INK, "xtick.color": INK, + "ytick.color": INK, "axes.titlecolor": INK, "font.size": 11, "axes.titlesize": 12, + "axes.titleweight": "bold", "axes.grid": True, "grid.color": "#e5e7eb", + "grid.linewidth": 0.8, "axes.spines.top": False, "axes.spines.right": False, + "figure.dpi": 130, "svg.hashsalt": "nuclear-computer"}) + fig, ((A, B), (C, D)) = plt.subplots(2, 2, figsize=(13.4, 9.4)) + + # A: the fabric is geometry + classes = ["ring", "axis", "diagonal"] + om = np.array([omega[c] for c in classes]) + gm = np.array([means[c] for c in classes]) + A.loglog(om, gm, "o", color=BLUE, ms=9, zorder=5, label="measured G, plastic cells") + A.loglog(om, gm * csi_ratio, "D", color=AMBER, ms=8, zorder=5, label=f"with CsI cells ({csi_ratio:.0f}× measured)") + xx = np.logspace(-4.2, -0.5, 50) + A.loglog(xx, xx * p_int, "--", color=BLUE, lw=1.4, label=f"Ω/4π × {p_int:.1%} (2 mm of plastic)") + A.loglog(xx, xx, "-", color=GREY, lw=1.4, label="Ω/4π: one interaction per photon, the ceiling") + for c, x, y in zip(classes, om, gm): + A.annotate(c, xy=(x, y), xytext=(x * 1.25, y * 0.55), fontsize=9, color=INK) + A.axvline(1 / 6, color=GREEN, ls=":", lw=1.3) + A.text(1 / 6 * 0.9, 2e-5, "a face of a cell\ntouching its neighbour", color=GREEN, fontsize=8, ha="right") + A.set_xlabel("solid angle of the receiving face, Ω/4π") + A.set_ylabel("coupling G_kj (interactions per photon born)") + A.set_title("A. The fabric is solid angle times an interaction probability") + A.legend(frameon=False, fontsize=8, loc="upper left") + + # B: the law, intended vs as built + B.plot([0, 1], [0, 1], "-", color=GREY, lw=1.2) + B.plot(marg, m_int, "o", color=GREEN, ms=5, alpha=0.8, label="the intended instance, sampled") + B.plot(marg, m_ab, "s", color=RED, ms=5, alpha=0.7, label="plus the fabric's crosstalk: saturated") + B.plot(marg, m_col, "^", color=AMBER, ms=6, alpha=0.8, label="the same, mean crosstalk taken out by the collar") + B.set_xlim(0, 1); B.set_ylim(0, 1.06) + B.set_xlabel("exact site marginal ⟨z_k⟩ of the intended law (transfer matrix)") + B.set_ylabel("marginal the 64 site twin sampled") + B.set_title(f"B. The law sampled at 64 sites ({sweeps:.1f} sweeps per independent sample)") + B.legend(frameon=False, fontsize=8.5, loc="upper left") + + # C: timing closure + bits = np.arange(2, 11) + for (label, ring_I, axis_I, fan_m, _), ls in zip(rows, ("--", "-")): + col = GREY if label.startswith("plastic") else INK + C.semilogy(bits, 2.0 ** (2 * bits) / fan_m, ls, color=BLUE, lw=2.0, label=f"the fan in of a site, {label}") + C.semilogy(bits, 2.0 ** (2 * bits) / ring_I, ls, color=RED, lw=2.0, label=f"one ring bond, {label}") + C.axhline(BENCHTOP_LOOP_S, color=GREEN, ls=":", lw=1.4) + C.text(2.1, BENCHTOP_LOOP_S * 1.4, "the benchtop cell's loop, 26 ms", color=GREEN, fontsize=8.5) + for y, lab in ((60, "a minute"), (3600, "an hour"), (86400, "a day"), (365.25 * 86400, "a year")): + C.axhline(y, color=GREY, lw=0.6) + C.text(10.2, y * 1.25, lab, color=GREY, fontsize=7.5, ha="right") + C.set_xlabel("bits of precision in the weight") + C.set_ylabel("time to read it, 2^2b counts at the synapse current (s)") + C.set_title("C. Timing closure: every weight is a photon rate") + C.legend(frameon=False, fontsize=7.6, loc="upper left") + C.set_xlim(2, 10.3) + + # D: the ladder + names = [r[0] for r in ladder] + vals = [r[1] for r in ladder] + cols = [RED, AMBER, BLUE, GREEN, GREY] + y = np.arange(len(vals))[::-1] + D.barh(y, vals, color=cols, height=0.6) + D.set_xscale("log") + D.set_yticks(y); D.set_yticklabels(names, fontsize=8.5) + for yy, v in zip(y, vals): + D.text(v * 1.4, yy, f"{rate(v)} /s", va="center", fontsize=8.5) + D.set_xlim(min(vals) / 5, max(vals) * 60) + D.set_xlabel("independent samples per second (4 bit weights)") + D.set_title("D. The ladder from the vessel as built to the vessel as priced") + + fig.suptitle("Figure 18. The vessel, compiled", fontsize=13, fontweight="bold", y=1.0) + fig.tight_layout() + for ext in ("svg", "png"): + kw = {"metadata": {"Date": None}} if ext == "svg" else {} + fig.savefig(os.path.join(FIGS, f"fig18_compiled.{ext}"), bbox_inches="tight", **kw) + plt.close(fig) + print("wrote fig18_compiled") + + +if __name__ == "__main__": + main() diff --git a/ampoule/compile_results.md b/ampoule/compile_results.md new file mode 100644 index 0000000..58fe3d8 --- /dev/null +++ b/ampoule/compile_results.md @@ -0,0 +1,85 @@ +# The vessel, compiled (regenerated by compile.py from tallies.json) + +The compiler of theory Section 11, run on the Green's function that /ampoule measured instead of on the toy fabric of transport/compiler_demo.py, and the timing closure the compilation forces into the open. Every number descends from the committed tallies, the twin's measured cost per sample, and the precision law; the instance is the twin's recipe on the lattice's bonds. + +## 0. The fabric: the measured G, sorted into the lattice's coupling classes + +Detailed balance needs a symmetric weight matrix, and a photon that crosses from j to k is as likely as one crossing from k to j in a mirror symmetric lattice, so the measured matrix is symmetrised; the two triangles differ by a median 20% where the coupling exceeds 10⁻⁵, which is the 15% counting uncertainty of a nearest neighbour entry taken twice. The classes: + +| class | pairs | mean G_kj | solid angle Ω/4π of a 2 mm face at that distance | G ÷ (Ω/4π): the interaction probability it implies | +|---|---|---|---|---| +| self | 64 | 1.31e-02 | | | +| ring | 128 | 3.32e-05 | 1.12e-03 | 0.030 | +| axis | 112 | 1.10e-04 | 3.18e-03 | 0.035 | +| diagonal | 224 | 2.24e-05 | 8.30e-04 | 0.027 | +| far | 3568 | 3.60e-06 | | | + +The fabric is geometry. A nearest neighbour coupling is the solid angle a 2 mm face subtends at 1.7 cm around the ring or 1 cm along the axis, times a 3.2% chance that the photon interacts in 2 mm of plastic, and the two classes give the same probability to a few percent. With CsI cells the sites interact 31× as often (the source stage, results.md), so the receiving end of every coupling rises by that factor and the interaction probability becomes 1.00: CsI takes the receiver to its ceiling, one interaction per photon that enters, and what remains of a coupling after that is solid angle alone. + +## 1. Way B: the instance placed on the fabric by apertures + +The instance is the digital twin's recipe restricted to the lattice's bonds: 64 sites, 120 bonds (64 around the rings, 56 along the axis), Gaussian couplings of standard deviation 1.4 and biases of 0.5, seed 90. Way B compiles it by division: an intended bond of magnitude |W_kj| rides the fabric's coupling G_kj through an aperture T_kj = |W_kj| / (s G_kj) ≤ 1, where s, the weights per unit coupling, is set by the bond that needs the fabric wide open, and the sign is a choice of excitatory or inhibitory channel (theory Section 5.3). + +- apertures on the 120 intended bonds: median transmission 0.16, all at or below 1 by construction; the ring bond that sets the scale is fully open and the axial bonds, on a coupling 3.3× stronger, sit mostly closed +- what the fabric adds that the instance did not ask for: every site also receives the 60 couplings of the diagonal and far classes, all excitatory and none behind an aperture, and in coupling units they sum to **1.08×** its intended fan in (from 0.85× to 1.25× across the sites). In weight units the imbalance is worse, because Way B closes most intended bonds to their targets while the unintended couplings stay wide open: a site's unintended weight sums to 30.5 against an intended magnitude of 4.2, **7.9×** the instance, and no choice of scale improves it, since the scale is already the smallest that fits the strongest bond +- the only lever against a coupling is the lead septum, measured at 0.49 of the open value across the plane it sits in and 1.00 on the unshielded side; a septum between two sectors halves the far couplings that cross that plane and halves the intended ring bond that crosses it too, which is the silence demand of the toy fabric (compiler_results.md) met in glass: the paths overlap, so nothing in this vessel silences a pair without also dimming its neighbours + +## 2. The law the vessel samples: intended, as built, and exact + +The lattice has a topology the twin's 8 site instance did not: each ring of 8 couples only to the next, so the exact Boltzmann law is a transfer matrix over 256 row states along the axis, and the 64 site machine can be checked against its exact law the way the 8 site one was checked against enumeration. + +| run | what the sites see | mean energy | site marginals against the exact law (rms over 64 sites) | worst site | +|---|---|---|---|---| +| exact (transfer matrix) | the intended instance | 31.700 | | | +| twin, 4,000,000 proposals | the intended instance | 31.648 | 0.0029 | 0.0080 | +| twin, 4,000,000 proposals | the instance plus the fabric's crosstalk | 973.1 | mean marginal 1.00 against 0.58: saturated | | +| twin, 4,000,000 proposals | the same, with the mean crosstalk taken out of every bias by the collar | -0.003 | **0.640** | **0.949** | + +- the sampler at 64 sites reproduces its exact law to the counting noise of the run (0.0029 rms on marginals that span 0 to 1), with an integrated autocorrelation time of **211 proposals, 3.3 sweeps** of the lattice: the twin's 26 decays per sample at 8 sites were 3.2 sweeps, so the cost of an independent sample in sweeps is unchanged by an eightfold larger machine +- the same sampler on the as built weights, the instance plus what the fabric adds, does not sample a perturbed version of the intended law; it saturates. 60 open couplings of mean weight 0.51 drive every site to a mean occupancy of 1.00 where the instance wanted 0.58, and the energy runs to 973 against 31.7. Way B places the instance and the fabric buries it +- the compiler has one more pass, and it is the collar. The crosstalk is a sum of many weak couplings, so most of it is a constant the compiler can predict from the target law it already knows exactly, and a constant drive is a bias, which is the collar opening. Subtracting the mean crosstalk from every site's bias leaves only its fluctuation, and that fluctuation is the verdict: site by site, treating the sites as independent, it has a standard deviation of 2.8 in weight units against 1.0 for the drive the instance wanted, **3.1×** the signal, so the sampled marginals still miss the intended law by 0.64 rms and 0.95 at the worst site. What the collar cannot remove is what a diffusive shell costs a nearest neighbour instance after the best compilation available to it, and the rest of the way is collimation, not arithmetic + +## 3. Timing closure: every weight is a photon rate + +A rate coded machine does not hold a weight, it counts one. The current on the synapse from j to k is at most I_kj = G_kj r_j: the site's interaction rate r_j is the most it can send (one photon out per interaction, the ceiling; the true fraction is the scatter share of the cell material, below one), and G_kj is the fraction that arrives and interacts. The precision law then prices the read: b bits of a rate cost 2^2b counts. With plastic cells the currents use the measured rates as they are; with CsI cells the sender interacts 31× as often and the receiver catches 31× as much, both measured, so a CsI coupling carries 964× the current. + +| cells | ring bond current (photons/s) | axial bond current | fan in per site, mean (min) | read the fan in to 4 bits | read the fan in to 6 bits | read the fan in to 8 bits | +|---|---|---|---|---|---|---| +| plastic cells | 0.0169 | 0.0614 | 0.301 (0.14) | 14 min | 4 h | 3 d | +| CsI cells | 16.3 | 59.3 | 291 (151) | 881 ms | 14 s | 4 min | + +- a nearest neighbour bond carries **0.0169 photons per second** with plastic cells and **16.3** with CsI: one photon every 59 s and every 61 ms. Reading that single weight to 4 bits takes 4 h and 16 s; to 8 bits, 45 d and 67 min +- the recurrence loop of the transistor note (count the fan in for T_loop = 2^2b / r, then reset the aperture to σ(u)) runs at T_loop = 881 ms per site at 4 bits with CsI cells and 14 min with plastic, against the benchtop cell's 26 ms: the sealed vessel updates a site 34× more slowly than the cell you could build this month, because the cell's input is a direct beam and the vessel's is scattered light + +### The sample rate as built + +Every site integrates its fan in for one loop time and re sets its aperture; a sweep of the twin is one loop time of the vessel; an independent sample costs 3.3 sweeps (Section 2). The machine note priced the vessel from its proposal budget alone, 10⁶ proposals per second at 26 decays per sample, 38,462 independent samples per second. The proposal budget is met with CsI cells (results.md). The synapse budget was never priced, and it binds. + +| cells | bits | loop time | independent samples per second, as built | against the priced 38,462 | +|---|---|---|---|---| +| plastic cells | 4 | 14 min | 0.00036 | 1.1×10⁸ short | +| plastic cells | 6 | 4 h | 2.2e-05 | 1.7×10⁹ short | +| plastic cells | 8 | 3 d | 1.4e-06 | 2.8×10¹⁰ short | +| CsI cells | 4 | 881 ms | 0.34 | 1.1×10⁵ short | +| CsI cells | 6 | 14 s | 0.022 | 1.8×10⁶ short | +| CsI cells | 8 | 4 min | 0.0013 | 2.9×10⁷ short | + +The vessel as built draws about **0.34 independent samples per second** with CsI cells at 4 bit weights, 1.1×10⁵ short of the figure the machine note printed, and 0.00036 per second with plastic, 1.1×10⁸ short. The currents are ceilings, so every rate in the table is a ceiling too. It is proposal rich and synapse poor: a gigabecquerel makes a million proposals a second and delivers a few hundred synapse photons a second to each site, and the sampler runs at the pace of the second number. The 26 decays per sample of the twin counted proposals and assumed the weighted sum was known at each one; in the vessel the weighted sum is the slow part. + +## 4. The ladder: measured levers between the vessel as built and the vessel as priced + +| rung | independent samples per second | the lever | +|---|---|---| +| as built, plastic cells, 4 bits | 0.00036 | the measured fabric and rates | +| CsI cells at both ends | 0.34 | 31× measured on each end; the receiver at its ceiling | +| cells packed face to face | 51.1 | solid angle from 1.1×10⁻³ to 1/6 of 4π: 148× by geometry | +| a terabecquerel core (industrial licence) | 51,143 | activity ×1,000: the source row of the ENIAC ledger, SCALING.md | +| priced in the machine note | 38,462 | the proposal budget at 26 decays per sample | + +Two of the four rungs are already measured in this repository and the other two are geometry and licensing: with CsI cells packed face to face and a terabecquerel core the vessel reaches up to 51,143 samples per second at 4 bit weights, 1.3× the priced figure at the ceiling of the currents, so the machine note's number is within reach of catalogue levers, on an industrial licence, at 4 bits, with no new physics, and within the factor of a few that the scatter share of CsI takes off the ceiling. At 8 bits every rung is 256× lower. What the ladder does not contain is a way to run a nearest neighbour instance without the crosstalk of Section 1: packing the cells closer raises every coupling class together. The clean synapse wants collimation, the sight lines of the build note's channel plates, which this vessel's transport did not include and which the next one should. + +## 5. What is not compiled here + +Way C, the trim through the wall by SPSA on Poisson counts of the glow, is not run on this vessel because its observable is not there: the boundary ring reads 24 paddles and 4 CZT pixels, 28 channels for 64 collar openings and 64 site rates, so the loss the trimmer needs is under determined by a factor of two before any noise. The toy fabric had a port per weight; the vessel does not. Giving the mouth enough distinguishable channels to see the shell it is trimming is the boundary theory's ceiling (theory Section 8.1) turned into a design requirement, and it belongs to the next vessel. + +*The compiler places the instance on the measured fabric and finds the fabric adds as much coupling as it was asked for; the timing closure finds that every weight is a photon current of order one per second, so the sealed vessel samples at a fraction of a sample per second where it was priced at tens of thousands; and the ladder finds the priced figure two measured levers and two catalogue levers away. Every one of those sentences is a number above.* diff --git a/ampoule/report.py b/ampoule/report.py index 9354342..8157195 100644 --- a/ampoule/report.py +++ b/ampoule/report.py @@ -435,13 +435,17 @@ def per_keV(y): # C: the Green's function Gp = np.maximum(G, 1e-6) - im = C.imshow(Gp, norm=LogNorm(vmin=1e-5, vmax=max(Gp.max(), 1e-2)), cmap="Blues", origin="lower") + # drawn as vector cells rather than an embedded raster, so the SVG is the same on every platform + im = C.pcolormesh(np.arange(65) - 0.5, np.arange(65) - 0.5, Gp, + norm=LogNorm(vmin=1e-5, vmax=max(Gp.max(), 1e-2)), cmap="Blues", shading="flat") + C.set_aspect("equal") for b in range(8, 64, 8): C.axhline(b - 0.5, color=GREY, lw=0.5); C.axvline(b - 0.5, color=GREY, lw=0.5) C.set_xlabel("photon born in site j (8 heights × 8 azimuths)"); C.set_ylabel("interacts in site k") C.set_title("C. The synapse: G between the 64 sites") C.grid(False) - plt.colorbar(im, ax=C, fraction=0.046, pad=0.03, label="G_kj per photon") + cb = plt.colorbar(im, ax=C, fraction=0.046, pad=0.03, label="G_kj per photon") + cb.solids.set_rasterized(False) # the colour bar as vectors too, for the same reason # D: energy budget and dose labels = list(power); vals = [power[k] * 1e6 for k in labels] diff --git a/data-manifest.sha256 b/data-manifest.sha256 new file mode 100644 index 0000000..f1870d2 --- /dev/null +++ b/data-manifest.sha256 @@ -0,0 +1,13 @@ +1585a5eea86c5e17e90307c7e6e786d060049c4039e392a261ff6db977df9859 gates/data/nubase_4.mas20.txt +4024cb6c8b04638946c480f6d65e10b2e99fdf37a3c0dd4ba91a1ac024ae9a45 gates/data/decay_g_108ag.csv +0a537564c75b5f86fea2f60dfe00ebbb66ebca89d0421c9866c8be1930331da9 gates/data/decay_g_137ba.csv +d4cfcfc702b77408744f71123a9691b4604479425398eeba6ac1004b078f6c89 gates/data/decay_g_166ho.csv +c319120234aa1624b093c173edbe02ffbea25ce4be19b9ecd7db23b395ac76ed gates/data/decay_g_177lu.csv +f68d001a9ddbe0410ea48c40f35e1ff13829d63f713dca6810291fb743598109 gates/data/decay_g_178hf.csv +e1d367a059db86c00743fa8a79adbd86bde36179ef2464d4be7137f8db594519 gates/data/decay_g_93mo.csv +8a5c3db642592bce4e6d586dcd2a90e7ec1507923be4b01ad6ff0a1f7fda9bd0 gates/data/decay_g_99tc.csv +0447f24d91ed95c150d50e080f844d09a84bf84d5a5208e86d5b7940c9236844 photon/levels.json.gz +a6f73c5389382e07d64e610390efd2f4916b4e2ab86628ae78fb14b6e40e538e neutron/tallies.json +e51e4600a2fa6082a4ebbe1ed3181baecc0037bd1de921e2d40cb21186d4698e neutron/benchmarks.json +8155612d53f03059f117020941c9ba1010efb0aba3373660a51dea819ca961ff ampoule/tallies.json +ce05f4cdbf5f93fd6932835a4df6d771de6fb78a8615428e2059c7f18c699c5b ampoule/calibration.json diff --git a/figures/fig10_nuclear_transistor.png b/figures/fig10_nuclear_transistor.png index fa99564..9578de9 100644 Binary files a/figures/fig10_nuclear_transistor.png and b/figures/fig10_nuclear_transistor.png differ diff --git a/figures/fig10_nuclear_transistor.svg b/figures/fig10_nuclear_transistor.svg index 71e8ffe..310dcb0 100644 --- a/figures/fig10_nuclear_transistor.svg +++ b/figures/fig10_nuclear_transistor.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -21,124 +21,124 @@ - + - +" clip-path="url(#p33ede1bb8c)" style="fill: #16213e"/> - +" clip-path="url(#p33ede1bb8c)" style="fill: #16213e"/> - +" clip-path="url(#p33ede1bb8c)" style="fill: #d7dbe6; stroke: #16213e; stroke-width: 0.8; stroke-linejoin: miter"/> - +" clip-path="url(#p33ede1bb8c)" style="fill: #94a3b8; stroke: #16213e; stroke-width: 0.8; stroke-linejoin: miter"/> - +" clip-path="url(#p33ede1bb8c)" style="fill: #94a3b8; stroke: #16213e; stroke-width: 0.8; stroke-linejoin: miter"/> - + - +" clip-path="url(#p33ede1bb8c)" style="fill: #eef4ff; stroke: #2563eb; stroke-width: 1.3; stroke-linejoin: miter"/> - +" clip-path="url(#p33ede1bb8c)" style="fill: #eef4ff; stroke: #2563eb; stroke-width: 1.3; stroke-linejoin: miter"/> - + - + - + - + - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + - + - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #ffffff; stroke: #94a3b8; stroke-width: 0.6; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #7c3aed; opacity: 0.85; stroke: #16213e; stroke-width: 1.2; stroke-linejoin: miter"/> - +" clip-path="url(#pee94180853)" style="fill: #2563eb; opacity: 0.5"/> - + - + - + - + @@ -2536,55 +2536,55 @@ C -0.649475 1.118292 -0.331504 1.25 0 1.25 z " style="stroke: #d97706"/> - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + - + - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - + + + + + + - +" clip-path="url(#pe8a1484679)" style="fill: #eceff5; stroke: #16213e; stroke-width: 1.2; stroke-linejoin: miter"/> - + - +" clip-path="url(#pe8a1484679)" style="fill: #dc2626; stroke: #16213e; stroke-linejoin: miter"/> - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/figures/fig11_sealed_unit.png b/figures/fig11_sealed_unit.png index b8142ca..3447786 100644 Binary files a/figures/fig11_sealed_unit.png and b/figures/fig11_sealed_unit.png differ diff --git a/figures/fig11_sealed_unit.svg b/figures/fig11_sealed_unit.svg index e6a1045..a9dde60 100644 --- a/figures/fig11_sealed_unit.svg +++ b/figures/fig11_sealed_unit.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,150 +20,150 @@ - - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - + + + + - + - - - - - + - - - - - - - - - - - - - - - + + + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - + - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -1601,14 +1637,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - + - + - + - + - - - + + - + - + - - - + + + - + - + - + - - - + + - + - + - - - + + + - + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + @@ -1827,14 +1863,14 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - - + + + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + @@ -3030,357 +3066,357 @@ L -2 0 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - + + + + + - - - - - + + + + + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/figures/fig12_datasheet.png b/figures/fig12_datasheet.png index 3e864a3..33e681f 100644 Binary files a/figures/fig12_datasheet.png and b/figures/fig12_datasheet.png differ diff --git a/figures/fig12_datasheet.svg b/figures/fig12_datasheet.svg index 28ad274..7d3d2fd 100644 --- a/figures/fig12_datasheet.svg +++ b/figures/fig12_datasheet.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -715,123 +715,123 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + + + + + + - - + - - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + - - + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + - - +" clip-path="url(#p71f5c275f5)" style="fill: #2563eb; opacity: 0.04; stroke: #2563eb; stroke-linejoin: miter"/> - +" clip-path="url(#p71f5c275f5)" style="fill: #7c3aed; opacity: 0.04; stroke: #7c3aed; stroke-linejoin: miter"/> - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - + - - - - + + + - + - + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - + + + + + + - + - + - - - - - - + + + + + + - + - + - - - - - - - - - + + + + + + - + - + - - - - - - + + + + + + - + - + - - - - - + + + + + - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - - - - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4242,22 +4262,22 @@ C -2.173559 3.742521 -1.109424 4.1833 0 4.1833 z " style="stroke: #16a34a"/> - - + + - - + - + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/figures/fig13_components.png b/figures/fig13_components.png index 687dac8..96074c4 100644 Binary files a/figures/fig13_components.png and b/figures/fig13_components.png differ diff --git a/figures/fig13_components.svg b/figures/fig13_components.svg index c25c5ab..7617a00 100644 --- a/figures/fig13_components.svg +++ b/figures/fig13_components.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - + + + - + - + - - - - + + + + - + - + - + - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + @@ -268,253 +268,253 @@ L 0 2 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -889,14 +889,14 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - + + + + - + - + - - - - - + + + + + - + - + - - - - + + + + @@ -960,134 +960,134 @@ L -2 0 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + @@ -1152,29 +1152,29 @@ C -1.81853 3.131218 -0.928211 3.5 0 3.5 z " style="stroke: #2563eb"/> - - - - - - + + + + + + - - - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + - + - + - - - - - - - - - - + + + + + + + + - - + - + - - + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - + - + - - - + + - + - + - + - - - + + - - - - - - - - - - - - + + + + + + + + + + + + - + - + - + - - - - - + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - + - - - - - + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + - + - + - + - + - - - + - - - - - - - - - - - - + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - + + + + + - - + - - - - - - - + + + + + + - - - - - - - - + + + + + + + - - - - - - - + + + + + + - - - - - - - + + + + + + - - + - + - - + + - + - + - - + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/figures/fig14_compiler.png b/figures/fig14_compiler.png index b1ee31d..9f0ca7f 100644 Binary files a/figures/fig14_compiler.png and b/figures/fig14_compiler.png differ diff --git a/figures/fig14_compiler.svg b/figures/fig14_compiler.svg index 8b6a9b9..359d1b7 100644 --- a/figures/fig14_compiler.svg +++ b/figures/fig14_compiler.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - + - + - + - + - - - - - + + + - + - + - - - - + + + + - + - + - + - - - - + + + - + - + - + - - - - - + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -672,21 +672,21 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - - + + + + - + - + - - - - - + + + + + - + - + - + - - - - - + + + + - + - + - - - - - + + + + + - + - + - + - - - - - + + + + - + - + - + - - - - - + + + + @@ -933,337 +933,337 @@ L -2 0 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #94a3b8"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #16a34a"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - +" clip-path="url(#p062efe1ee0)" style="fill: #dc2626; opacity: 0.6"/> - + - + - + - - - - + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - + - + - - + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - + + + + + - + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - + - + - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/figures/fig15_neutron_gate.png b/figures/fig15_neutron_gate.png index 2da9e2b..048b188 100644 Binary files a/figures/fig15_neutron_gate.png and b/figures/fig15_neutron_gate.png differ diff --git a/figures/fig15_neutron_gate.svg b/figures/fig15_neutron_gate.svg index 2f855f7..74ef1f8 100644 --- a/figures/fig15_neutron_gate.svg +++ b/figures/fig15_neutron_gate.svg @@ -4063,9 +4063,54 @@ L 440.890966 636.761736 " clip-path="url(#p00675ee43b)" style="fill: none; stroke: #16a34a; stroke-width: 1.3; stroke-linecap: square"/> - - + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -4472,7 +4509,7 @@ L 90.310547 405.531706 " style="fill: none; stroke: #7c3aed; stroke-opacity: 0.95; stroke-width: 2.6; stroke-linecap: square"/> - + @@ -4485,29 +4522,28 @@ L 90.310547 405.531706 - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/fig16_photon_keystone.png b/figures/fig16_photon_keystone.png index cfd5a13..6f1a965 100644 Binary files a/figures/fig16_photon_keystone.png and b/figures/fig16_photon_keystone.png differ diff --git a/figures/fig17_ampoule.png b/figures/fig17_ampoule.png index 17fa91d..029c365 100644 Binary files a/figures/fig17_ampoule.png and b/figures/fig17_ampoule.png differ diff --git a/figures/fig17_ampoule.svg b/figures/fig17_ampoule.svg index 23dcca6..9af6a80 100644 --- a/figures/fig17_ampoule.svg +++ b/figures/fig17_ampoule.svg @@ -3673,9 +3673,24583 @@ L 142.72719 386.595385 z " style="fill: #ffffff"/> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5509,8 +30083,1544 @@ L 419.139569 386.595385 z " style="fill: #ffffff"/> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5908,5 +32018,8 @@ z + + + diff --git a/figures/fig18_compiled.png b/figures/fig18_compiled.png new file mode 100644 index 0000000..4ae3ecc Binary files /dev/null and b/figures/fig18_compiled.png differ diff --git a/figures/fig18_compiled.svg b/figures/fig18_compiled.svg new file mode 100644 index 0000000..ca902fb --- /dev/null +++ b/figures/fig18_compiled.svg @@ -0,0 +1,5470 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/fig2_precision_law.png b/figures/fig2_precision_law.png index 700b874..334a14e 100644 Binary files a/figures/fig2_precision_law.png and b/figures/fig2_precision_law.png differ diff --git a/figures/fig2_precision_law.svg b/figures/fig2_precision_law.svg index e12aa75..8a15c23 100644 --- a/figures/fig2_precision_law.svg +++ b/figures/fig2_precision_law.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - + - + - + - + - - + - + - + - + - - + - + - + - + - - + - + - + - + - - - - + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + @@ -636,104 +636,104 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - + - - - + - - - - - - - + + + + + - + - - - - - - - - - - - + + + + + + + + - - - + - - - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - +" clip-path="url(#p10f41847b3)" style="fill: #16a34a; opacity: 0.06; stroke: #16a34a; stroke-linejoin: miter"/> - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - - - - - - - - - - - + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - + + + + + - - - - - - - + + + + + + - - - - - - + + + + + - - + - - - - - - - - - - - - + + + + + + + + + + - - + + - - + + diff --git a/figures/fig3_keystone_gate.png b/figures/fig3_keystone_gate.png index a69c4ac..a7c433f 100644 Binary files a/figures/fig3_keystone_gate.png and b/figures/fig3_keystone_gate.png differ diff --git a/figures/fig3_keystone_gate.svg b/figures/fig3_keystone_gate.svg index c304b6e..c07d911 100644 --- a/figures/fig3_keystone_gate.svg +++ b/figures/fig3_keystone_gate.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - + + - - - - - - - - + + + + + - + - + - - + + - - - - - + + + + - + - + - - + + - - - - - + + + + - + - + - - + + - - - - - + + + + - + - + - - - - - - + + + + + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - + - + - + - - - - + + + - - + + - + - + - + - - - - - - - + + + + - - + + - + - + - + - - - - - - - + + + + - - + + - + - + - + - - - - - - - + + + + - - + + - + - + - + - - - - - - - + + + + - - + + - + - + - + - - - - + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - + - + - + - + + + + + + + - - - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - + + - - - - - - - - - - - - - - - - - + - + - - - + + + - + - + - - - - + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + + + + + + + + + + + + + + + + + + - - - + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + - + - - - - - + + + + + - + - + - + - - - - - + + + + + - + - + - + - - - - - + + + + + - + - + - + - - - - - - + + + + + - + - + - + - - - - - - + + + + + + - + - + - + - - - - - - + + + + + + - + - + - + - - - - - - + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - + + + + + + + - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - + + + + + + + + + + - - - + - - - - - - - + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4004,8 +4078,8 @@ C -2.173559 3.742521 -1.109424 4.1833 0 4.1833 z " style="stroke: #2563eb"/> - - + + @@ -4022,8 +4096,8 @@ C -2.173559 3.742521 -1.109424 4.1833 0 4.1833 z " style="stroke: #dc2626"/> - - + + @@ -4040,75 +4114,111 @@ C -2.173559 3.742521 -1.109424 4.1833 0 4.1833 z " style="stroke: #d97706"/> - - + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + - + - - - - - - - + + + + + + + - - + - + - - - - - - + + + + + + - - + - + - - - - - - + + + + + + @@ -4127,18 +4237,18 @@ L 1.279927 -1.761668 z " style="stroke: #16a34a"/> - - + + - - + + - - + + diff --git a/figures/fig4_throughput.png b/figures/fig4_throughput.png index 584abbb..82793bd 100644 Binary files a/figures/fig4_throughput.png and b/figures/fig4_throughput.png differ diff --git a/figures/fig4_throughput.svg b/figures/fig4_throughput.svg index 4d3d661..301ca20 100644 --- a/figures/fig4_throughput.svg +++ b/figures/fig4_throughput.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - + + - - - - - - + + + - + - + - - + + - - - - + + + - + - + - - + + - - - - + + + - + - + - - - - - - + + + + + + - + - + - - + + - - - - - + + + + - + - + - - - - - - + + + + + + - + - + - - - - - - + + + + + + - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - + + + + - + - + - + - - - - - - + + + + + + - + - + - + - - - - - - - - + + + + + + - + - + - + - - - - - + + + + + - + - + - + - - + + - - - - + + + - + - + - + - - - - - - + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - + - + - + - + - + - + + + + + + + - - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + - - - - - - - + + + + + - + - - - - - + + + + + - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + - + - + - - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + - + - + - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + diff --git a/figures/fig5_energy.png b/figures/fig5_energy.png index f97ddc0..a9b0d2b 100644 Binary files a/figures/fig5_energy.png and b/figures/fig5_energy.png differ diff --git a/figures/fig5_energy.svg b/figures/fig5_energy.svg index 9174dc5..c1746ba 100644 --- a/figures/fig5_energy.svg +++ b/figures/fig5_energy.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,92 +20,92 @@ - - - +" clip-path="url(#p0efe62e4ea)" style="fill: #16a34a; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #16a34a; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #2563eb; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #2563eb; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #7c3aed; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #d97706; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #dc2626; opacity: 0.85"/> - +" clip-path="url(#p0efe62e4ea)" style="fill: #16a34a; opacity: 0.05; stroke: #16a34a; stroke-linejoin: miter"/> - + @@ -114,14 +114,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - - - - - + + + + + - + - + - - - - - - + + + + + + - + - + - + - - - - - - + + + + + - + - + - + - - - - - - + + + + + - + - + - + - - - - - - + + + + + - + - + - - - - - - + + + + + + - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -908,14 +908,14 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/figures/fig6_readiness.png b/figures/fig6_readiness.png index f16ec5b..67eac59 100644 Binary files a/figures/fig6_readiness.png and b/figures/fig6_readiness.png differ diff --git a/figures/fig6_readiness.svg b/figures/fig6_readiness.svg index c815639..1a12ce8 100644 --- a/figures/fig6_readiness.svg +++ b/figures/fig6_readiness.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,44 +20,44 @@ - - - +" clip-path="url(#p012f23ad7f)" style="fill: #dc2626; opacity: 0.04; stroke: #dc2626; stroke-linejoin: miter"/> - +" clip-path="url(#p012f23ad7f)" style="fill: #16a34a; opacity: 0.05; stroke: #16a34a; stroke-linejoin: miter"/> - + @@ -66,14 +66,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - + - + - + - + - - + - + - + - + - - + - + - + - + - - + - + - + - + - - + - + - + - + - - - + + - + - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -782,32 +782,32 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - + + - + - + - + - - + - + - + - - + + - + - + - + - - + - + - + - - + + - + - + - + - - + - + - + - - - + + + - + - + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1460,23 +1467,23 @@ C -3.939909 6.783896 -2.011002 7.582875 0 7.582875 z " style="stroke: #ffffff; stroke-opacity: 0.85; stroke-width: 1.5"/> - - + + - - + + - - + + - - + + @@ -1493,13 +1500,13 @@ C -3.939909 6.783896 -2.011002 7.582875 0 7.582875 z " style="stroke: #ffffff; stroke-opacity: 0.85; stroke-width: 1.5"/> - - + + - - + + @@ -1516,8 +1523,8 @@ C -3.939909 6.783896 -2.011002 7.582875 0 7.582875 z " style="stroke: #ffffff; stroke-opacity: 0.85; stroke-width: 1.5"/> - - + + @@ -1534,20 +1541,20 @@ C -5.924122 10.200393 -3.023781 11.401754 0 11.401754 z " style="stroke: #ffffff; stroke-opacity: 0.85; stroke-width: 1.5"/> - - + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/figures/fig7_siegert.png b/figures/fig7_siegert.png index 71c103e..5fc30bd 100644 Binary files a/figures/fig7_siegert.png and b/figures/fig7_siegert.png differ diff --git a/figures/fig7_siegert.svg b/figures/fig7_siegert.svg index 5be4f04..95b760c 100644 --- a/figures/fig7_siegert.svg +++ b/figures/fig7_siegert.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,519 +20,519 @@ - - - + - - - + + - + @@ -541,14 +541,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - + - + - + - + - - + - + - + - + - - - + + - + - + - - - + + + - + - + - + - - - + + - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1383,70 +1383,70 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - + + - + - + - - - + + + - + - + - - - + + + - + - + - + - - - + + - + - + - + - - - + + - + - + - - - + + + - + - + - + - - - + + - + - + - + - - - + + - + - + - + - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - + - - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/figures/fig8_isomer_landscape.png b/figures/fig8_isomer_landscape.png index 3c0ad9f..a04adba 100644 Binary files a/figures/fig8_isomer_landscape.png and b/figures/fig8_isomer_landscape.png differ diff --git a/figures/fig8_isomer_landscape.svg b/figures/fig8_isomer_landscape.svg index f7a8620..ec59165 100644 --- a/figures/fig8_isomer_landscape.svg +++ b/figures/fig8_isomer_landscape.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,19 +20,19 @@ - - @@ -50,1891 +50,1891 @@ C -0.68734 1.183489 -0.350831 1.322876 0 1.322876 z "/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +" clip-path="url(#p11fcf8f5aa)" style="fill: #16a34a; opacity: 0.03; stroke: #16a34a; stroke-linejoin: miter"/> - + @@ -1943,14 +1943,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - + + - - - - - - - - + + + + - + - + - - + + - - - - - + + + + - + - + - - - - - - + + + + + - + - + - - - - - - - - + + + + + - + - + - - - - - - - - + + + + + - + - + - - - - - - + + + + + + + + + - + - + - - - - - - + + + + + + + + + - + - + - - - - - - + + + + + + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -2692,184 +2706,171 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - - - - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + + + + - + - + - - - - - - - + + + + @@ -2881,414 +2882,414 @@ L -2 0 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - + - - - - - - - - - - - + + + + + + - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4903,13 +4962,13 @@ C -2.464584 4.24362 -1.257969 4.743416 0 4.743416 z " style="stroke: #ffffff; stroke-width: 1.2"/> - - + + - - + + @@ -4926,8 +4985,8 @@ C -2.464584 4.24362 -1.257969 4.743416 0 4.743416 z " style="stroke: #ffffff; stroke-width: 1.2"/> - - + + @@ -4944,8 +5003,8 @@ C -2.464584 4.24362 -1.257969 4.743416 0 4.743416 z " style="stroke: #ffffff; stroke-width: 1.2"/> - - + + @@ -4962,8 +5021,8 @@ C -2.464584 4.24362 -1.257969 4.743416 0 4.743416 z " style="stroke: #ffffff; stroke-width: 1.2"/> - - + + @@ -4980,8 +5039,8 @@ C -2.464584 4.24362 -1.257969 4.743416 0 4.743416 z " style="stroke: #ffffff; stroke-width: 1.2"/> - - + + @@ -4998,65 +5057,36 @@ C -2.464584 4.24362 -1.257969 4.743416 0 4.743416 z " style="stroke: #ffffff; stroke-width: 1.2"/> - - + + - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/figures/fig9_digital_twin.png b/figures/fig9_digital_twin.png index 0b6e6f6..6310512 100644 Binary files a/figures/fig9_digital_twin.png and b/figures/fig9_digital_twin.png differ diff --git a/figures/fig9_digital_twin.svg b/figures/fig9_digital_twin.svg index c4632cf..fb4eb51 100644 --- a/figures/fig9_digital_twin.svg +++ b/figures/fig9_digital_twin.svg @@ -1,7 +1,7 @@ - + @@ -9,7 +9,7 @@ image/svg+xml - Matplotlib v3.9.4, https://matplotlib.org/ + Matplotlib v3.11.1, https://matplotlib.org/ @@ -20,28 +20,28 @@ - - - + @@ -50,14 +50,14 @@ L 0 3.5 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + - + - + - + - - - - + + + @@ -279,190 +279,190 @@ L 0 2 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + @@ -765,14 +765,14 @@ L -3.5 0 " style="stroke: #16213e; stroke-width: 0.8"/> - + - + - - - - - + + + + - + - + - + - - - - - + + + + - + - + - - - - - + + + + + @@ -863,190 +863,190 @@ L -2 0 " style="stroke: #16213e; stroke-width: 0.6"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - + + + + + + + + + - - + - + - - - - - + + + + + - + - + - - - - - - + + + + + + - + - + - - - - - - + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - + - + - - - - - + + + + + - - + + - + - + - + - - - - - + + + + + - - + + - + - + - + - - - - - + + + + + - - + + - + - + - + - - - - - + + + + + - - + + - + - + - + - - - - - + + + + + - - + + - + - + - + - - - - - + + + + + - - + + - + - + - + - - - - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - +" clip-path="url(#p225dc8d6db)" style="fill: #7c3aed"/> - +" clip-path="url(#p225dc8d6db)" style="fill: #d97706"/> - +" clip-path="url(#p225dc8d6db)" style="fill: #dc2626"/> - +" clip-path="url(#p225dc8d6db)" style="fill: #94a3b8"/> - - - + + + - + - + - + - - - - - - + + + + + + - - - + + + - + - + - + - - - - - - + + + + + + - - - + + + - + - + - + - - - - - - + + + + + + - - - + + + - + - + - + - - - - - - + + + + + + - - - + + + - + - + - + - - - - - - + + + + + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - + - + - + - - - - - - - - - - - + + + + + + + + + + - - + + - + - + - + - + - - - - - - - - - - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - - + - + - - - - - - - - - - - + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/figures/make_figures.py b/figures/make_figures.py index ec86a1a..932561e 100644 --- a/figures/make_figures.py +++ b/figures/make_figures.py @@ -247,7 +247,7 @@ def save(fig, name): # =========================================================================== # FIG 7. Emergent sigmoid: Siegert first passage firing rate (the neuron) # =========================================================================== -erf = np.vectorize(math.erf) +erfc = np.vectorize(math.erfc) # 1 + erf(u) = erfc(-u), without the cancellation that made the curve platform dependent trapezoid = getattr(np, "trapezoid", getattr(np, "trapz", None)) tau_m, t_ref = 10e-3, 2e-3 Vth, Vr, sig = 15.0, 0.0, 4.0 @@ -256,7 +256,7 @@ def save(fig, name): for mu in mus: lo, hi = (Vr-mu)/sig, (Vth-mu)/sig u = np.linspace(lo, hi, 600) - integ = trapezoid(np.exp(u**2)*(1+erf(u)), u) + integ = trapezoid(np.exp(u**2)*erfc(-u), u) nu = 1.0/(t_ref + tau_m*math.sqrt(math.pi)*integ) nus.append(nu) nus = np.array(nus) diff --git a/gates/candidates.csv b/gates/candidates.csv index 5218e18..1380893 100644 --- a/gates/candidates.csv +++ b/gates/candidates.csv @@ -8,8 +8,8 @@ key,E_keV,t_half_s,beta_gamma,beta_note,mech,E_trig_keV,leverage,status,cite 177mLu,970.18,13858560.0,5.85,ENSDF cascade (21.4% IT branch),proposed photodepletion (high K),,,no demonstrated trigger,ENSDF; depletion proposals in literature 108mAg,109.44,13821933588.0,3.6,ENSDF cascade (mostly EC branch),none demonstrated,,,storage only,ENSDF 166mHo,5.98,37868311200.0,3.7,beta decay follows,none demonstrated,,,storage only,ENSDF -137mBa,661.66,153.12,1.0,the 662 keV line,readout reference (Cs-137 generator),,,readout workhorse,ENSDF -99mTc,142.68,21625.199999999997,0.98,the 140 keV line,availability reference (Mo-99 generator),,,most available isomer on Earth,ENSDF +137mBa,661.66,153.12,1.0,the 662 keV line,readout reference (¹³⁷Cs generator),,,readout workhorse,ENSDF +99mTc,142.68,21625.199999999997,0.98,the 140 keV line,availability reference (⁹⁹Mo generator),,,most available isomer on Earth,ENSDF 57mFe,14.41,9.83e-08,1.0,"Mossbauer coherence, not memory","nuclear forward scattering (coherent, directional)",14.41,1.0,Tier 2 interconnect reference,routine at ESRF ID18 / APS 3-ID "235U (n_th, f)",202000.0,2.2216075904e+16,9.4,nu-bar 2.43 neutrons + ~7 prompt gamma,"thermal neutron induced fission, sigma_f = 585 b",2.5e-08,8080000000000.0,"PROVEN, tabulated to 4 digits",ENDF/B-VIII.0 "9Be (n, 2n)",,stable,2.0,2 neutrons out per fast neutron in,"threshold reaction, E_n > 1.85 MeV, sigma ~ 0.5 b",1850.0,,PROVEN (standard reflector physics),ENDF/B-VIII.0 diff --git a/gates/candidates.md b/gates/candidates.md index 5a1f648..d3947d9 100644 --- a/gates/candidates.md +++ b/gates/candidates.md @@ -9,8 +9,8 @@ | 177mLu | 970.18 keV | 160 d | 5.00e-08 | 5.85 | proposed photodepletion (high K) | | | no demonstrated trigger | | 108mAg | 109.44 keV | 438 y | 5.01e-11 | 3.6 | none demonstrated | | | storage only | | 166mHo | 5.98 keV | 1.2e+03 y | 1.83e-11 | 3.7 | none demonstrated | | | storage only | -| 137mBa | 661.66 keV | 2.55 min | 4.53e-03 | 1 | readout reference (Cs-137 generator) | | | readout workhorse | -| 99mTc | 142.68 keV | 6.01 h | 3.21e-05 | 0.98 | availability reference (Mo-99 generator) | | | most available isomer on Earth | +| 137mBa | 661.66 keV | 2.55 min | 4.53e-03 | 1 | readout reference (¹³⁷Cs generator) | | | readout workhorse | +| 99mTc | 142.68 keV | 6.01 h | 3.21e-05 | 0.98 | availability reference (⁹⁹Mo generator) | | | most available isomer on Earth | | 57mFe | 14.41 keV | 98.3 ns | 7.05e+06 | 1 | nuclear forward scattering (coherent, directional) | 14.41 keV | 1 | Tier 2 interconnect reference | | 235U (n_th, f) | 202000 keV | 7.04e+08 y | 3.12e-17 | 9.4 | thermal neutron induced fission, sigma_f = 585 b | 2.5e-08 keV | 8.08e+12 | PROVEN, tabulated to 4 digits | | 9Be (n, 2n) | (binding energy) | stable | 0 | 2 | threshold reaction, E_n > 1.85 MeV, sigma ~ 0.5 b | 1850 keV | | PROVEN (standard reflector physics) | diff --git a/gates/isomer_screen.py b/gates/isomer_screen.py index b3c5d1e..0708d98 100644 --- a/gates/isomer_screen.py +++ b/gates/isomer_screen.py @@ -187,12 +187,12 @@ def gamma_multiplicity(nuclide, parent_E_keV, tol=2.0): cite="ENSDF"), dict(key="137mBa", livechart="137ba", E_keV=661.66, t_half_s=2.552 * 60, beta_note="the 662 keV line", - beta_gamma=None, mech="readout reference (Cs-137 generator)", + beta_gamma=None, mech="readout reference (¹³⁷Cs generator)", E_trig_keV=None, status="readout workhorse", cite="ENSDF"), dict(key="99mTc", livechart="99tc", E_keV=142.68, t_half_s=6.007 * 3600, beta_note="the 140 keV line", - beta_gamma=None, mech="availability reference (Mo-99 generator)", + beta_gamma=None, mech="availability reference (⁹⁹Mo generator)", E_trig_keV=None, status="most available isomer on Earth", cite="ENSDF"), dict(key="57mFe", livechart=None, E_keV=14.41, diff --git a/index.html b/index.html index 34503be..003f83d 100644 --- a/index.html +++ b/index.html @@ -425,7 +425,7 @@

A falsifiable roadmap (with ki ampoule/ -the sealed machine in real photon transport: the vessel of the build note in OpenMC with ENDF/B-VIII.0 photoatomic data and its own beta spectra, calibrated against XCOM and the thick target rule; the photon budget, site rates in plastic and in CsI, pile up, the collar's transfer curve, the 64 × 64 Green's function and what the septum does to it, the boundary count rate, the energy budget, and the dose outside +the sealed machine in real photon transport: the vessel of the build note in OpenMC with ENDF/B-VIII.0 photoatomic data and its own beta spectra, calibrated against XCOM and the thick target rule; the photon budget, site rates in plastic and in CsI, pile up, the collar's transfer curve, the 64 × 64 Green's function and what the septum does to it, the boundary count rate, the energy budget, and the dose outside; then the compiler run on that Green's function (Way B and the collar pass, the crosstalk it cannot remove, the exact law at 64 sites by transfer matrix) and the timing closure that prices every synapse as a photon rate and the vessel's sample rate as built transistor/ @@ -518,14 +518,14 @@

The ampoule: the machine, sealed

Where this all goes is the subject of transistor/SCALING.md, the ENIAC ledger: every component with its improvement lever, its physical ceiling, and whose industrial curve improves it for free (timing and collection ride PET and high energy physics; memory rides the nuclear clock laser program; sources ride isotope production). The machine starts nine orders of magnitude past ENIAC per operation on decay heat alone, and catalog technology, with no new physics, carries the sampler another five to six orders. The primitives are not placeholders: every lever multiplies the same counting, thinning, and coincidence the theory is written in.


The keystone, computed: the neutron gate at k below one

-

The claim that the keystone already exists in the neutron sector has, until now, been arithmetic on library constants and a citation to a 1958 paper. It is now a calculation. neutron/ builds the reference transistor's third scale in OpenMC with the official ENDF/B-VIII.0 library: two 72 litre tanks of 4.9 percent enriched uranyl fluoride solution (the composition of a handbook criticality benchmark, so every atom density is published), each at k ≈ 0.901 alone, standing 3 cm of water apart in a water bath, with an absorber that can be lowered between them and a Cf-252 point source in one tank. Before the gate is computed the same code and data reproduce three handbook criticals (neutron/results.md, Section 0), so the instrument is calibrated the way a criticality safety calculation is.

+

The claim that the keystone already exists in the neutron sector has, until now, been arithmetic on library constants and a citation to a 1958 paper. It is now a calculation. neutron/ builds the reference transistor's third scale in OpenMC with the official ENDF/B-VIII.0 library: two 72 litre tanks of 4.9 percent enriched uranyl fluoride solution (the composition of a handbook criticality benchmark, so every atom density is published), each at k ≈ 0.901 alone, standing 3 cm of water apart in a water bath, with an absorber that can be lowered between them and a ²⁵²Cf point source in one tank. Before the gate is computed the same code and data reproduce three handbook criticals (neutron/results.md, Section 0), so the instrument is calibrated the way a criticality safety calculation is.

Every number below carries a Monte Carlo uncertainty, and every configuration is strictly subcritical.

@@ -554,12 +554,24 @@

The ampoule, transported

The ampoule in photon transport

The machine the theory can seal today is therefore a rate coded sampler whose photons are hard, whose weights are small, whose mouth is narrower than it was priced, and whose two mechanical controls are analog. Every one of those adjectives was an adjective; each is now a number, and the notes are corrected where the numbers say so.


+

The vessel, compiled: what a gigabecquerel buys

+

The compiler of the theory (Section 11) had run only on a toy fabric, and Open Problem 4 asked for it to be run on a real geometry. ampoule/ now has one: the 64 × 64 Green's function of the transported vessel is the fabric, the digital twin's instance restricted to the vessel's own lattice (eight rings of eight sites, ring bonds and axial bonds) is the program, and ampoule/compile.py does with them what a compiler does, in ampoule/compile_results.md: it places the instance, reports what the fabric adds that was not asked for, and closes the timing.

+ +

The vessel, compiled

+

What changes in the theory is one sentence and one number. The twin's 26 decays per sample priced the machine's proposals and assumed its weighted sums were known at each one; in matter the weighted sum is a count, the precision law prices it, and in this vessel it is the slow part by five orders of magnitude. The machine note's throughput is amended to what the transport and the compiler say it is, the reset ledger of the theory gains the synapse term, and the ENIAC ledger gains the row that carries it back.

+

Open problems and how to contribute

  1. Keystone: propose or measure a compact state meeting the leak condition with β>1 in a level restoring or convertible class (theory, Section 2). This is problem number one. A concrete, computable subproblem: search ENSDF for heterogeneous pairs of isomers whose cascade lines and gateway lines are mutually resonant (gate A's output pumps gate B and vice versa); the search space is already tabulated in /gates. The computed neutron gate (neutron/) adds a second requirement that the photon sector had not been asked for: the state must also supply a signal controlled inhibition, because the only one the neutron sector has is heat and it is worth a fraction of the gain. A gate with gain but no inversion is a linear amplifier with a comparator bolted to its boundary, and the machine it builds is the Bernstein machine of Section 6 with better numbers, not a logic family.
  2. Tighten the throughput law for fan out reuse: when is a count "spent"?
  3. A learning rule: aperture update Δα ∝ coincidence(pre,post) is Hebbian or STDP using the same coincidence primitive as the AND gate (Appendix B.4); formalize and simulate.
  4. -
  5. Transport level 𝒢 for a real geometry that implements a target weight matrix (signed weights via complementary channels). The measurement half is done: ampoule/ has the 64 × 64 Green's function of the build note's compute shell, nearest neighbour weights of 3×10⁻⁵ per photon with 0.1% total fan out; what remains is to run the compiler of theory Section 11 on that geometry rather than on the toy fabric.
  6. +
  7. Transport level 𝒢 for a real geometry that implements a target weight matrix (signed weights via complementary channels). Done, in ampoule/: the 64 × 64 Green's function of the build note's compute shell is measured, nearest neighbour weights of 3×10⁻⁵ per photon with 0.1% total fan out, and the compiler has been run on it, Way B with the collar pass, and the timing closed (ampoule/compile_results.md). What remains is the vessel the result asks for: a compute shell whose couplings are collimated sight lines rather than scattering, so that a nearest neighbour instance is not buried by the far couplings, and a boundary with enough distinguishable channels for Way C to see the shell it trims.
  8. Tier 2: a concrete two qubit gate on nuclear spin or Mössbauer DOF with a room temperature error budget.
  9. The addressed long retention write. The broadband route to self written memory is dead by a bandwidth ratio of 10¹⁸, and the narrowline route is now open in principle (nuclear lamps, radiogenic feeding, resonance addressing: theory Section 9); what remains is a state that is simultaneously parent fed, gradient addressable, and long lived. A concrete, computable search: scan the catalog in /gates for isomers with lifetime above seconds whose feeding parents emit Mössbauer class lines, and rank by the addressing sensitivity Γ/(dE/dB).
  10. Measure realized bits per detected quantum for a pixelated spectroscopic boundary against the log_2(N_E N_x N_τ) ceiling of the boundary theory. The boundary's raw budget is now computed, 3.25 M/s detected in the build note's ring, 0.33× what it was priced at (ampoule/); the ceiling is still to be measured against it.
  11. diff --git a/neutron/README.md b/neutron/README.md index 50816ff..d0c68e4 100644 --- a/neutron/README.md +++ b/neutron/README.md @@ -18,7 +18,7 @@ The tank of the transistor note's third scale, drawn to a size a criticality saf - two identical cylindrical tanks, 24 cm inner radius, 40 cm of solution, 1.6 mm type 1100 aluminium shells, 72 litres each, of 4.9 percent enriched uranyl fluoride solution: the benchmark model composition of handbook case LEU-SOL-THERM-002, which is why every atom density in the model is a published number and not a choice; - standing side by side in a water bath, axes 3 cm of water apart at the walls, 20 cm of water beyond the tanks on every side: the moderator is the BODY; - an absorber that can be lowered into the water between them: the GATE. Two are computed, a 1 mm cadmium sheet (the classic thermal filter, insertable in quarters, so that its transfer curve is a curve) and a 2 cm natural boron carbide blade, each overhanging the tanks by 6 cm; -- a point source on the axis of tank A, the SOURCE: Cf-252 (Fröhner's Watt fit, mean 2.13 MeV), the driver of every source driven subcritical assembly ever built for teaching; a second source on the axis of B for the coincidence gate, and a 14.1 MeV point source there for the fusion driven case of the nomenclature section; +- a point source on the axis of tank A, the SOURCE: ²⁵²Cf (Fröhner's Watt fit, mean 2.13 MeV), the driver of every source driven subcritical assembly ever built for teaching; a second source on the axis of B for the coincidence gate, and a 14.1 MeV point source there for the fusion driven case of the nomenclature section; - the fission rate in tank B, the DRAIN; the neutron population in B, the CHANNEL. The dimensions were chosen so that a tank alone sits at k ≈ 0.90, the working point the transistor note names. Nothing else was tuned. diff --git a/neutron/benchmarks.json b/neutron/benchmarks.json index 0129d25..bb7b6af 100644 --- a/neutron/benchmarks.json +++ b/neutron/benchmarks.json @@ -1,7 +1,7 @@ { "provenance": { "openmc_version": "0.16.0", - "cross_sections": "/private/tmp/claude-501/-Users-maxmoussa-Claude/24fa5303-a712-43bf-9ff2-c92c88f6a9a0/scratchpad/nuclear-computing/neutron/data/endfb-viii.0-hdf5/cross_sections.xml", + "cross_sections": "endfb-viii.0-hdf5/cross_sections.xml (the official OpenMC ENDF/B-VIII.0 distribution, fetched and verified by neutron/data.py)", "particles": 10000, "batches": 420, "inactive": 40 diff --git a/neutron/report.py b/neutron/report.py index c25da68..243af4f 100644 --- a/neutron/report.py +++ b/neutron/report.py @@ -317,7 +317,7 @@ def absorbed(r, key): # ---- 4. the gate ---------------------------------------------------------- say("## 4. The gate: driven, with multiplication on\n") - say("A Cf-252 point source (Fröhner Watt spectrum, mean 2.13 MeV) or a 14.1 MeV deuterium tritium " + say("A ²⁵²Cf point source (Fröhner Watt spectrum, mean 2.13 MeV) or a 14.1 MeV deuterium tritium " "point source on the axis of a tank is the SOURCE terminal. Fixed source transport with full " "multiplication gives the steady fission neutron production in each tank per driver neutron; " "production in B is the DRAIN current. The point model of coupled regions predicts the same " @@ -399,7 +399,7 @@ def absorbed(r, key): say("|---|---|---|---|---|") spectra = {} for drive, desc in (("cfA", "the leakage of tank A, through 3 cm of water"), - ("cfB", "a Cf-252 spectrum at the axis, mean 2.13 MeV"), + ("cfB", "a ²⁵²Cf spectrum at the axis, mean 2.13 MeV"), ("dtB", "a 14.1 MeV line at the axis")): r = runs[f"gate_{drive}_open"] chi, e_chi, _ = spectrum(r, "chi_B", edges) @@ -550,7 +550,7 @@ def figure(curve, runs, P, spectra, edges, ts, Pt, Pinf, L, kpair): # C: level restoration. The three outputs coincide, so draw them so that is visible. mid = np.sqrt(edges[:-1] * edges[1:]) styles = [("cfA", BLUE, 5.0, 0.30, "driven from tank A (moderated input)"), - ("cfB", PURPLE, 2.6, 0.95, "Cf-252 at the axis of B"), + ("cfB", PURPLE, 2.6, 0.95, "²⁵²Cf at the axis of B"), ("dtB", GREEN, 1.3, 1.00, "14.1 MeV at the axis of B")] for drive, c, lw, al, lab in styles: C.step(mid, spectra[drive][0], where="mid", color=c, lw=lw, alpha=al, @@ -558,7 +558,7 @@ def figure(curve, runs, P, spectra, edges, ts, Pt, Pinf, L, kpair): arr = spectra["cfA"][1] C.step(mid, arr * (spectra["cfA"][0].max() / max(arr.max(), 1e-30)), where="mid", color=AMBER, lw=1.6, ls="--", label="input: entering B through its wall (scaled)", zorder=2) - for e_in, lab, frac, ha in ((2.13e6, "Cf-252 mean input\n2.13 MeV", 0.72, "right"), + for e_in, lab, frac, ha in ((2.13e6, "²⁵²Cf mean input\n2.13 MeV", 0.72, "right"), (14.1e6, "14.1 MeV\ninput line", 0.50, "left")): C.axvline(e_in, color=GREY, ls=":", lw=1.2, zorder=1) pad = " " if ha == "left" else "" diff --git a/neutron/results.md b/neutron/results.md index f575e13..aa45349 100644 --- a/neutron/results.md +++ b/neutron/results.md @@ -130,7 +130,7 @@ The cadmium sheet cuts the coupling k_BA by a factor 1.7, the boron carbide blad ## 4. The gate: driven, with multiplication on -A Cf-252 point source (Fröhner Watt spectrum, mean 2.13 MeV) or a 14.1 MeV deuterium tritium point source on the axis of a tank is the SOURCE terminal. Fixed source transport with full multiplication gives the steady fission neutron production in each tank per driver neutron; production in B is the DRAIN current. The point model of coupled regions predicts the same numbers from Section 3 and the first generation response c of each tank to the driver, P = (I - K)⁻¹ c, and the comparison is reported because the gap is physics, not noise. +A ²⁵²Cf point source (Fröhner Watt spectrum, mean 2.13 MeV) or a 14.1 MeV deuterium tritium point source on the axis of a tank is the SOURCE terminal. Fixed source transport with full multiplication gives the steady fission neutron production in each tank per driver neutron; production in B is the DRAIN current. The point model of coupled regions predicts the same numbers from Section 3 and the first generation response c of each tank to the driver, P = (I - K)⁻¹ c, and the comparison is reported because the gap is physics, not noise. | drive | absorber | c_A | c_B | P_A transport | P_B transport | P_A point model | P_B point model | 1 + P_A + P_B | |---|---|---|---|---|---|---|---|---| @@ -176,7 +176,7 @@ In a linear medium the coincidence AND is a threshold on a weighted sum, a perce | drive (open) | the input to tank B | mean energy crossing B's wall | fraction of that below 0.625 eV | mean energy of fission neutrons born in B | |---|---|---|---|---| | cfA | the leakage of tank A, through 3 cm of water | 0.251 MeV | 0.67 | 2.011 MeV | -| cfB | a Cf-252 spectrum at the axis, mean 2.13 MeV | 0.089 MeV | 0.73 | 2.008 MeV | +| cfB | a ²⁵²Cf spectrum at the axis, mean 2.13 MeV | 0.089 MeV | 0.73 | 2.008 MeV | | dtB | a 14.1 MeV line at the axis | 0.116 MeV | 0.72 | 2.009 MeV | Read the middle columns with care. When A is driven, everything tank B receives crosses its wall, and it arrives moderated: 0.251 MeV on average, 67% of it already thermal, because 3 cm of water is a moderator as well as a gap. In the other two rows the driver sits inside B, so the wall current is only the return from the water reflector and the input proper is the point source itself: a 2 MeV fission spectrum, and a 14.1 MeV line. diff --git a/neutron/tallies.json b/neutron/tallies.json index c232c05..ae62836 100644 --- a/neutron/tallies.json +++ b/neutron/tallies.json @@ -11899,7 +11899,7 @@ }, "provenance": { "openmc_version": "0.16.0", - "cross_sections": "/private/tmp/claude-501/-Users-maxmoussa-Claude/24fa5303-a712-43bf-9ff2-c92c88f6a9a0/scratchpad/xsdata/official/endfb-viii.0-hdf5/cross_sections.xml", + "cross_sections": "endfb-viii.0-hdf5/cross_sections.xml (the official OpenMC ENDF/B-VIII.0 distribution, fetched and verified by neutron/data.py)", "library": "ENDF/B-VIII.0, official OpenMC HDF5 distribution (openmc.org)", "budget": "full", "budget_numbers": { diff --git a/photon/census.py b/photon/census.py index b78e0b1..02ec056 100644 --- a/photon/census.py +++ b/photon/census.py @@ -56,6 +56,7 @@ """ import csv import gzip +import io import json import math import os @@ -406,7 +407,8 @@ def write_csv(path, rows, drop=()): open(path, "w").write("") return cols = [c for c in rows[0] if c not in drop] - opener = (lambda: gzip.open(path, "wt", newline="")) if path.endswith(".gz") else (lambda: open(path, "w", newline="")) + opener = ((lambda: io.TextIOWrapper(gzip.GzipFile(path, "wb", mtime=0), encoding="utf-8", newline="")) + if path.endswith(".gz") else (lambda: open(path, "w", newline=""))) # mtime 0: the file is byte identical run to run with opener() as f: w = csv.DictWriter(f, fieldnames=cols, extrasaction="ignore") w.writeheader() diff --git a/photon/ensdf.py b/photon/ensdf.py index 4bdf27b..58c8b1f 100644 --- a/photon/ensdf.py +++ b/photon/ensdf.py @@ -171,7 +171,7 @@ def main(): "jp": r["Jpi"], "modes": r["decay_modes"]} for r in keep[(Z, A)]]} if (n + 1) % 25 == 0: print(f" {n+1}/{len(keep)} nuclides, {time.time()-t0:.0f} s", flush=True) - with gzip.open(PACKED, "wt", encoding="utf-8") as f: + with io.TextIOWrapper(gzip.GzipFile(PACKED, "wb", mtime=0), encoding="utf-8") as f: # mtime 0: byte identical run to run json.dump({"source": "IAEA Live Chart of Nuclides, ENSDF adopted levels and gammas", "t_min_s": T_MIN, "nuclides": packed, "failed": failed}, f) nl = sum(len(v["levels"]) for v in packed.values()) diff --git a/photon/levels.json.gz b/photon/levels.json.gz index 96ab391..88a8bff 100644 Binary files a/photon/levels.json.gz and b/photon/levels.json.gz differ diff --git a/photon/pairs.csv.gz b/photon/pairs.csv.gz index be8a5d9..7dc52d4 100644 Binary files a/photon/pairs.csv.gz and b/photon/pairs.csv.gz differ diff --git a/reproduce.py b/reproduce.py new file mode 100644 index 0000000..a463689 --- /dev/null +++ b/reproduce.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +""" +Recompute every number, table and figure in the repository from the +committed data, in the order the CI does it, and say whether the tree came +back the same. + + python reproduce.py run every step, about two minutes + python reproduce.py --check run every step, then fail if any tracked + file other than a PNG differs from HEAD + or any new file appeared + python reproduce.py --list print the steps and stop + python reproduce.py --only gates,simulator + run the steps whose script path contains + one of the substrings + +The steps are the ones .github/workflows/build.yml runs, and a test +(tests/test_repository.py) fails if the two lists drift apart. Nothing here +needs the network or OpenMC: the three transport directories are reported +from their committed tallies, and the OpenMC runs that regenerate those +tallies live in .github/workflows/openmc.yml and the Dockerfile. + +What "the same" means. Every results file, CSV, JSON and SVG figure is +compared byte for byte, and under the pinned requirements.txt they match +on macOS and on Linux: the numbers are deterministic (seeded generators, +committed inputs) and the SVGs are drawn as vectors with no date and no +embedded raster. PNG figures are rasterised by the platform's own font and +antialiasing libraries and differ between operating systems by a few pixels, +so they are regenerated but not compared. +""" +import argparse +import os +import subprocess +import sys +import time + +ROOT = os.path.dirname(os.path.abspath(__file__)) + +# (script, what it regenerates); the order matters where a later step reads an earlier one's output +STEPS = [ + ("figures/make_figures.py", "figures 2 to 7: the laws, the keystone criterion, readiness"), + ("gates/isomer_screen.py", "the isomer catalogue, the candidate table, figure 8 (cached IAEA data)"), + ("transport/gate_demos.py", "the routine gates, transport/results.md"), + ("transport/degree_check.py", "the degree checker, transport/degree_results.md"), + ("transport/compiler_demo.py", "the compiler three ways, figure 14"), + ("gates/edm_plan.py", "the energy division channel plan"), + ("simulator/nuclear_ising.py", "the digital twin, figure 9"), + ("simulator/components.py", "the component proofs of concept, figure 13"), + ("transistor/make_transistor_figure.py", "figure 10"), + ("transistor/make_datasheet_figure.py", "figure 12"), + ("transistor/sealed_unit.py", "the ampoule computed, figure 11"), + ("neutron/report.py", "the neutron gate from its committed tallies, figure 15"), + ("photon/census.py", "the photon keystone census from the committed level schemes, figure 16"), + ("ampoule/report.py", "the ampoule from its committed tallies, figure 17"), + ("ampoule/compile.py", "the vessel compiled, figure 18"), + ("build_html.py", "index.html"), +] + + +def git(*args): + return subprocess.run(["git", *args], cwd=ROOT, capture_output=True, text=True, check=True).stdout + + +def main(): + ap = argparse.ArgumentParser(description=__doc__.split("\n\n")[0]) + ap.add_argument("--check", action="store_true", help="fail unless the tree (PNGs aside) is unchanged afterwards") + ap.add_argument("--list", action="store_true", help="print the steps and stop") + ap.add_argument("--only", default="", help="comma separated substrings of script paths to run") + args = ap.parse_args() + + steps = [s for s in STEPS if not args.only or any(k in s[0] for k in args.only.split(","))] + if args.list: + for script, what in steps: + print(f"{script:40s} {what}") + return 0 + + t_all = time.time() + for script, what in steps: + t0 = time.time() + print(f"== {script}: {what}", flush=True) + r = subprocess.run([sys.executable, os.path.join(ROOT, script)], cwd=ROOT, + capture_output=True, text=True) + if r.returncode != 0: + print(r.stdout[-4000:]) + print(r.stderr[-4000:]) + print(f"FAILED: {script}") + return 1 + print(f" ok, {time.time() - t0:.0f} s", flush=True) + print(f"all {len(steps)} steps ran in {time.time() - t_all:.0f} s") + + if not args.check: + return 0 + changed = [l[3:] for l in git("status", "--porcelain", "--untracked-files=all").splitlines()] + changed = [p for p in changed if not p.lower().endswith(".png")] + if changed: + print("the tree is not the same after regeneration:") + for p in changed: + print(" ", p) + print("(a changed results file means a number moved; a changed SVG means a figure moved; " + "a new file means a step wrote something the repository does not track)") + text = [p for p in changed if p.endswith((".md", ".csv", ".txt", ".json", ".cff"))] + if text: + print("what moved in the text outputs:") + print(subprocess.run(["git", "--no-pager", "diff", "--", *text], cwd=ROOT, + capture_output=True, text=True).stdout[:12000]) + return 2 + print("the tree is the same after regeneration: every number, table and vector figure reproduced byte for byte") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/requirements.txt b/requirements.txt index 5272666..0842be5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -numpy -matplotlib -markdown +numpy==2.5.2 +matplotlib==3.11.1 +markdown==3.10.3 diff --git a/simulator/README.md b/simulator/README.md index fa41544..6d3a9f1 100644 --- a/simulator/README.md +++ b/simulator/README.md @@ -18,4 +18,6 @@ python3 nuclear_ising.py Requires `numpy`; `matplotlib` for the figure. +The same sampler at 64 sites, on the ampoule's own lattice, is checked against an exact transfer matrix in [ampoule/compile.py](../ampoule/compile.py): 3.3 sweeps per independent sample, the 8 site cost unchanged by an eightfold larger machine. + `components.py` extends the twin with proofs of concept for the remaining machine components: the MUX adder (exact to counting noise), the divide by N clock (jitter exactly 1/√N), the bistable cell (a written bit dies below loop gain 1 and latches above it: the keystone, measured as a memory requirement), and the modulated glow telemetry link (bit error rate versus symbol time over the Poisson counting channel). Results in `components_results.md` and figure 13. diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..6d53c22 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,42 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +"""Shared helpers: the repository root, the tracked files, and a loader for +the scripts, which are written to be run and not imported.""" +import importlib.util +import os +import subprocess +import sys + +import pytest + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +def tracked(suffix=""): + """Every file git tracks, optionally filtered by suffix.""" + out = subprocess.run(["git", "ls-files"], cwd=ROOT, capture_output=True, text=True, check=True).stdout + return [p for p in out.splitlines() if p.endswith(suffix)] + + +def read(path): + return open(os.path.join(ROOT, path), encoding="utf-8").read() + + +def load_script(path, name=None): + """Import a script by path without running its main(); the neutron and + ampoule directories are put on sys.path the way the scripts expect.""" + full = os.path.join(ROOT, path) + name = name or os.path.basename(path)[:-3] + "_under_test" + for d in ("neutron", "ampoule", "gates"): + p = os.path.join(ROOT, d) + if p not in sys.path: + sys.path.insert(0, p) + spec = importlib.util.spec_from_file_location(name, full) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +@pytest.fixture(scope="session") +def root(): + return ROOT diff --git a/tests/test_links.py b/tests/test_links.py new file mode 100644 index 0000000..3f65df2 --- /dev/null +++ b/tests/test_links.py @@ -0,0 +1,37 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +"""Every relative link and image in the documents points at a file that +exists. The repository cross references itself hundreds of times; a renamed +directory or figure must not leave a dead link behind.""" +import os +import re + +from conftest import ROOT, read, tracked + +LINK = re.compile(r"!?\[[^\]]*\]\(([^)\s]*[./#][^)\s]*)\)") # a target with a slash, a dot or an anchor: not the (x) of B_n[f](x) + + +def test_every_relative_link_and_image_resolves(): + dead = [] + for p in tracked(".md"): + base = os.path.dirname(os.path.join(ROOT, p)) + for target in LINK.findall(read(p)): + if target.startswith(("http://", "https://", "mailto:", "#")): + continue + path = target.split("#")[0] + if not path: + continue + if not os.path.exists(os.path.normpath(os.path.join(base, path))): + dead.append((p, target)) + assert not dead, f"dead links: {dead}" + + +def test_every_figure_the_documents_show_is_regenerated_by_a_script(): + shown = set() + for p in tracked(".md"): + for target in LINK.findall(read(p)): + if target.endswith(".svg") and "figures/" in target: + shown.add(os.path.basename(target)) + scripts = "\n".join(read(p) for p in tracked(".py")) + orphans = sorted(s for s in shown if s[:-4] not in scripts and s != "fig1_architecture.svg") + assert not orphans, f"figures shown but not generated by any script: {orphans}" diff --git a/tests/test_numbers.py b/tests/test_numbers.py new file mode 100644 index 0000000..88a9ec6 --- /dev/null +++ b/tests/test_numbers.py @@ -0,0 +1,116 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +"""Every headline number the documents quote is read back from the file that +computes it. The results files are regenerated before the tests run, so a +number that moves in a computation and not in the prose fails here; the +180mTa correction of the first edition's erratum was exactly this class of +drift, between a curated table and a generated one. + +Each check names the generated file, a pattern that captures the number +there, and the documents that must quote it in the form given.""" +import csv +import re + +import pytest + +from conftest import ROOT, read + + +def captured(path, pattern): + m = re.search(pattern, read(path)) + assert m, f"{path}: nothing matches {pattern!r}" + return m.group(1) + + +def candidate(key, column): + for row in csv.DictReader(open(f"{ROOT}/gates/candidates.csv", encoding="utf-8")): + if row["key"] == key: + return row[column] + raise AssertionError(f"no candidate {key}") + + +# (generated file, capture pattern, {document: [forms the document must contain, with {v} for the value]}) +CHECKS = [ + ("neutron/results.md", r"Drain per source neutron with the gate open: \*\*([\d.]+)\*\*", + {"README.md": ["{v} fission neutrons", "{v} with the gate open"], "theory/THEORY.md": ["becomes {v} fission neutrons"], + "transistor/README.md": ["a drain of {v} fission neutrons"], "neutron/README.md": ["**{v} fission neutrons in B"]}), + ("neutron/results.md", r"gain bandwidth product M/τ = 1/Λ = \*\*([\d.]+) kHz\*\*", + {"README.md": ["1/Λ = {v} kHz", "**{v} kHz**"], "theory/THEORY.md": ["1/Λ = {v} kHz"], "transistor/README.md": ["{v} kHz"]}), + ("neutron/results.md", r"temperature coefficient \*\*(-\d+) pcm/K\*\*", + {"README.md": ["{v} pcm/K"], "theory/THEORY.md": ["{v} pcm/K"]}), + ("neutron/results.md", r"dominant eigenvalue of K \*\*([\d.]+) ± [\d.]+\*\* against k \*\*([\d.]+)", + {"README.md": ["eigenvalue {v}"], "theory/THEORY.md": ["dominant eigenvalue {v}"]}), + ("neutron/results.md", r"generation time of the pair Λ = \*\*(\d+)\.\d µs\*\*", + {"README.md": ["Λ = {v} µs"], "theory/THEORY.md": ["generation time is {v} µs"]}), + ("photon/results.md", r"\| coincidences compatible with resonance within one standard deviation of the data \| (\d+) \|", + {"README.md": ["{v} release lines"], "theory/THEORY.md": ["{v} coincidences"]}), + ("photon/results.md", r"\| of which heterogeneous \(different nuclides\) \| (\d+) \|", + {"README.md": ["{v} of them"], "theory/THEORY.md": ["{v} of them heterogeneous"]}), + ("photon/results.md", r"\| of which closed loops, A triggers B and B triggers A \| (\d+) \|", + {"README.md": ["{v} closed loops"], "theory/THEORY.md": ["{v} closed loops"]}), + ("photon/results.md", r"\| isomers with a signal gateway and a veto gateway \| (\d+) \|", + {"README.md": ["{v} isomers offer a signal gateway"], "theory/THEORY.md": ["counts {v} such isomers"]}), + ("photon/results.md", r"\| NEEC class gateways \(within 30 keV of the isomer\) \| \d+, of which (\d+) release \|", + {"README.md": ["{v} releasing gateways"], "theory/THEORY.md": ["NEEC class of {v} gateways"]}), + ("ampoule/results.md", r"photons leaving the source capsule into the lamp cell: \*\*([\d.]+ M/s)\*\*", + {"README.md": ["**{v}** leave the core"], "transistor/SEALED.md": ["sends {v} of bremsstrahlung"]}), + ("ampoule/results.md", r"detected boundary events: \*\*([\d.]+ M/s)\*\*", + {"README.md": ["counts **{v}**"], "transistor/SEALED.md": ["boundary counts {v}"], "transistor/EMBODIMENT.md": ["sees {v}"]}), + ("ampoule/results.md", r"\*\*the same shell with CsI cells\*\*.*?\*\*([\d.]+ M/s)\*\* over all 64", + {"README.md": ["**{v}**, 31× more"], "transistor/SEALED.md": ["CsI, at {v}"], "transistor/EMBODIMENT.md": ["{v} in all"]}), + ("ampoule/results.md", r"ON/OFF contrast of the collar: \*\*([\d.]+)\*\*", + {"README.md": ["contrast of {v} with plastic"], "transistor/SEALED.md": ["contrast of {v}"], "transistor/EMBODIMENT.md": ["contrast is {v} with plastic"]}), + ("ampoule/results.md", r"\| at the titanium wall \| \*\*([\d.]+) µSv/h\*\* \|", + {"README.md": ["**{v} µSv/h** at the titanium wall"], "transistor/SEALED.md": ["{v} µSv/h at contact"], "transistor/EMBODIMENT.md": ["{v} µSv/h at the titanium wall"]}), + ("ampoule/results.md", r"\| 1 m from the centre \| \*\*([\d.]+) µSv/h\*\* \|", + {"README.md": ["**{v} µSv/h** at one metre"], "transistor/SEALED.md": ["{v} µSv/h at a metre"], "transistor/EMBODIMENT.md": ["{v} µSv/h at a metre"]}), + ("simulator/results.md", r"decays per independent sample: \*\*(\d+)\*\*", + {"README.md": ["every {v} decays", "{v} decays per independent sample"], "transistor/README.md": ["measured {v} decays"], + "transistor/SEALED.md": ["{v} decays per sample"], "ampoule/compile_results.md": ["{v} decays per sample"]}), + ("simulator/results.md", r"\| 229mTh quantum \(8.4 eV\) \| [\de.+-]+ \| [\de.+-]+ \| (\d+)x cheaper \|", + {"README.md": ["about {v} times less energy"], "simulator/README.md": ["about {v} times cheaper"]}), + ("simulator/results.md", r"\| 60Co gamma \(1.25 MeV\) \| [\de.+-]+ \| [\de.+-]+ \| (\d+)x costlier \|", + {"README.md": ["{v} times *costlier*"], "simulator/README.md": ["about {v} times costlier"]}), + ("transport/compiler_results.md", r"worst error \*\*([\d.]+%)\*\* in 1500 Adam steps", + {"README.md": ["to {v0} percent from a blank plate"], "theory/THEORY.md": ["worst weight error of {v0} percent"], + "transport/README.md": ["random target to {v0} percent"]}), + ("ampoule/compile_results.md", r"draws about \*\*([\d.]+) independent samples per second\*\*", + {"README.md": ["**{v} independent samples per second**"], "transistor/SEALED.md": ["{v} independent samples per second"]}), + ("ampoule/compile_results.md", r"integrated autocorrelation time of \*\*\d+ proposals, ([\d.]+) sweeps\*\*", + {"README.md": ["{v} sweeps"]}), + ("ampoule/compile_results.md", r"a nearest neighbour bond carries \*\*[\d.]+ photons per second\*\* with plastic cells and \*\*([\d.]+)\*\* with CsI", + {"README.md": ["{v} photons per second"], "transistor/SEALED.md": ["{v} photons per second"], "theory/THEORY.md": ["{v} photons per second"]}), +] + + +@pytest.mark.parametrize("source,pattern,quotes", CHECKS, ids=[c[1][:40] for c in CHECKS]) +def test_documents_quote_the_computed_number(source, pattern, quotes): + m = re.search(pattern, read(source), re.S) + assert m, f"{source}: nothing matches {pattern!r}" + v = m.group(1) + v0 = v.rstrip("%").split(" ")[0] + if "." in v0: + v0 = v0.rstrip("0").rstrip(".") if float(v0) != int(float(v0)) else str(int(float(v0))) + missing = [] + for doc, forms in quotes.items(): + text = read(doc) + for form in forms: + want = form.format(v=v, v0=v0) + if want not in text: + missing.append((doc, want)) + assert not missing, f"{source} computes {v!r} but these quotations are missing: {missing}" + + +def test_the_candidate_table_agrees_with_the_documents_on_beta(): + for key, want in (("93mMo", "2.87"), ("178m2Hf", "12.39")): + assert candidate(key, "beta_gamma") == want, key + text = read("README.md") + read("gates/README.md") + read("theory/THEORY.md") + assert "β = 2.87" in text and "β = 12.39" in text + + +def test_the_180mta_correction_holds_everywhere(): + """The first edition's erratum: the curated table said 77.1 keV while the catalogue said 75.3.""" + assert candidate("180mTa", "E_keV").startswith("75.3") + for doc in ("README.md", "gates/candidates.md", "gates/experiment_menu.md"): + assert "77.1" not in read(doc), doc + assert "75.3 keV" in read("README.md") diff --git a/tests/test_physics.py b/tests/test_physics.py new file mode 100644 index 0000000..bfcbbfd --- /dev/null +++ b/tests/test_physics.py @@ -0,0 +1,113 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +"""The instruments, checked against things that are not themselves: the beta +spectra against their tabulated means, the transfer matrix against brute +force enumeration, the sampler against its exact law, the degree checker +against the theorem, the adjoint Jacobian against finite differences, and +the committed fission matrix against the committed eigenvalue.""" +import json +import os + +import numpy as np +import pytest + +from conftest import ROOT, load_script + + +def test_beta_spectra_reproduce_the_icrp_107_mean_energies(): + beta = load_script("ampoule/beta.py") + for name, b in beta.BRANCHES.items(): + m = beta.mean_energy(name) + assert abs(m / b["mean_ref"] - 1) < 0.03, f"{name}: {m:.1f} keV against {b['mean_ref']} keV" # the script's own stated accuracy, about a percent, and far inside what the yield needs + + +def test_transfer_matrix_marginals_match_brute_force_on_two_rings(): + c = load_script("ampoule/compile.py") + c.N_Z, c.N = 2, 16 # the exact law reads the lattice size from the module + rng = np.random.default_rng(7) + W = np.zeros((16, 16)) + for j in range(16): + for k in range(j + 1, 16): + if c.coupling_class(j, k) in ("ring", "axis"): + W[j, k] = W[k, j] = rng.normal(0, 1.4) + b = rng.normal(0, 0.5, 16) + logZ, marg, mean_E = c.exact_law(W, b) + states = ((np.arange(2 ** 16)[:, None] >> np.arange(16)) & 1).astype(float) + E = 0.5 * np.einsum("si,ij,sj->s", states, W, states) + states @ b + p = np.exp(E - E.max()) + Z = p.sum() + p /= Z + assert abs(logZ - (np.log(Z) + E.max())) < 1e-9 + assert np.abs(states.T @ p - marg).max() < 1e-9 + assert abs(mean_E - (E * p).sum()) < 1e-5 + + +def test_the_sampler_converges_to_its_exact_boltzmann_law(): + twin = load_script("simulator/nuclear_ising.py") + rng = np.random.default_rng(3) + N = 5 + A = rng.normal(0, 1.2, (N, N)) + W = np.triu(A, 1) + W = W + W.T + b = rng.normal(0, 0.4, N) + emp, p_exact, ckpts, kls, tvs, _ = twin.run_chain(W, b, 300_000) + assert kls[-1] < 2e-3, f"KL divergence {kls[-1]:.2e} after {ckpts[-1]:,} decays" + + +def test_the_degree_checker_flags_and_repairs_an_inhomogeneous_comparison(): + dc = load_script("transport/degree_check.py") + left = dc.AND(dc.THIN(0.8), dc.THIN(0.9)) + right = dc.THIN(0.5) + dA, dB, flags = dc.check_comparator(left, right) + assert (dA, dB) == (2, 1) and flags + fixed = dc.homogenize(right, dA) + dA2, dB2, flags2 = dc.check_comparator(left, fixed) + assert dA2 == dB2 == 2 and not flags2 + # the theorem: a like degree comparison is invariant under global scaling of the activity + for lam in (1e5, 5e4, 2.5e4): + assert (dc.rate(left, lam) > dc.rate(fixed, lam)) == (dc.rate(left, 1e5) > dc.rate(fixed, 1e5)) + + +def test_the_adjoint_jacobian_matches_finite_differences(): + cd = load_script("transport/compiler_demo.py") + rng = np.random.default_rng(11) + s0 = rng.uniform(0.96, 0.999, cd.V) + G0, phi0, psi0 = cd.transport(s0) + adj = cd.jacobian_entry(phi0, psi0, 1, 2) + h = 1e-4 + for v in rng.choice(cd.V, 4, replace=False): + sp = s0.copy(); sp[v] += h + sm = s0.copy(); sm[v] -= h + fd = (cd.transport(sp)[0][1, 2] - cd.transport(sm)[0][1, 2]) / (2 * h) + assert abs(adj[v] - fd) < 1e-7 * max(abs(fd), 1e-3) + + +def test_the_committed_fission_matrix_reproduces_the_committed_eigenvalue(): + """Avery's coupling: the dominant eigenvalue of K must land within a few + hundred pcm of the transport k of the pair, in every absorber state.""" + doc = json.load(open(os.path.join(ROOT, "neutron/tallies.json"))) + runs = doc["runs"] + for state, coupled in (("open", "coupled_open"), ("cd", "coupled_cd"), ("b4c", "coupled_b4c")): + K = np.zeros((2, 2)) + for j, tag in enumerate("AB"): + r = runs[f"coupling_{tag}_{state}"] + for i, out in enumerate("AB"): + K[i, j] = r["regions"][out]["nu-fission"][0] + lam = np.linalg.eigvals(K).real.max() + k = runs[coupled]["k"][0] if isinstance(runs[coupled]["k"], list) else runs[coupled]["k"] + assert abs(lam - k) < 0.004, f"{state}: eigenvalue {lam:.4f} against k {k:.4f}" + assert lam < 1 and k < 1, "everything is subcritical" + + +def test_the_ampoule_synapse_is_symmetric_and_below_the_solid_angle_ceiling(): + doc = json.load(open(os.path.join(ROOT, "ampoule/tallies.json"))) + G = np.array(doc["runs"]["synapse_open"]["G"]) + c = load_script("ampoule/compile.py") + lay = doc["provenance"]["site_layout"] + d_ring = 2 * lay["radius_cm"] * np.sin(np.pi / 8) + omega_ring = 0.04 / (4 * np.pi * d_ring ** 2) + ring = G[c.CLASS == "ring"] + assert 0 < ring.mean() < omega_ring, "a coupling cannot exceed the solid angle of the receiving face" + big = 0.5 * (G + G.T) > 1e-5 + asym = np.abs(G - G.T)[big] / (0.5 * (G + G.T))[big] + assert np.median(asym) < 0.5 diff --git a/tests/test_repository.py b/tests/test_repository.py new file mode 100644 index 0000000..bf805a3 --- /dev/null +++ b/tests/test_repository.py @@ -0,0 +1,99 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +"""The repository's own promises, as tests: the reproduce script and the CI +run the same steps, every generating script is run by one of them, the +environment is pinned, the committed inputs are the ones the manifest +names, and the figures and compressed tables are written in the form that +reproduces byte for byte on every platform.""" +import gzip +import hashlib +import os +import re + +from conftest import ROOT, load_script, read, tracked + +# scripts that need OpenMC, the nuclear data library, or the network, and so run in openmc.yml or by hand +NEEDS_OPENMC_OR_NETWORK = {"neutron/gate.py", "neutron/benchmarks.py", "neutron/data.py", + "ampoule/model.py", "ampoule/calibrate.py", "ampoule/beta.py", "photon/ensdf.py"} + + +def ci_steps(): + return re.findall(r"run:\s*python\s+(\S+\.py)", read(".github/workflows/build.yml")) + + +def test_reproduce_and_ci_run_the_same_steps_in_the_same_order(): + rep = load_script("reproduce.py") + assert [s for s, _ in rep.STEPS] == ci_steps() + + +def test_every_generating_script_is_run_by_reproduce_or_needs_openmc(): + rep = load_script("reproduce.py") + run = {s for s, _ in rep.STEPS} + scripts = {p for p in tracked(".py") if not p.startswith("tests/") and p != "reproduce.py"} + unrun = sorted(scripts - run - NEEDS_OPENMC_OR_NETWORK) + assert not unrun, f"scripts nobody runs: {unrun}" + assert not (NEEDS_OPENMC_OR_NETWORK - scripts), "the OpenMC set names a script that does not exist" + + +def test_the_openmc_workflow_runs_the_openmc_scripts(): + text = read(".github/workflows/openmc.yml") + for s in ("neutron/data.py", "neutron/benchmarks.py", "neutron/gate.py", "ampoule/calibrate.py", "ampoule/model.py"): + assert s in text, s + + +def test_requirements_are_pinned(): + for line in read("requirements.txt").splitlines(): + if line.strip() and not line.startswith("#"): + assert re.match(r"^[A-Za-z0-9_.-]+==\d", line), f"unpinned requirement: {line}" + + +def test_the_ci_installs_the_pinned_requirements_and_checks_the_tree(): + text = read(".github/workflows/build.yml") + assert "pip install -r requirements.txt" in text + assert "git status --porcelain" in text, "the CI does not verify that the tree reproduced" + assert "pytest" in text + + +def test_svg_figures_are_vector_only_and_undated(): + bad = [] + for p in tracked(".svg"): + text = read(p) + if "image/png" in text or "" in text: + bad.append(p) + assert not bad, f"figures with an embedded raster or a date, which differ between platforms: {bad}" + + +def test_compressed_tables_carry_no_timestamp(): + for p in tracked(".gz"): + with open(os.path.join(ROOT, p), "rb") as f: + header = f.read(10) + assert header[:2] == b"\x1f\x8b", p + assert header[4:8] == b"\x00\x00\x00\x00", f"{p} carries a gzip mtime and will differ run to run" + with gzip.open(os.path.join(ROOT, p), "rb") as f: + f.read(64) + + +def test_committed_inputs_match_the_manifest(): + entries = [l.split() for l in read("data-manifest.sha256").splitlines() if l.strip()] + assert entries, "the manifest is empty" + wrong = [] + for digest, path in entries: + h = hashlib.sha256(open(os.path.join(ROOT, path), "rb").read()).hexdigest() + if h != digest: + wrong.append(path) + assert not wrong, f"inputs that differ from the manifest: {wrong}" + + +def test_the_manifest_names_every_committed_input(): + named = {l.split()[1] for l in read("data-manifest.sha256").splitlines() if l.strip()} + expected = {p for p in tracked() if p.startswith("gates/data/")} | { + "photon/levels.json.gz", "neutron/tallies.json", "neutron/benchmarks.json", + "ampoule/tallies.json", "ampoule/calibration.json"} + assert named == expected, f"missing: {sorted(expected - named)}, extra: {sorted(named - expected)}" + + +def test_the_dockerfile_matches_the_ci_openmc_version(): + dockerfile = read("Dockerfile") + ci = read(".github/workflows/openmc.yml") + m = re.search(r"openmc=([\d.]+)=\*nompi\*", ci) + assert m and f"openmc={m.group(1)}=*nompi*" in dockerfile diff --git a/tests/test_style.py b/tests/test_style.py new file mode 100644 index 0000000..26e5343 --- /dev/null +++ b/tests/test_style.py @@ -0,0 +1,55 @@ +# Copyright 2026 Max Freedom Pollard +# SPDX-License-Identifier: Apache-2.0 +"""The house rules of the prose, as tests: no dashes in prose, isotopes as +superscripts, and no edition or version notes inside the documents, which +must read as finished products.""" +import re + +from conftest import read, tracked + +DOCUMENTS = [p for p in tracked(".md") if not p.startswith(".github/")] +ISOTOPE_HYPHEN = re.compile(r"\b(Cf|Cs|Mo|Th|U|Am|Hf|Ta|Sr|Fe|Co|Ba|Ni|Pu|Kr|Ho|Lu|Ag|Tc|Na|Mn|Zn|Rb|Sn|Xe|Ir|Pt|Os|Au|Re|W|Y)-\d{2,3}m?\d?\b") + + +def prose_lines(text): + """The lines of a markdown file that are prose: outside fenced code, not + a table rule, and with inline code and URLs removed.""" + out, fenced = [], False + for line in text.splitlines(): + if line.strip().startswith("```"): + fenced = not fenced + continue + if fenced or re.match(r"^\s*\|?\s*-{3,}", line): + continue + line = re.sub(r"`[^`]*`", "", line) + line = re.sub(r"https?://\S+", "", line) + out.append(line) + return out + + +def test_no_em_or_en_dashes_anywhere_in_the_prose(): + offenders = [(p, i + 1) for p in DOCUMENTS + for i, line in enumerate(read(p).splitlines()) if "—" in line or "–" in line] + assert not offenders, f"em or en dashes in prose: {offenders[:10]}" + + +def test_isotopes_are_written_as_superscripts_not_hyphenated(): + offenders = [(p, m.group(0)) for p in DOCUMENTS + for line in prose_lines(read(p)) for m in ISOTOPE_HYPHEN.finditer(line)] + assert not offenders, f"hyphenated isotope designations: {offenders[:10]}" + + +def test_documents_carry_no_version_or_edition_notes(): + pattern = re.compile(r"\bv\d+\.\d+(\.\d+)?\b|\b(this|second|new) edition\b|\bchangelog\b", re.I) + documents = [p for p in DOCUMENTS if p not in ("CHANGELOG.md",)] + offenders = [(p, m.group(0)) for p in documents for m in pattern.finditer(read(p))] + assert not offenders, f"version or edition notes inside a document: {offenders[:10]}" + + +def test_every_script_carries_the_copyright_and_licence_header(): + missing = [] + for p in tracked(".py"): + head = read(p).split("\n", 4)[:4] + if not any("Copyright 2026 Max Freedom Pollard" in l for l in head) or not any("SPDX-License-Identifier: Apache-2.0" in l for l in head): + missing.append(p) + assert not missing, f"scripts without the header: {missing}" diff --git a/theory/THEORY.md b/theory/THEORY.md index b0d2fc8..7a61b90 100644 --- a/theory/THEORY.md +++ b/theory/THEORY.md @@ -86,7 +86,7 @@ and the sustained rate of a pipelined gate is bounded by both the trigger and th > `f_gate ≤ min(R_trig, σ_p φ_p).` -Ops per decay, the document's figure of merit, must be quoted against C_eval, not against C_in alone. For the stochastic tier the correction is benign (the sampler's proposals do not empty registers); for the amplifier tier it typically doubles the cost. +Ops per decay, the document's figure of merit, must be quoted against C_eval, not against C_in alone. For the stochastic tier the correction is benign (the sampler's proposals do not empty registers); for the amplifier tier it typically doubles the cost. A third term belongs on the same line for any rate coded recurrence: 2²ᵇ synapse photons per site update, the count that makes the weighted sum a number (Section 11.5). In the vessel of [/ampoule](../ampoule/) it exceeds the other two by orders of magnitude, and it is the term the machine note left out. ### 3.2 The pile up ceiling @@ -113,7 +113,7 @@ Every keystone inequality is satisfied simultaneously, by library data, with mar **What this does and does not claim.** It does not claim a practical computer: a neutron gate is centimeters to meters of moderated or fast assembly, wrapped in licensing, shielding, and fissile material control that place it outside individual reach, and its energy per operation is grotesque by Section 5 of the README. It claims something more important for the theory: existence. The model of computation defined by the two governing equations is physically complete at one scale, with 1940s physics; nature has run self restoring triggered release networks (natural reactors at Oklo, two billion years ago) without human help. The keystone program is therefore a *miniaturization* program, from meter scale neutron gates toward crystal scale photon gates, and not a search for whether the model can exist at all. A theory whose central risk is "can this be shrunk" is in a categorically stronger position than one whose central risk is "can this exist." -**Computed.** Phase B2 has now been carried out ([/neutron](../neutron/), numbers in [`neutron/results.md`](../neutron/results.md)). Two 72 litre tanks of 4.9 percent enriched uranyl fluoride solution (the LEU-SOL-THERM-002 benchmark composition), each at k ≈ 0.901 alone, coupled through 3 cm of water to k = 0.9132, in OpenMC with the official ENDF/B-VIII.0 library, the same code and data first shown to reproduce three handbook criticals. The fission matrix of the pair, measured one generation at a time from the converged fission bank, has dominant eigenvalue 0.9140 against a transport k of 0.9133, and a control that runs one generation on the whole source returns 0.9140: the identification of coupled region kinetics with a Green's function carrying gain on the diagonal is confirmed to between -263 and +138 pcm across the three absorber states, the residual being the measured cost of describing each tank by a single number rather than a shape. Obtaining that source is itself a result. A gate is built to couple its regions weakly, weak coupling drives the dominance ratio toward one (0.957 to 0.983 here), the tilt between the regions then mixes more slowly than any affordable run, and the Shannon entropy that is normally trusted to detect this is nearly blind to it, because entropy watches the shape inside each region. The eigenvalues survive the tilt, since a mode that integrates to zero cannot shift a total production rate, but the fission matrix does not, and the first version of this calculation produced a plausible and wrong one. The remedy is to remove the mode rather than average it away, by running the mirror symmetric half geometry with a reflective plane. Any network of many weakly coupled cells, in this sector or the photon one, inherits the problem in a sharper form, and this is the first place the theory has had to say so. A Cf-252 driver neutron in one tank becomes 1.49 fission neutrons in the other with the coupling open, so the gate has gain across the synapse and not merely within a region. Two drivers superpose to 0.6 percent, which is the linearity of Section 5.3 measured in a real geometry. The emission spectrum of the driven tank is the same to a total variation distance of 0.002 whether its input arrived moderated from the neighbour, as a 2 MeV fission spectrum, or as a 14.1 MeV line: level restoration, measured. The generation time is 106 µs, the prompt switching time Λ/(1 - k) is 1.22 ms, and M/τ = 1/Λ = 9.4 kHz. +**Computed.** Phase B2 has now been carried out ([/neutron](../neutron/), numbers in [`neutron/results.md`](../neutron/results.md)). Two 72 litre tanks of 4.9 percent enriched uranyl fluoride solution (the LEU-SOL-THERM-002 benchmark composition), each at k ≈ 0.901 alone, coupled through 3 cm of water to k = 0.9132, in OpenMC with the official ENDF/B-VIII.0 library, the same code and data first shown to reproduce three handbook criticals. The fission matrix of the pair, measured one generation at a time from the converged fission bank, has dominant eigenvalue 0.9140 against a transport k of 0.9133, and a control that runs one generation on the whole source returns 0.9140: the identification of coupled region kinetics with a Green's function carrying gain on the diagonal is confirmed to between -263 and +138 pcm across the three absorber states, the residual being the measured cost of describing each tank by a single number rather than a shape. Obtaining that source is itself a result. A gate is built to couple its regions weakly, weak coupling drives the dominance ratio toward one (0.957 to 0.983 here), the tilt between the regions then mixes more slowly than any affordable run, and the Shannon entropy that is normally trusted to detect this is nearly blind to it, because entropy watches the shape inside each region. The eigenvalues survive the tilt, since a mode that integrates to zero cannot shift a total production rate, but the fission matrix does not, and the first version of this calculation produced a plausible and wrong one. The remedy is to remove the mode rather than average it away, by running the mirror symmetric half geometry with a reflective plane. Any network of many weakly coupled cells, in this sector or the photon one, inherits the problem in a sharper form, and this is the first place the theory has had to say so. A ²⁵²Cf driver neutron in one tank becomes 1.49 fission neutrons in the other with the coupling open, so the gate has gain across the synapse and not merely within a region. Two drivers superpose to 0.6 percent, which is the linearity of Section 5.3 measured in a real geometry. The emission spectrum of the driven tank is the same to a total variation distance of 0.002 whether its input arrived moderated from the neighbour, as a 2 MeV fission spectrum, or as a 14.1 MeV line: level restoration, measured. The generation time is 106 µs, the prompt switching time Λ/(1 - k) is 1.22 ms, and M/τ = 1/Λ = 9.4 kHz. **Two corrections this section keeps.** First, "local absorbers program thresholds and vetoes" claims too much. A 1 mm cadmium sheet between the tanks cuts the coupling by 1.7× and a 2 cm boron carbide blade by 2.6×, because what crosses 3 cm of water is still largely fast and a thin absorber is a filter rather than a barrier. An absorber therefore programs a *weight*; the medium stays linear, its AND is a perceptron AND, and the threshold remains a comparison of rates at the boundary. Second, "adding a veto absorber yields NAND" holds only if something other than a neutron signal moves the absorber. Every coupling in this sector is excitatory, an absorber that burns up disinhibits, and the one channel by which a neutron signal lowers a neighbour's gain is heat: -25 pcm/K for this pair, a 14 percent modulation of the gain over 56 K, with roughly 343 K needed to halve it. Signal controlled inversion is thus the neutron sector's weak point as an embodiment, and the keystone search of Section 2 inherits it: the compact state must supply an inhibition as well as a gain, or the machine built from it is a linear amplifier network read by comparators, which is universal for continuous functions (Section 6) and not for logic. @@ -311,7 +311,7 @@ Freeze the cross sections (Section 5.3): transport is the linear operator 𝒢(s > `(∂ 𝒢_io)/(∂ s_v) = φ_i(v) ψ_o(v)` -the forward visit density φ_i = B_i (I-Q)⁻¹ (how often a photon entering port i visits cell v) times the importance ψ_o(v) (the probability that a photon leaving v eventually exits at port o), which is the *adjoint* flux ψ = M(I-Q)⁻¹C + C. One forward solve gives all φ_i; one adjoint solve gives all ψ_o; their outer product is the entire Jacobian of the whole weight matrix with respect to the whole layout. This is not a new trick: it is the importance function reactor physicists have computed since the 1950s (Ussachoff 1955), it is what shielding optimizers already use, and it is, exactly, backpropagation. The demo verifies the boxed formula against finite differences to a worst relative error of 9×10⁻⁷, machine precision. +the forward visit density φ_i = B_i (I-Q)⁻¹ (how often a photon entering port i visits cell v) times the importance ψ_o(v) (the probability that a photon leaving v eventually exits at port o), which is the *adjoint* flux ψ = M(I-Q)⁻¹C + C. One forward solve gives all φ_i; one adjoint solve gives all ψ_o; their outer product is the entire Jacobian of the whole weight matrix with respect to the whole layout. This is not a new trick: it is the importance function reactor physicists have computed since the 1950s (Ussachoff 1955), it is what shielding optimizers already use, and it is, exactly, backpropagation. The demo verifies the boxed formula against finite differences to a worst relative error below 10⁻⁷, machine precision. ### 11.2 Way A, full custom: grind the problem into the geometry @@ -331,6 +331,10 @@ Neither route above needs the *inside* of a sealed unit once built, because the **The three are one workflow.** Way A designs the plate; Way B is the reprogrammable alternative when flux is cheap and edits are frequent; Way C trims whatever was built and keeps it trimmed. Together they are the missing assembler, and with them the phrase "the problem is ground into the geometry" stops being a slogan and becomes a function you can call. +### 11.5 The compiler on the measured vessel + +The three ways above were demonstrated on a toy fabric. Run on the measured Green's function of the ampoule ([/ampoule](../ampoule/), numbers in [`ampoule/compile_results.md`](../ampoule/compile_results.md)), they return two results the toy could not. First, Way B on a diffusive shell is exact on the bonds it is asked for and helpless against the couplings it is not: the 60 diagonal and far couplings of each site pass no aperture and sum to 7.9× the instance in weight units, so the compiled law saturates, and the one pass that remains, subtracting the predictable mean of the crosstalk from the biases through the collar, leaves a fluctuation 3.1× the intended drive. The silence demand of 11.2 is therefore not a corner case of the toy but the normal condition of a scattering shell, and collimation, the sight lines of the build note's channel plates, is a requirement of the compiler and not a refinement. Second, compilation has a timing closure. A weight in a rate coded machine is a photon current, I_kj = G_kj r_j, and the precision law (5.6) prices its read at 2²ᵇ counts: with CsI cells a nearest neighbour bond carries 16.3 photons per second, a site's fan in 291, and a 4 bit loop takes 0.88 s, so the vessel samples at 0.34 independent samples per second where the machine note, pricing proposals alone, said 38,462. The proposal budget and the synapse budget are different budgets; the twin's 26 decays per sample counted only the first, and the reset ledger of Section 3.1 now carries the second. + --- *Sections 1 through 3 are the referee armor: every known way a working gate quietly dies, written down with its inequality. Section 4 is the existence proof that the model survives them all at one scale. Sections 6 through 10 are the machine that needs no keystone, no calibration, and no wires. Section 11 is the compiler that turns a problem into a piece of matter. What remains is the search itself.* diff --git a/transistor/EMBODIMENT.md b/transistor/EMBODIMENT.md index 947ffe0..40d2fb6 100644 --- a/transistor/EMBODIMENT.md +++ b/transistor/EMBODIMENT.md @@ -77,4 +77,6 @@ A sealed cylindrical vessel, outer envelope 90 mm diameter × 170 mm, about 4 kg The vessel above has been run in OpenMC with its own beta spectra ([/ampoule](../ampoule/)); four lines of this note are corrected by it. The scintillating cells of Section 1.2 are CsI, not plastic: a 2 mm plastic cell in the 252 keV field the core delivers interacts 515 /s, and the 64 together reach 0.033× the proposal budget of SEALED.md Section 8, while CsI cells interact 31× as often, 1.02 M/s in all, which meets it. The tungsten aperture inserts of the same section are analog trims and not shutters: the collar's ON/OFF contrast is 6.34 with plastic cells and 11.94 with CsI, because 2 mm of tungsten passes the hard half of the bremsstrahlung. The lead septa are attenuators and not blocks: a 1 mm sheet leaves the coupling it sits across at 0.49 of its open value. And the health physics calculation Section 1.5 left to the builder now has a first figure: 67.8 µSv/h at the titanium wall and 0.261 µSv/h at a metre, from 3.4 M/s escaping at a mean 565 keV, which places this vessel where Section 0 already put it, in an institution with a lead pot. The counting ring of Section 1.4 sees 3.25 M/s, 0.33× the 10⁷ per second the performance line at the top of this note was priced on, so the 8 bit reads are 50 per second and not 153 until the ring collects more than its present 7% of the core's light. +The compilation of the same vessel ([`ampoule/compile_results.md`](../ampoule/compile_results.md)) corrects two more lines. The performance line of Section 0, 38,000 samples per second, was priced on proposals; the synapse currents of the compute shell as built support 0.34 per second at 4 bit weights with CsI cells, and the figure is approached only by packing the cells face to face and raising the core to a terabecquerel, which moves the unit to the industrial licence tier. And the coincidence pairs defined by shared sight lines through the plates (Section 1.2) are not a detail of the layout but the synapse itself: the scattering couplings the transport measured bury a nearest neighbour instance under the far couplings, so the plates' sight lines must carry the intended bonds and the glass must carry as little as possible of the rest. + *Nothing in this note is exotic to a nuclear instrumentation shop: ISO sealed sources, Mössbauer foils and drives from catalog, channel plates from any microfluidics fab, SiPMs and CZT from the PET industry. The novelty is entirely in what the assembly is for. That is the point.* diff --git a/transistor/README.md b/transistor/README.md index bc0bae5..5ef737f 100644 --- a/transistor/README.md +++ b/transistor/README.md @@ -53,7 +53,7 @@ This is the p bit of the stochastic tier, and nothing in it awaits a discovery. 2. form the drive u_k = (n_k - n_0)/s, with offset and scale set once at calibration (they encode the site's bias and the weight normalization); 3. set the site's aperture to duty σ(u_k) for the next window: the shutter dwells open that fraction of the cycle, a pulse width modulated Gibbs acceptance. -The timing closes on itself: at a thinned input rate of 10⁴ per second and 4 bit drive resolution, the precision law sets T_loop = 2²ᵇ/r ≈ 26 ms, which is a 40 Hz loop, which is exactly a hobby servo's natural cadence. Quantized acceptance biases the sampled law by an amount bounded by the quantization step (the variance calculus of theory Section 10.1 prices it); 4 bits is ample for annealing. Two implementations, honestly ranked: Mode A (the working mode): a boundary counter and lookup table drive the servos at up to kHz, electronics touching only counts and servo commands, never quanta in flight. Mode B (the demonstration mode): the duty table is printed and a clockwork cam or a patient human executes it at tenths of hertz, proving the loop contains no essential silicon, at a pace that makes the point and nothing else. Electronics free recurrence at speed is precisely what the valve fabric ([VALVE.md](VALVE.md)) and the keystone are for. +The timing closes on itself: at a thinned input rate of 10⁴ per second and 4 bit drive resolution, the precision law sets T_loop = 2²ᵇ/r ≈ 26 ms, which is a 40 Hz loop, which is exactly a hobby servo's natural cadence. In the sealed vessel the same loop is fed by scattered light rather than a beam and runs at 0.88 s per update with CsI cells ([`ampoule/compile_results.md`](../ampoule/compile_results.md)): the cadence is the synapse current's, not the servo's. Quantized acceptance biases the sampled law by an amount bounded by the quantization step (the variance calculus of theory Section 10.1 prices it); 4 bits is ample for annealing. Two implementations, honestly ranked: Mode A (the working mode): a boundary counter and lookup table drive the servos at up to kHz, electronics touching only counts and servo commands, never quanta in flight. Mode B (the demonstration mode): the duty table is printed and a clockwork cam or a patient human executes it at tenths of hertz, proving the loop contains no essential silicon, at a pace that makes the point and nothing else. Electronics free recurrence at speed is precisely what the valve fabric ([VALVE.md](VALVE.md)) and the keystone are for. ## Between the scales: the valve, or why "field effect" is not a metaphor @@ -87,7 +87,7 @@ a constant gain bandwidth product, exactly the signature behavior of an operatio **Why it is in this document.** Not as a proposal; nobody wants this computer. It is here because a skeptical reader's strongest objection to the crystal cell ("no such device has ever existed") is answered by pointing at this one: the same pinout, with the gain socket filled, has operated on Earth since 1942, and operated *unattended* at Oklo two billion years before that. The crystal cell is that device shrunk by seven orders of magnitude, minus, so far, its gain. -**Computed, not cited.** The device above is now built in [/neutron](../neutron/): two solution tanks in OpenMC with ENDF/B-VIII.0, an absorber between them as the GATE, a Cf-252 point source as the SOURCE, the fission rate in the far tank as the DRAIN. Its measured pinout is M = 11.5 for the pair, a drain of 1.49 fission neutrons in the far tank per driver neutron with the gate open against 0.67 with a boron carbide blade in, a generation time of 106 µs, and a gain bandwidth product 1/Λ of 9.4 kHz, which is the theorem above checked against a real light water assembly rather than a textbook figure. The same calculation returns the bad news the table above cannot show: the gate's ON/OFF contrast is 2.2, because an absorber in a moderated gap programs a weight and not a threshold, and the sector has no signal controlled inversion. The GATE terminal is real, and it is an analog knob. +**Computed, not cited.** The device above is now built in [/neutron](../neutron/): two solution tanks in OpenMC with ENDF/B-VIII.0, an absorber between them as the GATE, a ²⁵²Cf point source as the SOURCE, the fission rate in the far tank as the DRAIN. Its measured pinout is M = 11.5 for the pair, a drain of 1.49 fission neutrons in the far tank per driver neutron with the gate open against 0.67 with a boron carbide blade in, a generation time of 106 µs, and a gain bandwidth product 1/Λ of 9.4 kHz, which is the theorem above checked against a real light water assembly rather than a textbook figure. The same calculation returns the bad news the table above cannot show: the gate's ON/OFF contrast is 2.2, because an absorber in a moderated gap programs a weight and not a threshold, and the sector has no signal controlled inversion. The GATE terminal is real, and it is an analog knob. --- diff --git a/transistor/SCALING.md b/transistor/SCALING.md index 439f7a5..4f5d355 100644 --- a/transistor/SCALING.md +++ b/transistor/SCALING.md @@ -8,12 +8,13 @@ This document is that ledger for the nuclear machine: every component as it exis ## The comparison that sets the tone -The 1 GBq ampoule of [SEALED.md](SEALED.md) draws about 38,000 independent samples per second from 181 µW of deposited decay power: roughly 5 nanojoules per sample against ENIAC's 30 joules per operation, ahead by nine to ten orders of magnitude on the day it is sealed, unpowered, with no moving electrons it did not inherit from nuclei. The machine does not begin where ENIAC began. It begins past it, and the ledger below says where it goes. +The 1 GBq ampoule of [SEALED.md](SEALED.md) draws, as priced on its proposal budget, about 38,000 independent samples per second from 181 µW of deposited decay power: roughly 5 nanojoules per sample against ENIAC's 30 joules per operation, nine to ten orders ahead. As built, with its synapse currents measured in transport and compiled ([`ampoule/compile_results.md`](../ampoule/compile_results.md)), it draws 0.34 per second, half a millijoule per sample, still nearly five orders past ENIAC on the day it is sealed, unpowered, with no moving electrons it did not inherit from nuclei. The machine does not begin where ENIAC began. It begins past it, and the ledger below says where it goes, its newest row first. ## The ledger | component | 1945 analog | in this repository today | the lever | the ceiling | headroom | |---|---|---|---|---|---| +| synapse current | plugboard wiring by hand | 16 photons per second per nearest neighbour bond (CsI cells, the vessel as built) | cells packed face to face (×148 in solid angle); activity (×10³ to the terabecquerel tier); collimated sight lines carrying the instance's bonds instead of the glass | the solid angle ceiling: one interaction per photon that enters | ×10⁵, to the priced unit | | source activity | more tubes, bigger rooms | 3.7×10⁴ decays/s (exempt benchtop); 10⁹ (ampoule) | licensing tiers: GBq institutional, TBq industrial irradiator class | pile up: activity must be spread over n ≳ λτ_d sites (THEORY.md 3.2); self absorption | ×10³ to 10⁹ | | coincidence window | tube switching speed | 100 ns (plastic scintillator, conservative) | LaBr₃ at ~1 ns; time of flight PET silicon photomultipliers at ~200 ps; Cherenkov timing near 30 ps in research devices | nuclear level lifetimes (fs) are far below any electronics | ×10³ | | collection | hand wiring | ~1 percent solid angle (benchtop) | 4π enclosure geometries; photodetector efficiency ~50 percent; total body PET raised system sensitivity ~40× in one product generation | unity | ×10² | diff --git a/transistor/SEALED.md b/transistor/SEALED.md index 845a7ec..b83e3e8 100644 --- a/transistor/SEALED.md +++ b/transistor/SEALED.md @@ -82,4 +82,6 @@ A sealed cylinder, roughly a liter, one GBq of ⁹⁰Sr/⁹⁰Y at the core (181 **Transported.** The vessel of this note has now been run in real photon transport ([/ampoule](../ampoule/), numbers in [`ampoule/results.md`](../ampoule/results.md)), and three of its numbers move. Its core sends 43.9 M/s of bremsstrahlung into the lamp cell at a mean energy of 252 keV, 0.0569 photons per decay, and deposits 183 µW against the ledger of Section 5, which holds. The boundary counts 3.25 M/s, 0.33× the 10⁷ per second assumed in Section 7, from 7% of those photons: the mouth is a factor 3.0 narrower than priced, and the digital port reads 50 eight bit words per second rather than 150. The proposal budget of Section 8 is reached only if the sites are CsI, at 1.02 M/s; in plastic they see 32.9 k/s, 0.033× the budget. What the transport adds that the note could not is the character of the light: it is hard, so the tungsten apertures switch with a contrast of 6.34 (11.94 with CsI cells) and the lead septa leave the coupling they block at 0.49 of its open value, and the wall passes 7.7% of it for an ambient dose of 67.8 µSv/h at contact and 0.261 µSv/h at a metre. The ampoule computes in rates as this note says; its knobs are analog, its lead is a filter, its mouth is narrower, and the build note is amended accordingly. +**Compiled.** The compiler of theory Section 11 has been run on the transported vessel's Green's function ([/ampoule](../ampoule/), numbers in [`ampoule/compile_results.md`](../ampoule/compile_results.md)), and it moves the one number this note printed most confidently. The proposal budget of Section 8 was the wrong budget: a weight in a rate coded machine is a photon current, a nearest neighbour bond of the compute shell carries 16.3 photons per second with CsI cells, and reading a site's fan in to 4 bits takes 0.88 s, so the worked unit draws 0.34 independent samples per second as built, not 38,000, and its law is buried by the far couplings of a scattering shell unless the sight lines of the build note are what carry the synapse. The 38,000 figure is within reach on the ledger of [SCALING.md](SCALING.md), with CsI cells packed face to face and a terabecquerel core, at the ceiling of the currents; the vessel this note seals today is a sampler of a fraction of a sample per second, with an aging curve it can still print on its label. + *The ampoule closes the loop the charter opened: a lump of structured matter, bathed in its own radiation, computing. Nothing enters but fields; nothing leaves but light; nothing inside it can be recalled, recharged, or corrected, and by the aging theorem nothing needs to be.* diff --git a/transport/README.md b/transport/README.md index d7bbcd7..9a3624e 100644 --- a/transport/README.md +++ b/transport/README.md @@ -9,7 +9,7 @@ 5. The degree checker ([`degree_check.py`](degree_check.py) writes [`degree_results.md`](degree_results.md)): the design rule tool of theory Section 7.1. It labels every node's coincidence degree, flags unequal degree comparisons, repairs them with reference stages, and demonstrates the stakes by simulation: the defective comparator inverts its decision at half activity, the repaired one never moves. 6. **Bernstein feed forward universality.** A circuit of thinning, coincidence, and MUX alone evaluates a nonlinear function of its input rate, matching its Bernstein polynomial to counting noise (0.0012) while the polynomial converges to the target as 1/n exactly as the theorem in THEORY.md Section 6 requires. Function approximation does not wait on the keystone. -7. The compiler ([`compiler_demo.py`](compiler_demo.py) writes [`compiler_results.md`](compiler_results.md), figure 14): the missing assembler, three ways. The adjoint Jacobian of the whole weight matrix (forward flux times importance, the reactor perturbation formula) is verified against finite differences to 9×10⁻⁷; adjoint descent then compiles a random target to 0.65 percent, a crossbar compiles any target by exact division, and SPSA trims a sealed unit through the wall using only Poisson counts of its glow (theory Section 11). +7. The compiler ([`compiler_demo.py`](compiler_demo.py) writes [`compiler_results.md`](compiler_results.md), figure 14): the missing assembler, three ways. The adjoint Jacobian of the whole weight matrix (forward flux times importance, the reactor perturbation formula) is verified against finite differences to below 10⁻⁷; adjoint descent then compiles a random target to 0.65 percent, a crossbar compiles any target by exact division, and SPSA trims a sealed unit through the wall using only Poisson counts of its glow (theory Section 11). For engineering geometries (real cross sections, real materials, coupled neutron and photon transport, the subcritical gate of the theory document) the same measurements should be repeated in OpenMC (openmc.org: open source, ENDF/B data, Python API); these demonstrations are deliberately dependency free so that every claim can be checked anywhere first. diff --git a/transport/compiler_demo.py b/transport/compiler_demo.py index 586322e..93d95f1 100644 --- a/transport/compiler_demo.py +++ b/transport/compiler_demo.py @@ -48,6 +48,11 @@ def say(s=""): print(s) +def pow10(x): + """A power of ten as 10ⁿ.""" + return "10" + str(int(round(math.log10(x)))).translate(str.maketrans("0123456789-", "⁰¹²³⁴⁵⁶⁷⁸⁹⁻")) + + # --------------------------------------------------------------------------- # the transport fabric: movement matrix M (cell to cell) and exits X (cell # to port), fixed by geometry; survival s_v is the compiled variable @@ -123,7 +128,7 @@ def main(): s0 = RNG.uniform(0.96, 0.999, V) G0, phi0, psi0 = transport(s0) adj = jacobian_entry(phi0, psi0, 1, 2) - h = 1e-6 + h = 1e-4 # a step where truncation, not rounding, dominates the residual fd = np.zeros(5) cells = RNG.choice(V, 5, replace=False) for k, v in enumerate(cells): @@ -131,10 +136,13 @@ def main(): sm = s0.copy(); sm[v] -= h fd[k] = (transport(sp)[0][1, 2] - transport(sm)[0][1, 2]) / (2 * h) err = np.max(np.abs(adj[cells] - fd) / np.abs(fd)) + # the residual is a few parts in 10^9 and its digits depend on which BLAS inverted the + # matrix, so it is reported as the bound it satisfies, which reads the same everywhere + bound = 1e-7 if err < 1e-7 else 10.0 ** math.ceil(math.log10(err)) say("## Way A: the adjoint compiler (full custom)\n") say(f"- adjoint Jacobian (flux times importance, two solves) versus " f"finite differences at 5 random cells: worst relative error " - f"**{err:.1e}** (machine precision: the reactor perturbation " + f"**below {pow10(bound)}** (machine precision: the reactor perturbation " "formula, verified)") # ---- compile: (1) a feasible target exactly, (2) a silence demand ---- @@ -193,8 +201,11 @@ def compile_target(G_star, zero_mask, mu, steps=1500): T = np.clip(G_star / np.maximum(G_fab, 1e-9), 0, 1) G_xbar = G_fab * T err_x = np.max(np.abs(G_xbar - G_star)[G_star > 0] / G_star[G_star > 0]) + # G_fab * (G*/G_fab) is G* up to rounding, which lands on exactly zero on one architecture + # and on a few 10^-16 on another; the bound is the platform independent statement + bound_x = 1e-15 if err_x < 1e-15 else 10.0 ** math.ceil(math.log10(err_x)) say(f"- fabricate once wide open, program apertures per channel: " - f"T = G*/G_fab elementwise; error **{err_x:.1e}** by construction " + f"T = G*/G_fab elementwise; error **below {pow10(bound_x)}**, zero to rounding, by construction " "for any target under the fabric ceiling. No optimization, " "instant reprogramming, at the price of dedicated sight lines " "(flux per channel falls as the channel count grows): the FPGA " diff --git a/transport/compiler_results.md b/transport/compiler_results.md index 615811c..c97c8c5 100644 --- a/transport/compiler_results.md +++ b/transport/compiler_results.md @@ -2,12 +2,12 @@ ## Way A: the adjoint compiler (full custom) -- adjoint Jacobian (flux times importance, two solves) versus finite differences at 5 random cells: worst relative error **9.1e-07** (machine precision: the reactor perturbation formula, verified) +- adjoint Jacobian (flux times importance, two solves) versus finite differences at 5 random cells: worst relative error **below 10⁻⁷** (machine precision: the reactor perturbation formula, verified) - **fidelity**: handed a feasible random 4 x 4 target and a blank plate, the compiler recovers every significant weight to worst error **0.65%** in 1500 Adam steps (final loss 4.5e-09), without ever being told the seed layout - **the silence demand**: killing one channel of a diffusive fabric while preserving its neighbors is deliberately over constrained (the paths overlap), and the compiler finds the physical optimum of the trade: the loudest crosstalk channel G[2,3] suppressed **3x** at a worst collateral error of **61.1%** on the kept weights. Perfect isolation wants collimation (Way B), and the compiler quantifies exactly how much ## Way B: the crossbar (universal fabric) -- fabricate once wide open, program apertures per channel: T = G*/G_fab elementwise; error **0.0e+00** by construction for any target under the fabric ceiling. No optimization, instant reprogramming, at the price of dedicated sight lines (flux per channel falls as the channel count grows): the FPGA to Way A's full custom +- fabricate once wide open, program apertures per channel: T = G*/G_fab elementwise; error **below 10⁻¹⁵**, zero to rounding, by construction for any target under the fabric ceiling. No optimization, instant reprogramming, at the price of dedicated sight lines (flux per channel falls as the channel count grows): the FPGA to Way A's full custom ## Way C: self calibration through the wall (SPSA)