Complete CODATA coverage with published uncertainties - #821
Merged
Conversation
The post claimed `iau::G` and the HEP namespaces were the extent of the measured constants. There is a `codata` system now, and IAU imports G from it rather than defining its own, so the note pointed at a shape the library no longer has. Also links the tracking issue for filling out the rest of the table. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ncertainty
NIST publishes a constant's value and its standard uncertainty mutually
rounded, both to two significant digits of sigma. Storing only the relative
form could not reproduce the published sigma (off by up to 6.1% for the
fine-structure constant), and sigma is the number `uncertain<T>` carries,
prints, and propagates. A measured constant now declares exactly one of two
wrappers, whichever form its source publishes:
- `standard_uncertainty{mag * unit}` - absolute, spelled as a full unit
expression of the constant's own dimension, so the relative form derives
as an exact ratio of canonical magnitudes with the units cancelling;
- `relative_standard_uncertainty{mag}` - retained for constants whose
defining unit is not tabulated or needs an inexact conversion.
`MeasuredConstant` detects either wrapper, `get_standard_uncertainty` is
added, and both accessors derive the undeclared form on demand (using
`u_r = u(x)/|x|`, so negative-valued constants yield positive uncertainties
in both directions). The conversion engine reads `u_r` through the accessor
and needs no other change.
All 36 existing definitions (32 in `hep`, 4 in `codata`) migrate to the
absolute form, each transcribing its NIST table row verbatim, which removes
the derived-sigma error. This also surfaced that
`hep::codata2022::electron_compton_wavelength` wrongly aliased the 2018
value: CODATA 2022 publishes 2.426 310 235 38(76)e-12 m, so it is now a
definition of its own.
`scripts/systems_reference.py` renders whichever form a constant declares
in a single "Standard uncertainty" column, and the `~` format-spec rationale
is reworded: it quotes the value to the precision the uncertainty justifies
(GUM 7.2.6) rather than marking the output as an approximation.
Part of #820
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d-Brent Pollard's rho `find_first_factor` relied on unbounded odd trial division after the Baillie-PSW primality gate. BPSW certifies large primes cheaply, but for a composite whose prime factors all exceed the trial-division range it only answers "composite" and the loop then walks to the smallest factor: the CODATA 2018 atomic unit of electric potential mantissa (27'211'386'245'988 = 2^2 * 3 * 7 * 531'871 * 609'067) needs 265'665 iterations, over GCC's default `-fconstexpr-loop-limit` of 262'144, so the value could not be defined at all. The 2018 electron Compton wavelength already shipped at 89% of that ceiling. Following the approach validated in Au (aurora-opensource/au#686, blessed by Chip Hogg for porting): `mul_mod` now forms the full-width product in `unsigned __int128` where the compiler provides one (the original chunking reduction stays as the portable fallback), and factors are found by Pollard's rho with Brent's cycle detection and batched gcd checks, recursing with BPSW to return the smallest prime factor. Trial division remains as the last-resort fallback. Factorization drops from ~22 s to ~0.9 s of a CODATA-heavy TU, and the previously impossible value compiles in about a second. Free functions are used instead of local lambdas on purpose: only C++23 consteval propagation lets a plain lambda call `consteval` functions, and gcc-12 builds in C++20 mode. Part of #820 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…f a non-template base A hidden friend of a class template is redeclared by every specialization, and magnitude-heavy code instantiates thousands of specializations per translation unit (every product materializes intermediates), so the ~20 friends `unit_magnitude` carried made its instantiations dominate compile times: 30 s of a 42 s CODATA translation unit went into `InstantiateClass` over 6775 specializations. Everything taking a magnitude now lives in the new non-template `unit_magnitude_interface` base, the same shape as `unit_interface` and `quantity_spec_interface`: declared exactly once per program, found through ADL exactly as before (a base class is an associated class of the argument), invisible to ordinary lookup, and with nothing of these names left at namespace scope an ADL call on a magnitude sees exactly one candidate family. Only `empty_magnitude` and `negate_magnitude` stay outside, because a friend body cannot name a concrete specialization of the still-incomplete class template, plus the element-level utilities that take no magnitude at all. The `magnitude_base` CRTP layer is gone, and all magnitude parameters are taken by value. Measured on the three-arm benchmark (best-of-3, interleaved; full data in the mp-units-benchmarks findings): | TU | before | after | |---------------------------|---------|--------| | codata2022.h, gcc-15 | 44.8 s | 4.1 s | | codata2022.h, clang-21 | 44.0 s | 6.8 s | | si units + constants TU | 2.6 s | 1.6 s | The last row applies to every mp-units user: the win is library-wide, not CODATA-specific. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`scripts/codata_constants.py` generates the `codata` system headers from the NIST "allascii" tables (checked in byte-verbatim under `scripts/codata/` and excluded from whitespace-normalizing hooks). Every row of every adjustment is accounted for in exactly one way - transcribed with its published value and absolute standard uncertainty digit for digit, defined by a curated exact relation (values NIST prints truncated with "..." are exact non-terminating decimals), aliased (`si::si2019` constants and exact-duplicate rows), skipped as a unit variant, or skipped for a curated documented reason - and an unaccounted row fails generation. The output is then verified independently: every emitted expression is re-parsed and re-evaluated numerically in the row's own unit against the printed digits. Each adjustment ships in two tiers spelling the same types: `codata/codataYYYY_essential.h` (the NIST "Frequently used constants" selection, costing nothing measurable over the framework headers) and `codata/codataYYYY.h` (the complete table, ~230 constants). Adjustment- invariant values live outside the tiers: `codata/adopted_values.h` holds the CGPM/CIPM conventional constants that are identical in every table (the generator verifies that), and `codata/math_constants.h` defines the two Wien displacement transcendental roots that the post-2019 Wien constants are defined through. `codata.h` remains the umbrella, and `iau.h` now includes only the essential tier. `scripts/systems_reference.py` learns the new layout: per-constant-alias inline-namespace detection (fixing triplicated index entries with dead anchors), alias target resolution that prefers a nearer system's constant over a farther system's quantity, symbol cells with word-break opportunities, and uncertainty carried through constant aliases. Resolves #820 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…precated in favor of their `codata` homes Neither is an SI defining constant; both sat in `si` for convenience. The standard gravity is a conventional value adopted by CGPM 3 (1901), which is exactly what NIST's "adopted values" CODATA category holds, so its home is `codata::standard_gravity` in `<mp-units/systems/codata/adopted_values.h>`, a single adjustment-invariant entity. The reduced Planck constant's home is `codata::reduced_planck_constant`: the exact `h / 2π` relation in the post-2019 adjustments and the measured "Planck constant over 2 pi" value in `codata2014`. The deprecated `si` duplicates stay for compatibility, following the `si::magnetic_constant` precedent. `yard_pound`'s `pound_force` is now defined through the codata entity and includes only the tiny adopted-values header. All in-repo users (examples, tests, tutorials, workshops) migrate; the docs snippets gain the include, and the `weighing_the_earth` example page's snippet pins are shifted for the added include line. A constant should have exactly one home so that every alias refers to the very same entity and conversions through it stay exact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…generated reference The users guide, the how-to guide, and the blog draft now describe the two uncertainty wrappers the way the design settled: `standard_uncertainty` transcribes the published absolute value verbatim (NIST rounds the pair mutually, so no derived form reproduces it), and `relative_standard_uncertainty` remains for sources publishing only the relative form, with each accessor deriving the other on demand. The blog post shows the NIST table row before the code that transcribes it, and the codata users-guide page documents the full header layout (tiers, adopted values, Wien math constants) with current compile-time numbers. Every output quoted in the docs is regenerated from the real code: the weighing-the-earth accepted-value sigma is the published one now, and the systems reference covers all ~740 generated constants. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The MD013 fix on the neighboring line pushed words down and made this one 97 characters. Verified with a full `pre-commit run --all-files` (exit code checked, not eyeballed output) before pushing this time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… forks Seven workflows carried both a `push` trigger over all branches and a `pull_request` trigger, so every push to a branch with an open PR started two runs of each. They land in different concurrency groups - `github.ref` is `refs/heads/<branch>` for one and `refs/pull/N/merge` for the other - so neither cancels the other and they compete for runners. The two events also filter paths differently, and that is what made the duplication expensive rather than merely redundant: `push` matches the paths against the commits just pushed, while `pull_request` matches them against the whole base...head diff. Once any commit in a PR has touched `src/**`, every later push re-runs the full matrix, even a docs-only one. Skip the `pull_request` event where `push` already covers it - that is, whenever the head branch lives in this repository. Fork PRs never fire `push` here, so they keep full `pull_request` coverage on every push, and comparing `head.repo.full_name` rather than the repository name keeps that working for forks renamed away from `mp-units`. The guard sits on the first job of each workflow; the rest are chained through `needs:` and skip with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sion All three failing MSVC 14.5 CI legs die identically in `prime_factorization::first_base` with a bogus "failure was caused by a read of an uninitialized symbol: std::_Optional_destruct_base<uint64_t>::_Has_value" the moment `find_first_factor` reaches the Pollard's rho path (first hit: the codata2014 alpha particle-proton mass ratio mantissa). GCC and Clang evaluate the same code fine. `smallest_prime_factor_of_hard_composite` and `smallest_prime_in` now return a plain `std::uint64_t` with `0` (never a valid prime factor) as the every-parameterization-failed sentinel instead of `std::optional`. Verified on gcc-15 (full build, all tests) and covered by the existing `find_first_factor` static assertions, which exercise the rho path directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Generates the complete
codatasystem from the NIST tables and lands everything that fell out of making that possible. Resolves #820.What's here (7 commits, in dependency order)
standard_uncertaintystores a constant's published absolute uncertainty — NIST publishes value and σ mutually rounded, so storing only the relative form reconstructed σ wrong (6.1% off for the fine-structure constant). A measured constant now declares exactly one of the two wrappers; accessors derive the other exactly; all 36 existing definitions migrate; also fixeshep::codata2022::electron_compton_wavelengthwrongly aliasing the 2018 value.mul_mod+ batched-Brent Pollard's rho (approach from Fix compile-time factorization hitting constexpr step limit (#328) aurora-opensource/au#686, blessed by Chip Hogg) — a real CODATA mantissa (semiprime remainder531'871 × 609'067) needed 265k trial-division iterations, over GCC's default constexpr loop limit; factorization drops from ~22s to ~0.9s of a CODATA TU.unit_magnitudeinterface hosted as hidden friends of a non-template base — a hidden friend of a class template is redeclared per specialization (6775 specializations × ~20 friends dominated compile time). Measured:codata2022.hTU 44.8s → 4.1s (gcc-15), si-baseline TU 2.6s → 1.6s — a library-wide win. Three-arm benchmark data recorded in the mp-units-benchmarks findings._essential≈ free, full ≈ +2.5s/TU) plus sharedadopted_values.handmath_constants.h;iau.hincludes only the essential tier.si::standard_gravityandsi::reduced_planck_constantdeprecated — neither is an SI defining constant; their homes arecodata::standard_gravity(CGPM-adopted, adjustment-invariant) andcodata::reduced_planck_constant(exacth/2πpost-2019, measured in 2014).pound_forcenow builds on the codata entity via the tiny adopted-values header.Verification
--checkreruns are byte-stablescripts/systems_reference.py --forceleaves the tree clean; full regeneration in ~20s🤖 Generated with Claude Code