Repository navigation
feat(math): add es.math, maths functions for Parameters with variance and bounds propagation - #327
Closed
markbujehein wants to merge 21 commits into
Closed
markbujehein wants to merge 21 commits into
markbujehein wants to merge 21 commits into
Conversation
…nces as per latest pixi standard (done by `pixi install`)
…onometric functions
…ctions - Update trigonometric functions to accept only the Parameter type. - Add new inverse trigonometric functions.
- Add TODO comments for inverse trigonometric functions.
Fix inheritance type errors (PEP 673) when invoking from_scipp() on subclassed objects like Parameter.
- Remove unused imports and commented-out code. - Standardize function headers and docstrings. - Add helper functions for bounds derivation to improve error handling. - Centralize Scipp operations for trig functions (sin, cos, tan, etc.). - Add a new sinc function with dedicated error handling and docs. - Protect tangent bounds to prevent variance explosions near asymptotes.
Replace the generic dispatcher with declarative `_MathOp` specs and add log10, sqrt, erf, erfc and the hyperbolic functions (sinh, cosh, tanh, arcsinh, arccosh, arctanh). - Derive exact result bounds from endpoints and critical points instead of a sampled grid, which could miss an extremum and make Parameter.from_scipp raise - Convert degrees to radians for trig bounds - Accept infinite bounds; clip bounds to the function's domain - Raise ValueError for out-of-domain values and non-finite results - Propagate variance for erf, erfc and arctan2 via a Jacobian (delta method), as Scipp lacks support - Remove ~500 lines of commented-out code - Export all math functions from easyscience.variable and make __all__ a list of strings - Add unit tests in tests/unit/variable/test_math.py
Give each of the 20 public math functions two examples, using rad and deg for angle functions and two dimensionless cases (bounds, variance, clipping or units) for the rest. Outputs were generated by executing the examples and cross-checked against independent formulas.
Annotate every test in test_math.py with WHEN / THEN / EXPECT comments.
…iance handling - Replace `lru_cache` with `cache` from `functools` for simpler caching. - Add constants for mathematical limits and tolerances. - Enhance error messages for exponential and hyperbolic overflow conditions. - Enforce checks for finite results during variance propagation in math operations. - Expand test coverage for `sinc` edge cases and `tan`/`arctan2` variance propagation. - Mark test for known collapsed bounds bug in `Parameter` (`@pytest.mark.xfail`).
… enhanced tests. Also added common aliases.
__all__ held the objects themselves (including the value of __version__) instead of their names. The language reference requires a sequence of strings, so `from easyscience import *` failed with AttributeError on the first entry, the version string. Only star imports were affected, which is why it went unnoticed. List the names instead, keeping the same set of public objects. Also import the math submodule and add it to __all__, so that `es.math` is available.
Remove the math module from easyscience.math to prevent naming conflicts with Python's built-in math library.
- tan: a bound exactly on an asymptote now makes the result infinite on that side only, so [0, 90] deg gives [0, inf) instead of (-inf, inf); a lower bound on an asymptote gives -inf - variable: re-export the math names with `from .math import *` and build __all__ from math.__all__ instead of keeping a second list - math: document how to use es.math inside a model (derive in __call__, results are snapshots, inputs are assumed uncorrelated, uncertainties depend on the minimizer) and leave NOTE()/TODO() remarks for the lead developer (1-sigma guards, non-fixed snapshot results, cost per evaluation, hard-coded Para tolerance) - tests: add integration tests that apply es.math to fitted parameters (straight line, angle in degrees, quadrature, Gaussian peak with a width derived in __call__, across minimizers), a strict xfail documenting that correlated parameters are propagated as independent, and unit tests for degree variances, tan bounds on asymptotes and the package star import not exporting math
Every es.math function now takes a DescriptorNumber or a Parameter (including user subclasses). The result is a Parameter, with bounds, if any argument is a Parameter, and a DescriptorNumber otherwise; it is always the base class. A DescriptorNumber argument counts as the point [value, value] when the bounds are derived. Unary functions are typed with a TypeVar; arctan2 has three overloads. Tests cover the new input and result classes, subclasses, mixed arctan2, the unit keyword and the guards. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Collaborator
Author
|
As far as I can tell, the workflows .github/workflows/docs.yml and .github/workflows/tutorial-tests.yml will inherently fail for any PR from a fork Not sure what's is going on with .github/workflows/lint-format.yml, but seems to be related to the ongoing refactoring (?) |
markbujehein
marked this pull request as draft
October 13, 2026 09:14
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.
Summary
This adds
es.math, a set of maths functions that takeParameterobjects and return a newParameter. Each result carries:The functions are:
sin,cos,tan,sinc,arcsin,arccos,arctan,arctan2, plus the aliasesasin,acos,atanandatan2.sinh,cosh,tanh,arcsinh,arccosh,arctanh, plus the aliasesasinh,acoshandatanh.exp,log,log10,sqrt,erf,erfc.The implementation is in
easyscience.variable.math.easyscience.mathis a thin re-export, soes.math.sin(angle)works. The names are also exported fromeasyscience.variable.Motivation
This work is motivated by the needs discussed in
Parameters such assinandcos#201Design
_MathOpspec (Scipp function, domain, bounds strategy). One dispatcher,_apply, handles all of them, so adding a function means adding a spec rather than new control flow.Parameter.from_scippraise. Degrees are converted to radians for trig bounds.ValueError, because it would break a fit loop.tanhandles asymptotes per side. For example,[0, 90] deggives[0, inf), and a lower bound exactly on an asymptote gives-inf.erf,erfcandarctan2use a Jacobian because Scipp doesn't support them.tanrejects values near an asymptote, where the variance would blow up.Other changes
__all__fix.easyscience/__init__.pyandvariable/__init__.pylisted the objects themselves, including the__version__string, instead of their names. As a result,from easyscience import *raisedAttributeError. Both now list strings, andvariable.__all__includesmath.__all__.es.mathin the top-level__all__.mathis imported soes.mathworks, but it is deliberately left out of the top-level__all__. A star import would otherwise shadow the stdlibmath. A test covers this.from_scippreturn type. It now returnsSelf(PEP 673) indescriptor_number.py, so calling it on a subclass such asParametertype-checks.docs/api-reference/math.md, nav entry and index entry. All 20 public functions have docstring examples that were executed and cross-checked against independent formulas.Tests
tests/unit/variable/test_math.py: unit tests for values, bounds, variance, domain errors, units and the namespace. They are written in the repo's WHEN / THEN / EXPECT style.tests/integration/fitting/test_math_in_fit.py:es.mathused inside models (straight line, angle in degrees, quadrature, Gaussian peak with a derived width) across minimizers.xfaildocuments the known limitation described below.Known limitations and notes for reviewers
Correlations are ignored. Variances assume uncorrelated inputs, because a
Parameterstores a variance but no covariance. A function of strongly correlated fit parameters can be off by a large factor. The strictxfailtest documents this, and the module docstring explains it.Results are snapshots. A result doesn't follow later changes to its inputs. Inside a model, derive it in
__call__, not__init__. The module docstring has a worked example.Open points for the lead developer. These are marked
NOTE()andTODO()inmath.py:tanguards.pixi.lock.419828cmodifiespixi.lock. It looks like the result of runningpixi install, so please check whether it should stay in this PR. Seems like Pixi is updating the lock file to a newer format.Out of scope. This PR does not yet address the issues mentioned in: