Skip to content

Eliminate the Variable class #262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 76 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
3a53d8c
A first pass on linear_combo -> ucombo
jagerber48 Aug 9, 2024
01ef70d
revert test changes
jagerber48 Aug 10, 2024
f338549
rework UCombo, delete Variable
jagerber48 Aug 11, 2024
5f64b9e
some test updates
jagerber48 Aug 11, 2024
80e3d31
Pass more tests
jagerber48 Aug 12, 2024
f939766
Merge branch 'master' into feature/linear_combo_refactor
jagerber48 Nov 5, 2024
d7b9a2e
remove large float test
jagerber48 Nov 16, 2024
48c3973
Clean up UFloat class
jagerber48 Nov 17, 2024
1731b5a
some formatting changes
jagerber48 Nov 17, 2024
f0d4225
uncertainty instead of _linear_combo
jagerber48 Nov 17, 2024
1b385f2
variety of updates and test cleanup
jagerber48 Nov 17, 2024
fe849ff
copy tests
jagerber48 Nov 17, 2024
c8fc497
pickling tests
jagerber48 Nov 17, 2024
681bef9
no negative std_dev in tests
jagerber48 Nov 17, 2024
2c1b11d
modify test
jagerber48 Nov 17, 2024
ac6b497
more tests
jagerber48 Nov 17, 2024
b3f7fb2
handle some edge cases with 0 uncertainty
jagerber48 Nov 18, 2024
fc6e592
fix test_hypot
jagerber48 Dec 5, 2024
f2bfc60
compare analytic and numerical derivatives on math functions
jagerber48 Dec 7, 2024
2361849
unumpy
jagerber48 Dec 7, 2024
3c428a2
mainly code to handle inv and pinv array function
jagerber48 Dec 12, 2024
24f1249
Merge remote-tracking branch 'lmfit/master' into feature/linear_combo…
jagerber48 Dec 12, 2024
4084e7f
fix import
jagerber48 Dec 12, 2024
ec8d7f8
slim down UCombo, especially remove __hash__
jagerber48 Dec 13, 2024
eba7ccd
Add hashes
jagerber48 Dec 13, 2024
3f78e5c
bring back is_expanded
jagerber48 Dec 13, 2024
c80dd9b
do not check std_dev during operations. This kills performance.
jagerber48 Dec 13, 2024
5fc3cbd
avoid empty ucombos, or ucombo/uatom weights exactly equal to zero.
jagerber48 Dec 13, 2024
6d53afb
special case empty uncertainty in the tests. Is this something we want??
jagerber48 Dec 13, 2024
7ad82ba
fix broken test that wasn't running
jagerber48 Dec 17, 2024
fb69b1f
ucombo clean up and refactor
jagerber48 Dec 17, 2024
7c35233
don't calculate std_dev with kwargs inputs, cleanup f_with_affine_out…
jagerber48 Dec 17, 2024
0eb135b
some correlated_values_norm cleanup
jagerber48 Dec 17, 2024
c6f116f
todo on untested, probably broken functions
jagerber48 Dec 17, 2024
a8fd413
codecov CI
jagerber48 Dec 18, 2024
0abc0f6
revert previous commit (it was made to the wrong branch and had a wro…
jagerber48 Dec 18, 2024
0086a0a
fixed ucombo hash
jagerber48 Dec 26, 2024
e6211ca
Merge branch 'master' into feature/linear_combo_refactor
jagerber48 Dec 28, 2024
7aeeed0
start updating docs
jagerber48 Dec 28, 2024
ddf2e1d
instance check for ABC real seems to be slow. See if removing that im…
jagerber48 Dec 28, 2024
40b088c
need to include int
jagerber48 Dec 28, 2024
968feef
documentation and doctest
jagerber48 Dec 30, 2024
d5edb5f
fix index
jagerber48 Dec 30, 2024
76a4b80
cast default dict to dict for ucombo expanded dict. Also don't do eag…
jagerber48 Dec 30, 2024
1da88c3
Add back make.bat
jagerber48 Dec 30, 2024
54179b7
add doctest sphinx extension in conf.py so doctests can run
jagerber48 Dec 30, 2024
e8aba3f
Merge branch 'feature/add_make.bat' into feature/linear_combo_refactor
jagerber48 Dec 30, 2024
1da127e
UAtom repr
jagerber48 Dec 30, 2024
17bc5a7
error_components doctest
jagerber48 Dec 30, 2024
34701c2
doctests
jagerber48 Dec 30, 2024
5c309d4
more documentation
jagerber48 Dec 30, 2024
79e00d0
don't document Variable
jagerber48 Dec 31, 2024
9607a0d
add tuples instead of nesting for addition. Will this be faster?
jagerber48 Dec 31, 2024
e7e327d
Merge branch 'master' into feature/linear_combo_refactor
jagerber48 Mar 15, 2025
357a37f
refactor test_power_derivatives
jagerber48 Mar 15, 2025
ee48ae2
Merge branch 'master' into feature/linear_combo_refactor
jagerber48 Apr 10, 2025
1b6bffa
Merge branch 'master' into feature/linear_combo_refactor
jagerber48 Apr 29, 2025
1b95718
fixed mangled merge ordering
jagerber48 Apr 29, 2025
cb5e067
fix import
jagerber48 Apr 29, 2025
8c1e0c8
Merge branch 'master'
jagerber48 May 21, 2025
f8bfcfe
include main in CI (#313)
jagerber48 May 21, 2025
c3d5bb3
Remove deprecated functions (#309)
jagerber48 May 22, 2025
782b8e9
No equality with float (#314)
jagerber48 May 22, 2025
09a809c
Merge branch 'master'
jagerber48 May 22, 2025
e7407cb
Remove zero special handling (#317)
jagerber48 May 23, 2025
abb3c4d
Merge branch 'main' into test_merge_2
jagerber48 May 23, 2025
3485582
fix some tests
jagerber48 May 23, 2025
951abf8
use simpler test
jagerber48 May 23, 2025
f8e3e6e
Merge branch 'master'
jagerber48 May 28, 2025
f506876
Merge branch 'main' into test_merge_2
jagerber48 May 28, 2025
6c119c9
remove unused cases and generation code
jagerber48 May 28, 2025
0003ed8
use other case strategy
jagerber48 May 28, 2025
abca48a
Merge branch 'test_merge_2' into feature/linear_combo_refactor
jagerber48 May 28, 2025
2f899e0
start handling zero weight differently
jagerber48 May 28, 2025
42542fa
rewrite tests
jagerber48 May 28, 2025
8b14818
calculated zero equality test
jagerber48 May 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ name: Run Tests

on:
push:
branches: [ "master" ]
branches: [ "main", "master" ]
pull_request:
branches: [ "master" ]
branches: [ "main", "master" ]

jobs:
build:
Expand Down
34 changes: 34 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
Change Log
===================

Unreleased 4.x
--------------

Changes:

- Includes the `main` branch in continuous integration automation.
- [**BREAKING**] Previously when tallying the uncertainty for a `UFloat` object, the
contribution from other `UFloat` objects with `std_dev == 0` were excluded. Now this
special casing for `std_dev == 0` has been removed so that the contribution from all
contributing `UFloat` objects is included. This changes the behavior in certain
corner cases where `UFloat` `f` is derived from `UFloat` `x`, `x` has `x.s == 0`, but
the derivative of `f` with respect to `x` is `NaN`. For example, previously
`(-1)**ufloat(1, 0)` gave `-1.0+/-0`. The justification for this was that the second
`UFloat` with `std_dev` of `0` should be treated like a regular float. Now the same
calculation returns `-1.0+/-nan`. In this case the `UFloat` in the second argument
of the power operator is treated as a degenerate `UFloat`.

Removes:

- [**BREAKING**] Removes certain deprecated `umath` functions and
`AffineScalarFunc`/`UFloat` methods. The following `umath` functions are removed:
`ceil`, `copysign`, `fabs`, `factorial`, `floor`, `fmod`, `frexp`, `ldexp`, `modf`,
`trunc`. The following `AffineScalarFunc`/`UFloat` methods are removed:
`__floordiv__`, `__mod__`, `__abs__`, `__trunc__`, `__lt__`, `__le__`, `__gt__`,
`__ge__`, `__bool__`.
- [**BREAKING**] Previously it was possible for a `UFloat` object to compare equal to a
`float` object if the `UFloat` `standard_deviation` was zero and the `UFloat`
`nominal_value` was equal to the `float`. Now, when an equality comparison is made
between a `UFloat` object and another object, if the object is not a `UFloat` then
the equality comparison is deferred to this other object. For the specific case of
`float` this means that the equality comparison always returns `False`.
- [**BREAKING**] The `uncertainties` package is generally dropping formal support for
edge cases involving `UFloat` objects with `std_dev == 0`.

Unreleased
----------

Expand Down
6 changes: 2 additions & 4 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ quick taste of how to use :mod:`uncertainties`:
The :mod:`uncertainties` library calculates uncertainties using linear `error
propagation theory`_ by automatically :ref:`calculating derivatives
<derivatives>` and analytically propagating these to the results. Correlations
between variables are automatically handled. This library can also yield the
derivatives of any expression with respect to the variables that have uncertain
values. For other approaches, see soerp_ (using higher-order terms) and mcerp_
(using a Monte-Carlo approach).
between variables are automatically handled. For other approaches, see soerp_ (using
higher-order terms) and mcerp_ (using a Monte-Carlo approach).

The `source code`_ for the uncertainties package is licensed under the `Revised
BSD License`_. This documentation is licensed under the `CC-SA-3 License`_.
Expand Down
135 changes: 35 additions & 100 deletions doc/tech_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ user-supplied function.

.. autofunction:: ufloat_fromstr

.. autoclass:: Variable
.. autoclass:: UFloat

.. autofunction:: wrap

Expand Down Expand Up @@ -93,102 +93,47 @@ are completely uncorrelated.
.. _comparison_operators:


Comparison operators
--------------------
Equality Comparison
-------------------

Comparison operations (>, ==, etc.) on numbers with uncertainties have
a **pragmatic semantics**, in this package: numbers with uncertainties
can be used wherever Python numbers are used, most of the time with a
result identical to the one that would be obtained with their nominal
value only. This allows code that runs with pure numbers to also work
with numbers with uncertainties.
Numbers with uncertainty, :class:`UFloat` objects, model random variables.
There are a number of senses of equality for two random variables.
The stronger senses of equality define two random variables to be equal if the two
random variables always produce the same result given a random sample from the sample
space.
For :class:`UFloat`, this is the case if two :class:`UFloat` objects have equal
nominal values and standard deviations and are perfectly correlated.
We can test for these conditions by taking the difference of two :class:`UFloat` objects
and looking at the nominal value and standard deviation of the result.
If both the nominal value and standard deviation of the difference are zero, then the
two :class:`UFloat` objects have the same nominal value, standard deviation, and are
perfectly correlated.
In this case we say the two :class:`UFloat` are equal.

.. index:: boolean value

The **boolean value** (``bool(x)``, ``if x …``) of a number with
uncertainty :data:`x` is defined as the result of ``x != 0``, as usual.

However, since the objects defined in this module represent
probability distributions and not pure numbers, comparison operators
are interpreted in a specific way.

The result of a comparison operation is defined so as to be
essentially consistent with the requirement that uncertainties be
small: the **value of a comparison operation** is True only if the
operation yields True for all *infinitesimal* variations of its random
variables around their nominal values, *except*, possibly, for an
*infinitely small number* of cases.

Example:

>>> x = ufloat(3.14, 0.01)
>>> x == x
>>> x = ufloat(1, 0.1)
>>> a = 2 * x
>>> b = x + x
>>> print(a - b)
0.0+/-0
>>> print(a == b)
True

because a sample from the probability distribution of :data:`x` is always
equal to itself. However:
It might be the case that two random variables have the same marginal probability
distribution but are uncorrelated.
A weaker sense of equality between random variables may consider two such random
variables to be equal.
This is equivalent to two :class:`UFloat` objects have equal nominal values and
standard deviations, but, are uncorrelated.
The :mod:`uncertainties` package, however, keeps to the stronger sense of random
variable equality such that two such :class:`UFloat` objects do not compare as equal.

>>> y = ufloat(3.14, 0.01)
>>> x == y
>>> x = ufloat(1, 0.1)
>>> y = ufloat(1, 0.1)
>>> print(x - y)
0.00+/-0.14
>>> print(x == y)
False

since :data:`x` and :data:`y` are independent random variables that
*almost* always give a different value (put differently,
:data:`x`-:data:`y` is not equal to 0, as it can take many different
values). Note that this is different
from the result of ``z = 3.14; t = 3.14; print(z == t)``, because
:data:`x` and :data:`y` are *random variables*, not pure numbers.

Similarly,

>>> x = ufloat(3.14, 0.01)
>>> y = ufloat(3.00, 0.01)
>>> x > y
True

because :data:`x` is supposed to have a probability distribution largely
contained in the 3.14±~0.01 interval, while :data:`y` is supposed to be
well in the 3.00±~0.01 one: random samples of :data:`x` and :data:`y` will
most of the time be such that the sample from :data:`x` is larger than the
sample from :data:`y`. Therefore, it is natural to consider that for all
practical purposes, ``x > y``.

Since comparison operations are subject to the same constraints as
other operations, as required by the :ref:`linear approximation
<linear_method>` method, their result should be essentially *constant*
over the regions of highest probability of their variables (this is
the equivalent of the linearity of a real function, for boolean
values). Thus, it is not meaningful to compare the following two
independent variables, whose probability distributions overlap:

>>> x = ufloat(3, 0.01)
>>> y = ufloat(3.0001, 0.01)

In fact the function (x, y) → (x > y) is not even continuous over the
region where x and y are concentrated, which violates the assumption
of approximate linearity made in this package on operations involving
numbers with uncertainties. Comparing such numbers therefore returns
a boolean result whose meaning is undefined.

However, values with largely overlapping probability distributions can
sometimes be compared unambiguously:

>>> x = ufloat(3, 1)
>>> x
3.0+/-1.0
>>> y = x + 0.0002
>>> y
3.0002+/-1.0
>>> y > x
True

In fact, correlations guarantee that :data:`y` is always larger than
:data:`x`: ``y-x`` correctly satisfies the assumption of linearity,
since it is a constant "random" function (with value 0.0002, even
though :data:`y` and :data:`x` are random). Thus, it is indeed true
that :data:`y` > :data:`x`.


.. index:: linear propagation of uncertainties
.. _linear_method:

Expand Down Expand Up @@ -252,16 +197,6 @@ This indicates that **the derivative required by linear error
propagation theory is not defined** (a Monte-Carlo calculation of the
resulting random variable is more adapted to this specific case).

However, even in this case where the derivative at the nominal value
is infinite, the :mod:`uncertainties` package **correctly handles
perfectly precise numbers**:

>>> umath.sqrt(ufloat(0, 0))
0.0+/-0

is thus the correct result, despite the fact that the derivative of
the square root is not defined in zero.

.. _math_def_num_uncert:

Mathematical definition of numbers with uncertainties
Expand Down
Loading
Loading