Skip to content

Commit f5859a9

Browse files
authored
Merge pull request #1 from phisgroup/development-1.1.4
Development 1.1.4
2 parents 5127d8d + 4ed5ace commit f5859a9

File tree

3 files changed

+111
-32
lines changed

3 files changed

+111
-32
lines changed

README.md

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,66 @@
11
# labfis.py
2-
Small library (currently only one class) for uncertainty calculations. Made by and for Physics Laboratory students in IFSC, who can't use uncertainties.py because mean absolute deviation.
2+
3+
## Description
4+
5+
Small library (currently only one class) for uncertainty calculations and error propagation.
6+
7+
The uncertainty calculations are in accordance with gaussian’s propagation, as calculated by an analytical method:
8+
9+
<p align="center">
10+
<img src="https://latex.codecogs.com/svg.latex?%5Cdpi%7B120%7D%20%5CDelta_f%20%3D%20%5Csqrt%7B%5Cleft%28%5Cfrac%7B%5Cpartial%20f%7D%7B%5Cpartial%20x%7D%5Cright%29%5E2%7B%5CDelta_x%7D%5E2%20&plus;%20%5Cleft%28%5Cfrac%7B%5Cpartial%20f%7D%7B%5Cpartial%20y%7D%5Cright%29%5E2%7B%5CDelta_y%7D%5E2%20&plus;%20%5Cleft%28%5Cfrac%7B%5Cpartial%20f%7D%7B%5Cpartial%20z%7D%5Cright%29%5E2%7B%5CDelta_z%7D%5E2%20&plus;%20...%7D">
11+
</p>
12+
13+
Made by and for Physics Laboratory students in IFSC, who can't use uncertainties.py because of mean’s absolute deviation used in its calculation.
314

415
To get this library on google colaboratory:
5-
16+
617
```
718
!curl --remote-name \
8-
-H 'Accept: application/vnd.github.v3.raw' \
9-
--location https://raw.githubusercontent.com/phisgroup/labfis.py/master/labfis/main.py
19+
20+
-H 'Accept: application/vnd.github.v3.raw' \
21+
22+
--location https://raw.githubusercontent.com/phisgroup/labfis.py/development/labfis/main.py
23+
```
24+
25+
## Usage
26+
27+
Just import with `from labfis import labfloat` and create an *labfloat* object, as this exemple below:
28+
29+
```py
30+
>>> from labfis import labfloat
31+
>>> a = labfloat(1,3)
32+
>>> b = labfloat(2,4)
33+
>>> a*b
34+
(2 ± 7)
1035
```
36+
Check the Wiki for more details
37+
38+
## Instalation
39+
40+
Intstall main releases with:
41+
42+
```
43+
pip install labfis
44+
```
45+
46+
Install development version with:
47+
48+
```
49+
pip install git+https://github.com/phisgroup/labfis.py/tree/development
50+
```
51+
52+
## References
53+
54+
1. Kirchner, James. ["Data Analysis Toolkit #5: Uncertainty Analysis and Error Propagation"](http://seismo.berkeley.edu/~kirchner/eps_120/Toolkits/Toolkit_05.pdf) (PDF). _Berkeley Seismology Laboratory_. University of California. Retrieved 22 April 2016.
55+
2. [Goodman, Leo](https://en.wikipedia.org/wiki/Leo_Goodman "Leo Goodman") (1960). "On the Exact Variance of Products". _Journal of the American Statistical Association_. **55** (292): 708–713. [doi](https://en.wikipedia.org/wiki/Doi_(identifier) "Doi (identifier)"):[10.2307/2281592](https://doi.org/10.2307%2F2281592). [JSTOR](https://en.wikipedia.org/wiki/JSTOR_(identifier) "JSTOR (identifier)") [2281592](https://www.jstor.org/stable/2281592).
56+
3. Ochoa1,Benjamin; Belongie, Serge ["Covariance Propagation for Guided Matching"](http://vision.ucsd.edu/sites/default/files/ochoa06.pdf)
57+
4. Ku, H. H. (October 1966). ["Notes on the use of propagation of error formulas"](http://nistdigitalarchives.contentdm.oclc.org/cdm/compoundobject/collection/p16009coll6/id/99848/rec/1). _Journal of Research of the National Bureau of Standards_. **70C** (4): 262. [doi](https://en.wikipedia.org/wiki/Doi_(identifier) "Doi (identifier)"):[10.6028/jres.070c.025](https://doi.org/10.6028%2Fjres.070c.025). [ISSN](https://en.wikipedia.org/wiki/ISSN_(identifier) "ISSN (identifier)") [0022-4316](https://www.worldcat.org/issn/0022-4316). Retrieved 3 October 2012.
58+
5. Clifford, A. A. (1973). _Multivariate error analysis: a handbook of error propagation and calculation in many-parameter systems_. John Wiley & Sons. [ISBN](https://en.wikipedia.org/wiki/ISBN_(identifier) "ISBN (identifier)") [978-0470160558](https://en.wikipedia.org/wiki/Special:BookSources/978-0470160558 "Special:BookSources/978-0470160558").
59+
6. Lee, S. H.; Chen, W. (2009). "A comparative study of uncertainty propagation methods for black-box-type problems". _Structural and Multidisciplinary Optimization_. **37** (3): 239–253. [doi](https://en.wikipedia.org/wiki/Doi_(identifier) "Doi (identifier)"):[10.1007/s00158-008-0234-7](https://doi.org/10.1007%2Fs00158-008-0234-7).
60+
7. Johnson, Norman L.; Kotz, Samuel; Balakrishnan, Narayanaswamy (1994). _Continuous Univariate Distributions, Volume 1_. Wiley. p. 171. [ISBN](https://en.wikipedia.org/wiki/ISBN_(identifier) "ISBN (identifier)") [0-471-58495-9](https://en.wikipedia.org/wiki/Special:BookSources/0-471-58495-9 "Special:BookSources/0-471-58495-9").
61+
8. Lecomte, Christophe (May 2013). "Exact statistics of systems with uncertainties: an analytical theory of rank-one stochastic dynamic systems". _Journal of Sound and Vibrations_. **332** (11): 2750–2776. [doi](https://en.wikipedia.org/wiki/Doi_(identifier) "Doi (identifier)"):[10.1016/j.jsv.2012.12.009](https://doi.org/10.1016%2Fj.jsv.2012.12.009).
62+
9. ["A Summary of Error Propagation"](http://ipl.physics.harvard.edu/wp-uploads/2013/03/PS3_Error_Propagation_sp13.pdf) (PDF). p. 2. Retrieved 2016-04-04.
63+
10. ["Propagation of Uncertainty through Mathematical Operations"](http://web.mit.edu/fluids-modules/www/exper_techniques/2.Propagation_of_Uncertaint.pdf) (PDF). p. 5. Retrieved 2016-04-04.
64+
11. ["Strategies for Variance Estimation"](http://www.sagepub.com/upm-data/6427_Chapter_4__Lee_%28Analyzing%29_I_PDF_6.pdf) (PDF). p. 37. Retrieved 2013-01-18.
65+
12. Harris, Daniel C. (2003), [_Quantitative chemical analysis_](https://books.google.com/books?id=csTsQr-v0d0C&pg=PA56)(6th ed.), Macmillan, p. 56, [ISBN](https://en.wikipedia.org/wiki/ISBN_(identifier) "ISBN (identifier)") [978-0-7167-4464-1](https://en.wikipedia.org/wiki/Special:BookSources/978-0-7167-4464-1 "Special:BookSources/978-0-7167-4464-1")
66+
13. ["Error Propagation tutorial"](http://www.foothill.edu/psme/daley/tutorials_files/10.%20Error%20Propagation.pdf) (PDF). _Foothill College_. October 9, 2009. Retrieved 2012-03-01.

labfis/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Copyright © 2020 labfis.py
44
# (see LICENSE for details)
55

6-
__version__ = '1.0.0'
6+
__version__ = '1.1.4'
77

88
# Local imports
99
from labfis.main import labfloat

labfis/main.py

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from math import floor, ceil, trunc, log, log10
1+
from math import floor, ceil, trunc, log, log10, sqrt
22
from numbers import Number
33

44
class LabFloatError(Exception):
@@ -26,12 +26,12 @@ def __init__(self, *args, **kwargs):
2626

2727
if args:
2828
if len(args) == 1:
29-
mean = args[0]
29+
mean = args[0]
3030
elif len(args) == 2:
3131
mean = args[0]
3232
uncertainty = args[1]
3333
else:
34-
raise LabFloatError("Too many arguments, expected (val,err), got: ",args)
34+
raise LabFloatError("Too many arguments, expected (val,err) or ([(val,err),...]), got: ",args)
3535

3636
self.mean = float(mean)
3737
self.uncertainty = abs(float(uncertainty))
@@ -77,29 +77,48 @@ def split(self):
7777
else:
7878
m, u = self.format()
7979
return(["{:g}".format(m),"{:g}".format(u)])
80-
81-
def tex(self):
82-
val = self.split()
83-
if len(val) == 1:
84-
m = val[0].split("e")
80+
81+
def tex(self,*args,**kwargs):
82+
precision = kwargs.get('precision')
83+
if args:
84+
if len(args) == 2:
85+
precision = args
86+
elif len(args) > 2:
87+
raise LabFloatError("Too many arguments, expected: (precision) or (mean precision,err precision) got: ",args)
88+
else:
89+
precision = [args[0],args[0]]
90+
91+
if self.uncertainty == 0:
92+
if precision:
93+
precision[0] = str(precision[0])
94+
m = eval("'{:."+precision[0]+"e}'.format(self.mean)")
95+
else:
96+
m = self.split()[0]
97+
m = m.split("e")
8598
if len(m) > 1:
86-
m = m[0]+"\cdot 10^{"+m[1]+"}"
99+
m = m[0]+r"\cdot 10^{"+m[1]+"}"
87100
else:
88101
m = m[0]
89102
return("{0}".format(m))
90103
else:
91-
m,u = val
104+
if precision:
105+
precision = (str(precision[0]),str(precision[1]))
106+
m, u = self.format()
107+
m = eval("'{:."+precision[0]+"e}'.format(m)")
108+
u = eval("'{:."+precision[1]+"e}'.format(u)")
109+
else:
110+
m, u = self.split()
92111
m = m.split("e")
93112
u = u.split("e")
94113
if len(m) > 1:
95-
m = m[0]+"\cdot 10^{"+m[1]+"}"
114+
m = m[0]+r"\cdot 10^{"+m[1]+"}"
96115
else:
97116
m = m[0]
98117
if len(u) > 1:
99-
u = u[0]+"\cdot 10^{"+u[1]+"}"
118+
u = u[0]+r"\cdot 10^{"+u[1]+"}"
100119
else:
101120
u = u[0]
102-
return("({0}\, \pm \,{1})".format(m, u))
121+
return(r"({0}\, \pm \,{1})".format(m, u))
103122

104123
def __str__(self):
105124
val = self.split()
@@ -110,6 +129,10 @@ def __str__(self):
110129

111130
def __repr__(self):
112131
return self.__str__()
132+
133+
def __getitem__(self, idx):
134+
vals = [self.mean,self.uncertainty]
135+
return vals[idx]
113136

114137
def __pos__(self):
115138
return self
@@ -170,7 +193,7 @@ def __ge__(self,other):
170193

171194
def __add__(self, other):
172195
if isinstance(other, labfloat):
173-
return labfloat(self.mean + other.mean, self.uncertainty + other.uncertainty)
196+
return labfloat(self.mean + other.mean, sqrt(self.uncertainty ** 2 + other.uncertainty ** 2))
174197
if isinstance(other, Number):
175198
return labfloat(self.mean + other, self.uncertainty)
176199

@@ -182,13 +205,13 @@ def __iadd__(self, other):
182205

183206
def __sub__(self, other):
184207
if isinstance(other, labfloat):
185-
return labfloat(self.mean - other.mean, self.uncertainty + other.uncertainty)
208+
return labfloat(self.mean - other.mean, sqrt(self.uncertainty ** 2 + other.uncertainty ** 2))
186209
if isinstance(other, Number):
187210
return labfloat(self.mean - other, self.uncertainty)
188211

189212
def __rsub__(self, other):
190213
if isinstance(other, labfloat):
191-
pass
214+
return labfloat(other.mean - self.mean, sqrt(other.uncertainty ** 2 + self.uncertainty ** 2))
192215
if isinstance(other, Number):
193216
return labfloat(other - self.mean, self.uncertainty)
194217

@@ -197,9 +220,9 @@ def __isub__(self, other):
197220

198221
def __mul__(self, other):
199222
if isinstance(other, labfloat):
200-
return labfloat(self.mean * other.mean, self.mean * other.uncertainty + other.mean * self.uncertainty)
223+
return labfloat(self.mean * other.mean, sqrt((other.mean * self.uncertainty) ** 2 + (self.mean * other.uncertainty) ** 2))
201224
if isinstance(other, Number):
202-
return labfloat(self.mean * other, other * self.uncertainty)
225+
return labfloat(self.mean * other, abs(other * self.uncertainty))
203226

204227
def __rmul__(self, other):
205228
return self.__mul__(other)
@@ -209,9 +232,9 @@ def __imul__(self, other):
209232

210233
def __div__(self, other):
211234
if isinstance(other, labfloat):
212-
return labfloat(self.mean / other.mean, (self.mean * other.uncertainty + other.mean * self.uncertainty)/other.mean**2)
235+
return labfloat(self.mean / other.mean, sqrt((self.uncertainty / other.mean) ** 2 + (self.mean * other.uncertainty / (other.mean ** 2)) ** 2 ))
213236
if isinstance(other, Number):
214-
return labfloat(self.mean / other, self.uncertainty / other)
237+
return labfloat(self.mean / other, abs(self.uncertainty / other))
215238

216239
def __truediv__(self, other):
217240
return self.__div__(other)
@@ -224,24 +247,24 @@ def __itruediv__(self, other):
224247

225248
def __rdiv__(self, other):
226249
if isinstance(other, labfloat):
227-
return labfloat(other.mean / self.mean, (other.mean * self.uncertainty + self.mean * other.uncertainty)/self.mean**2)
250+
return labfloat(other.mean / self.mean, sqrt((other.uncertainty / self.mean) ** 2 + (other.mean * self.uncertainty / (self.mean ** 2)) ** 2 ))
228251
if isinstance(other, Number):
229-
return labfloat(other / self.mean, other * self.uncertainty / self.mean ** 2)
252+
return labfloat(other / self.mean, abs(other * self.uncertainty / self.mean ** 2))
230253

231254
def __rtruediv__(self, other):
232255
return self.__rdiv__(other)
233256

234257
def __pow__(self, other):
235258
if isinstance(other, labfloat):
236-
raise LabFloatError(0)
259+
return labfloat(self.mean ** other.mean, sqrt((other.mean * self.mean ** (other.mean - 1) * self.uncertainty) ** 2 + (self.mean ** other.mean * log(abs(self.mean)) * other.uncertainty) ** 2))
237260
if isinstance(other, Number):
238-
return labfloat(self.mean ** other, other * self.mean ** (other-1) * self.uncertainty)
261+
return labfloat(self.mean ** other, abs(other * self.mean ** (other - 1) * self.uncertainty))
239262

240263
def __rpow__(self, other):
241264
if isinstance(other, labfloat):
242-
raise LabFloatError(0)
243-
if isinstance(other, (float, int, hex, oct, complex)):
244-
return labfloat(other ** self.mean, other ** self.mean * log(other) * self.uncertainty)
265+
return labfloat(other.mean ** self.mean, sqrt((self.mean * other.mean ** (self.mean - 1) * other.uncertainty) ** 2 + (other.mean ** self.mean * log(abs(other.mean)) * self.uncertainty) ** 2))
266+
if isinstance(other, Number):
267+
return labfloat(other ** self.mean, abs(other ** self.mean * log(abs(other)) * self.uncertainty))
245268

246269
def __ipow__(self, other):
247270
return self.__pow__(other)

0 commit comments

Comments
 (0)