-
-
Notifications
You must be signed in to change notification settings - Fork 77
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
Eliminate the Variable
class
#262
base: master
Are you sure you want to change the base?
Eliminate the Variable
class
#262
Conversation
Variable
class
@@ -104,9 +105,6 @@ def test_ufloat_fromstr(): | |||
"3.4(nan)e10": (3.4e10, float("nan")), | |||
# NaN value: | |||
"nan+/-3.14e2": (float("nan"), 314), | |||
# "Double-floats" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These floats are too large to work with. Prior to this PR the large float value could be saved into the AffineScalarFunc
object and displayed, but any arithmetic with such large values would result in an OverflowError
. In the new framework even displaying a UFloat
the first time requires a calculation, even if it's as simple as sqrt(x**2)
. So in the new framework the OverflowError
appears immediately.
All the tests are passing except some having to do with the uarray inverse and pseudo inverse functions. The code for this is pretty complicated. It might make sense to just rewrite the code to convert array-compatible functions to ufloat array compatible functions. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #262 +/- ##
==========================================
- Coverage 96.55% 93.62% -2.94%
==========================================
Files 17 18 +1
Lines 1947 2039 +92
==========================================
+ Hits 1880 1909 +29
- Misses 67 130 +63
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Wow all tests are passing now. That's a big milestone for this PR. If folks are interested I'd be curious to hear general feedback on the source code changes in this PR. I tried to do as little wholesale rewriting as possible but did chose to do some of that in Here's a summary of the changes so far. See #251 for a more thorough discussion of these changes and their motivations.
Some todo items
Other notes:
|
This test wasn't running because the generator defining ufloat_args was consumed while calculating output so it couldn't be iterated over again for the for loop. Need to save the result as a list before using it.
These functions need to be overhauled so for now trying to make minimal changes while keeping functionality to keep the PR as slim as possibly (though it's already pretty huge)
…ng commit message)
return self._hash | ||
|
||
def __lt__(self: UAtom, other: UAtom) -> bool: | ||
return self.uuid < other.uuid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
codecov gives a load of warnings for UAtom and UCombo. Would bit be worth having tests to show methods like eq, lt behave as expected?
it's also a bit suprising some of these lines (eg for UCombo's eq) don't get hit by any of the existing tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking a look. I haven't looked at codecov yet. The story for why UCombo
s __eq__
doesn't get hit is worth sharing.
First off, before this PR and as of this comment, UFloat.__eq__
does not check for equality of the nominal value and equality of the uncertainty as I would have naively implemented. Rather, it looks at the difference between self
and other
and checks that the resulting UFloat
has zero nominal value and zero std_dev. Because subtraction is supported between UFloat
and float
, this allows __eq__
to easily support comparison between UFloat
and float
. In going through the tests I've learned that, for better or for worse, uncertainties
has definitely chosen the convention that a UFloat
with a std_dev
of zero should behave like a regular float
.
I am still using this difference calculation for UFloat.__eq__
. It would be more natural to me to have __eq__
be something like
def __eq__(self, other):
if isinstance(other, UFloat):
return (self.nominal_value == other.nominal_value and self.uncertainty = other.uncertainty)
else:
if self.std_dev != 0:
return False
else:
return self.nominal_value == other
But currently the code implementing __eq__
is defined in ops.py
and gets monkey patched onto UFloat
. I can't import UFloat
into this function because it would create circular imports between ops.py
and core.py
.
Anyways, I can look into disentangling this.
Note though, that I tried something like the above code for a second and found out that the current version of UCombo.__eq__
was broken because I didn't know sorted
returned a list! Easy fix, but emphasizes the importance of testing.
Note that I made the decision that UCombo
__eq__
and __hash__
use the expanded
dictionary for comparison. Thuis means that two UCombo
s with different ucombo_tuple
s could compare equal. For UFloat
I think it is clear that we want two UFloat
s to compare based on the expanded dictionary from the uncertainty. For UCombo
it wasn't as obvious to me. For example, if dx
is a UAtom
then it would be possible for there to be a nested UCombo
storing something like
dx + (-dx + (dx + (-dx + (dx + (-dx + ...)))))
Which ultimately is equal to 0. But the former might take a longer time to compute.
Actually I think I need to add a special case for 0 so that the presence of a UAtom
in one UCombo
expanded dict but not the other doesn't matter if the weight is equal to 0.
In any case, does this make sense to allow two UCombo
to compare the same even if they have different ucombo_tuple
? Or should that distinction be made apparent in __eq__
and __hash__
(but UFloat
will still compare based on expanded
dict)?
sorted returns a (unhashable) list, so much convert this list to a tuple before hashing.
- [x] Closes #274 - [x] Executed `pre-commit run --all-files` with no errors - [x] The change is fully covered by automated unit tests - [x] Documented in docs/ as appropriate - [x] Added an entry to the CHANGES file add a performance benchmark test. This test is important especially to ensure #262 doesn't introduce a performance regression. --------- Co-authored-by: andrewgsavage <[email protected]>
CodSpeed Performance ReportMerging #262 will degrade performances by 35.86%Comparing Summary
Benchmarks breakdown
|
Ok, it is time to pick the names of the classes because I want to start updating the docs (I'm not technically blocked but would be nice to get it right earlier). Right now we have For reference, suppose we have
Notes on names:
|
…er checks for absence of uncertainty terms.
pre-commit run --all-files
with no errorsThis PR:
Variable
class and eliminates theAffineScalarFunc.derivatives
property.AffineScalarFunc
class is renamed toUFloat
withAffineScalarFunc
left as a legacy name.LinearCombo
class is refactored into theUCombo
class but the architectural role is similar: track the uncertainties ofUFloat
objects as a lazily expanded combination of objects with uncertaintyUAtom
object is introduced as the fundamental element which captures uncertainty. EachUAtom
models a random variable with zero mean and unity standard deviation/variance. EachUAtom
has auuid
and allUAtom
are mutually statistically independent. The expanded version of theUCombo
mapsdict[UAtom, float]
.For more detail/discussion see #251 (comment)
Note that as of the time opening this PR the PR is still a work in progress. Not all elements in the bullet list above are implemented and a good handful of tests are still failing.