1 """
2
3 Uncertainty propagation class, and log() and exp() functions.
4
5 Based on scalars or numpy vectors, this class allows you to store and
6 manipulate values+uncertainties, with propagation of gaussian error for
7 addition, subtraction, multiplication, division, power, exp() and log().
8
9 Storage properties are determined by the numbers used to set the value
10 and uncertainty. Be sure to use floating point uncertainty vectors
11 for inplace operations since numpy does not do automatic type conversion.
12 Normal operations can use mixed integer and floating point. In place
13 operations (a *= b, etc.) create at most one extra copy for each operation.
14 c = a*b by contrast uses four intermediate vectors, so shouldn't be used
15 for huge arrays.
16 """
17
18 from __future__ import division
19
20 import numpy
21 import err1d
22 from formatnum import format_uncertainty
23
24 __all__ = ['Uncertainty']
25
26
27
29
37 dx = property(_getdx,_setdx,doc="standard deviation")
38
39
42
43
54
55
56
83
84
94 - def __rpow__(self, other): return NotImplemented
95
96
134
135
139
140
141
148
157 return "Uncertainty(%s,%s)"%(str(self.x),str(self.variance))
158
159
161 - def __mod__(self, other): return NotImplemented
162 - def __divmod__(self, other): return NotImplemented
163 - def __mod__(self, other): return NotImplemented
164 - def __lshift__(self, other): return NotImplemented
165 - def __rshift__(self, other): return NotImplemented
166 - def __and__(self, other): return NotImplemented
167 - def __xor__(self, other): return NotImplemented
168 - def __or__(self, other): return NotImplemented
169
171 - def __rmod__(self, other): return NotImplemented
173 - def __rmod__(self, other): return NotImplemented
176 - def __rand__(self, other): return NotImplemented
177 - def __rxor__(self, other): return NotImplemented
178 - def __ror__(self, other): return NotImplemented
179
181 - def __imod__(self, other): return NotImplemented
183 - def __imod__(self, other): return NotImplemented
186 - def __iand__(self, other): return NotImplemented
187 - def __ixor__(self, other): return NotImplemented
188 - def __ior__(self, other): return NotImplemented
189
192 - def __int__(self): return NotImplmented
193 - def __long__(self): return NotImplmented
195 - def __oct__(self): return NotImplmented
196 - def __hex__(self): return NotImplmented
199
202
205
206 -def log(val): return self.log()
207 -def exp(val): return self.exp()
208
210 a = Uncertainty(5,3)
211 b = Uncertainty(4,2)
212
213
214 z = a+4
215 assert z.x == 5+4 and z.variance == 3
216 z = a-4
217 assert z.x == 5-4 and z.variance == 3
218 z = a*4
219 assert z.x == 5*4 and z.variance == 3*4**2
220 z = a/4
221 assert z.x == 5./4 and z.variance == 3./4**2
222
223
224 z = 4+a
225 assert z.x == 4+5 and z.variance == 3
226 z = 4-a
227 assert z.x == 4-5 and z.variance == 3
228 z = 4*a
229 assert z.x == 4*5 and z.variance == 3*4**2
230 z = 4/a
231 assert z.x == 4./5 and abs(z.variance - 3./5**4 * 4**2) < 1e-15
232
233
234 z = a**2
235 assert z.x == 5**2 and z.variance == 4*3*5**2
236 z = a**1
237 assert z.x == 5**1 and z.variance == 3
238 z = a**0
239 assert z.x == 5**0 and z.variance == 0
240 z = a**-1
241 assert z.x == 5**-1 and abs(z.variance - 3./5**4) < 1e-15
242
243
244 z = a+b
245 assert z.x == 5+4 and z.variance == 3+2
246 z = a-b
247 assert z.x == 5-4 and z.variance == 3+2
248 z = a*b
249 assert z.x == 5*4 and z.variance == (5**2*2 + 4**2*3)
250 z = a/b
251 assert z.x == 5./4 and abs(z.variance - (3./5**2 + 2./4**2)*(5./4)**2) < 1e-15
252
253
254
255 y = a+0; y += 4
256 z = a+4
257 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
258 y = a+0; y -= 4
259 z = a-4
260 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
261 y = a+0; y *= 4
262 z = a*4
263 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
264 y = a+0; y /= 4
265 z = a/4
266 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
267
268
269 y = a+0; y **= 4
270 z = a**4
271 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
272
273
274 y = a+0; y += b
275 z = a+b
276 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
277 y = a+0; y -= b
278 z = a-b
279 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
280 y = a+0; y *= b
281 z = a*b
282 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
283 y = a+0; y /= b
284 z = a/b
285 assert y.x == z.x and abs(y.variance-z.variance) < 1e-15
286
287
288
289
290 z = Uncertainty(numpy.array([1,2,3,4,5]),numpy.array([2,1,2,3,2]))
291 assert z[2].x == 3 and z[2].variance == 2
292 assert (z[2:4].x == [3,4]).all()
293 assert (z[2:4].variance == [2,3]).all()
294 z[2:4] = Uncertainty(numpy.array([8,7]),numpy.array([4,5]))
295 assert z[2].x == 8 and z[2].variance == 4
296 A = Uncertainty(numpy.array([a.x]*2),numpy.array([a.variance]*2))
297 B = Uncertainty(numpy.array([b.x]*2),numpy.array([b.variance]*2))
298
299
300
301
302 z = A+B
303 assert (z.x == 5+4).all() and (z.variance == 3+2).all()
304 z = A-B
305 assert (z.x == 5-4).all() and (z.variance == 3+2).all()
306 z = A*B
307 assert (z.x == 5*4).all() and (z.variance == (5**2*2 + 4**2*3)).all()
308 z = A/B
309 assert (z.x == 5./4).all()
310 assert (abs(z.variance - (3./5**2 + 2./4**2)*(5./4)**2) < 1e-15).all()
311
312
313 assert str(Uncertainty(5,3)) == "5.0(17)"
314 assert str(Uncertainty(15,3)) == "15.0(17)"
315 assert str(Uncertainty(151.23356,0.324185**2)) == "151.23(32)"
316
317 if __name__ == "__main__": test()
318