-
Notifications
You must be signed in to change notification settings - Fork 476
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
The Measurements Overhaul for 0.8 #350
Comments
I figured out a better fix for the first problem listed if you are interested. The problem comes in the call to the if isinstance(value, ufloat) and cls is not cls._REGISTRY.Measurement:
cls = cls._REGISTRY.Measurement The added if statement allows the constructor to use the proper There was a constructor bug in the def __new__(cls, value, error, units=MISSING):
if units is MISSING:
# new if statement
# missed option before
if isinstance(value, ufloat):
inst = super(_Measurement, cls).__new__(cls, value, error)
return inst
# the old method
try:
value, units = value.magnitude, value.units
except AttributeError:
try:
value, error, units = value.nominal_value, value.std_dev, error
except AttributeError:
units = ''
try:
error = error.to(units).magnitude
except AttributeError:
pass
inst = super(_Measurement, cls).__new__(cls, ufloat(value, error), units)
if error < 0:
raise ValueError('The magnitude of the error cannot be negative'.format(value, error))
return inst My apologies for not making this suggestion via a pull request. I ended up using my own uncertain math package instead of |
Thanks for the feedback. Can you elaborate about why are you dropping uncertainties in favor of another option? It might be useful to feedback into the Measurement design. |
Mostly I need a package that can handle non-linear functions. For example, here are the results for a nonlinear function of two random variables that are distributed according to a multi-variate normal. x_mean = [1.0, 2.0]
x_covariance = [[1.0, 0.1], [0.1, 1.0]]
def f(x):
return 1/(x[0]**2 + x[1]**2 + 1) + x[0]x[1]**2 The below results compare 5 different methods for computing the function. The most important is the Monte Carlo plot in purple since this can be considered the "true" value of the function. Of course these results vary for different functions and distributions of the rvs, but the important point is that So all in all I wanted more functionality and more accuracy than |
Thanks for the detailed information. It does help a lot! I was wondering if you would like to contribute your code to Pint. Instead of using another package to optionally provide support for Measurements, we will be making Measurements a first class citizen of the package. What do you think? |
I think that's a great idea. I need to get permission to release my code under an open source license first. It may take some time, but I don't anticipate it being an issue. The code does have one dependency, which is the |
Great! Let me know. I do not think depending on autograd is a problem. When you are ready, just organize your commits, push your changes and issue a PR. |
First, I apologize for the long post. I did not realize it would be this long when I started it... I think it would be useful to separate the Measurement class from error propagation. A measurement is quantity with an uncertainty, and there are many useful features that the Measurement class can provide. Here are just a few that come to mind: the upper bound (nominal value + uncertainty) These are fairly simple calculations, but it would be nice if the measurement class did them. There is currently an issue with non-multiplicative units that could be resolved if the Measurement class did this, I can't do this for example:
because I can't add two temperatures. These features would be more useful if you wanted to add support for non-symmetric errors. If we assume that the measurement has Gaussian statistics (which is the only assumption that makes sense when the uncertainty is specified as a single quantity), then these features would be useful: the 95% confidence interval for the measurement All of these things would be useful, and are separate from error propagation. And now for error propagation... I would argue that error propagation is like function interpolation. Most people that need to do it have some very specific requirements and end up using their own code for anything beyond very basic calculations because no available library does everything exactly the way that they need. For example, I also use my own error propagation module (https://github.com/CD3/pyErrorProp) because I teach an undergraduate level physics lab and I needed to be able to reproduce the uncertainties that our students would calculate by hand, and we do not use the derivative method. There are many cases where the derivative method simply does not work. For example, what if I want to propagate error through a function that I don't have an analytic expression for? As @alexfeld points out, the "correct" way to propagate error is to use a Monte-Carlo algorithm. But even then there are numerous options. The "real correct" way to propagate error would be to specify a complete probability distribution for all inputs to a calculation and compute the complete probability distribution for the result. But this is usually not possible because the input probability distributions are not available (and it may take way to long to calculate). So, we have to make some assumptions. If we assume that all of the inputs are Gaussian, then we can use a Monte Carlo method to generate the result's probability distribution. But here again, we will have to make an assumption because the result's probability distribution may not be Gaussian or symmetric. So it's not possible to characterize it with just a nominal value and error. So, my point is this. Any error propagation method you choose will likely only satisfy a minority of users. Anyhow, that is my two cents. Again, sorry for the long post. |
@CD3 Do not apologize. On the contrary, thanks for taking the time to write this. It is very useful. I do agree that it will be nice to support what you suggested. My problem with not providing any kind of error propagation for a Measurement class is that event most simple operations will fail. For example, you have two measurements and want to calculate their product, you do So the question would be ... how can we support the common case, make it clear that we this is only valid in certain cases, but still make it easy to extend? |
Yes, I agree. There should be some simple default algorithm so that things like addition, subtraction, multiplication, and division work. The simple method that I teach in physics laboratory courses is that the uncertainty in a calculation I only have experience with C++ operator overloading, so I don't know the details of how Python handles it, but from what I have read it seems like the I also don't know much about the details of |
Another thought I've had in the past is that it would be nice if the My particular need is for rounding. There are rules for how to round a quantity with uncertainty, and I want to be able to reproduce the same rounded result as a hand calculation, but using a |
It looks like the latest version of numpy (1.11) adds a new magic method named |
If I understand this thread correctly, the idea is to make Measurement.backends.error_propagation.base.propagate_error(X, F, COV, **KW) -> DF
"""
base class for Measurement class error propagation backend. Implements the default method.
:param X: a sequence of dependent variables
:param F: function that takes X
:param COV: a covariance matrix for X
:param KW: backend specific keyword arguments
:return: DF a covariance matrix for the output of F(X)
""" As it is I also fall into the camp of writing our own package, UncertaintyWrapper because we needed a much faster implementation than the autodifferentiation or Monte Carlo approaches, we also needed something that did not overload or force us to rewrite our code using specific implementations of ufuncs and most importantly we needed something that could wrap extensions in C/C++. Currently our method works with the Pint wrapper, but would be improved by PR #364. Also, I think that use of the new explicit overloading method in Numpy-1.11
... which is according to these threads (numpy-7591, uncertainties-47) ...
|
@mikofski I did not know about the better numpy overloading method. Thank you for pointing that out! My apologies for disappearing for a while, my time has been diverted to other projects. I have stopped work on this at the moment, but I will commit what I had before so you can see what I was doing. I do not know if it will be useful because it is basically just a different version of |
I'll add to this that
wrapped_f(Q) returns a value in meters, as expected, but if I add uncertainty:
wrapped_f(Q) doesn't seem to recognize the units on Q anymore. It raises a ValueError:
|
This issue is to summarize the overhaul of Measurements targeted for Pint 0.8. The features/open questions are:
The text was updated successfully, but these errors were encountered: