Source code for tf_pwa.err_num

import numpy as np

from .utils import error_print


[docs] class NumberError(object): """basic class for propagation of error""" def __init__(self, value, error=1.0): self._value = value self._error = error def __repr__(self): return error_print(self._value, self._error) @property def value(self): return self._value @property def error(self): return self._error def __add__(self, other): if isinstance(other, NumberError): val = self._value + other._value err = np.sqrt(self._error**2 + other._error**2) else: val = self._value + other err = self._error return NumberError(val, err) def __sub__(self, other): if isinstance(other, NumberError): val = self._value - other._value err = np.sqrt(self._error**2 + other._error**2) else: val = self._value - other err = self._error return NumberError(val, err) def __neg__(self): val = -self._value err = self._error return NumberError(val, err) def __mul__(self, other): if isinstance(other, NumberError): val = self._value * other._value err = np.sqrt( (self._error * other._value) ** 2 + (self._value * other._error) ** 2 ) else: val = self._value * other err = self._error * other return NumberError(val, err) def __truediv__(self, other): if isinstance(other, NumberError): val = self._value / other._value err = ( np.sqrt( (self._error) ** 2 + (self._value * other._error / other._value) ** 2 ) / other._value ) else: val = self._value / other err = self._error / other return NumberError(val, err) def __pow__(self, other): if isinstance(other, NumberError): val = self._value**other._value err1 = ( other._value * self._value ** (other._value - 1) * self._error ) err2 = np.log(other._value) * val * other._error err = np.sqrt(err1**2 + err2**2) else: val = self._value**other err = np.abs(other * self._value ** (other - 1)) * self._error return NumberError(val, err) def __rpow__(self, other): val = other**self._value err = np.log(self._value) * val * self._error return NumberError(val, err)
[docs] def log(self): val = np.log(self._value) err = self._error / np.abs(self._value) return NumberError(val, err)
[docs] def exp(self): val = np.exp(self._value) err = val * self._error return NumberError(val, err)
[docs] def apply(self, fun, grad=None, dx=1e-5): val = fun(self._value) if grad is not None: err = np.abs(grad(self._value)) * self._error else: grad_v = (fun(self._value + dx) - fun(self._value - dx)) / 2 / dx err = np.abs(grad_v) * self._error return NumberError(val, err)
[docs] def cal_err(fun, *args, grad=None, dx=1e-5, kwargs=None): kwargs = {} if kwargs is None else kwargs value = [] errs = [] for i in args: if isinstance(i, NumberError): value.append(i._value) errs.append(i._error) else: value.append(i) errs.append(0.0) val = fun(*value, **kwargs) if grad is None: grad_v = [] for i, k in enumerate(value): value[i] += dx val_p = fun(*value, **kwargs) value[i] -= 2 * dx val_m = fun(*value, **kwargs) value[i] = k grad_v.append((val_p - val_m) / 2 / dx) else: grad_v = grad(*value, **kwargs) err = np.sqrt(sum((i * j) ** 2 for i, j in zip(grad_v, errs))) return NumberError(val, err)