Move the moment equations into FORTRAN 77 and build with meson-python - #53
Merged
Conversation
The Cox (1979) moment equations are a quadruple loop over the input
variables evaluated for every uncertain result, and in Python they
dominated the cost of the library. They are now FORTRAN 77 subroutines in
src/soerp/_soerp.f, compiled into an extension module by f2py, which
returns the numerical core to the language the original SOERP was written
in. Python keeps the automatic differentiation, the distribution moments
and the public API.
Measured against the pure-Python implementation this replaces, on the same
machine and inputs:
rawmoment(k=4), equation (A-9) soerp_numeric(), the full call
n python fortran speedup python fortran speedup
2 59.9us 3.2us 18.8x 179.1us 12.5us 14.3x
3 203.8us 4.2us 48.8x 462.1us 13.8us 33.4x
5 1195.4us 4.4us 271.5x 2131.3us 16.9us 125.9x
10 18598.0us 13.0us 1434.9x 19636.0us 41.1us 477.3x
Cox's own three-part assembly now takes 16us end to end rather than 495us,
so a result that used to cost half a millisecond is comfortably inside one.
The whole test suite runs in half the time it did.
The kernel is verified, not assumed: it reproduces the exact expansion of
E[y**k] for n = 1..5 across every combination of linear, pure-quadratic and
cross-product terms, under both standardized and general input moments, and
still reproduces Table 2 of the paper.
Build system, following the f2py-tpl template:
- meson-python replaces hatchling, with meson.build at the root, one per
package level, and the version derived from git by bin/get_version.py.
- bin/build.py wraps install / wheel / clean.
- Windows links the gfortran runtime statically so a wheel imports without
MinGW present. Each flag is probed rather than assumed, since
-static-libquadmath only exists from GCC 9 onwards and an unsupported
flag is a hard link error.
- VCCP is zeroed before use: it is intent(out) but only the i < j triangle
is written, so the rest would otherwise be uninitialised memory.
- VARCMP takes its scratch arrays from the caller via intent(cache,hide)
rather than using automatic arrays, which keeps the source inside
FORTRAN 77 and leaves the number of input variables unbounded.
The package moves under src/. Without that, a local soerp/ directory
shadows the installed package, so `pip install .` followed by `pytest` from
the repository root imports the source tree, which has no compiled
extension, and every test errors on `cannot import name '_soerp'`.
CI has to change shape because the wheel is no longer pure Python. A single
artifact can no longer be installed across the test matrix, so the test job
builds from source on each runner and installs gfortran where the image
lacks it; wheel building moves to cibuildwheel across Linux, Windows and
macOS, with the results collected into the artifact the publish workflow
already expects.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: codex <267193182+codex@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: gemini-code-assist <gemini-code-assist@users.noreply.github.com>
Co-authored-by: Junie <junie@jetbrains.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: kilocode-bot <github-actions@github.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.



The Cox (1979) moment equations are a quadruple loop over the input variables evaluated for every uncertain result, and in Python they dominated the cost of the library. They are now FORTRAN 77 subroutines in src/soerp/_soerp.f, compiled into an extension module by f2py, which returns the numerical core to the language the original SOERP was written in. Python keeps the automatic differentiation, the distribution moments and the public API.
Measured against the pure-Python implementation this replaces, on the same machine and inputs:
10 18598.0us 13.0us 1434.9x 19636.0us 41.1us 477.3x
Cox's own three-part assembly now takes 16us end to end rather than 495us, so a result that used to cost half a millisecond is comfortably inside one. The whole test suite runs in half the time it did.
The kernel is verified, not assumed: it reproduces the exact expansion of E[y**k] for n = 1..5 across every combination of linear, pure-quadratic and cross-product terms, under both standardized and general input moments, and still reproduces Table 2 of the paper.
Build system, following the f2py-tpl template:
The package moves under src/. Without that, a local soerp/ directory shadows the installed package, so
pip install .followed bypytestfrom the repository root imports the source tree, which has no compiled extension, and every test errors oncannot import name '_soerp'.CI has to change shape because the wheel is no longer pure Python. A single artifact can no longer be installed across the test matrix, so the test job builds from source on each runner and installs gfortran where the image lacks it; wheel building moves to cibuildwheel across Linux, Windows and macOS, with the results collected into the artifact the publish workflow already expects.