Source code for scuq.ucomponents

## \file ucomponents.py
# \brief This file contains the module to model uncertain values.
#  \author <a href="http://thomas.reidemeister.org/" target="_blank">
#          Thomas Reidemeister</a>

## \namespace scuq::ucomponents
# \brief This namespace contains the classes to evaluate the
#        uncertainty of scalar functions.

## \defgroup ucomponents The Uncertainty Module
#
# This module contains classes to model uncertain values.
# \author <a href="http://thomas.reidemeister.org/" target="_blank">
#         Thomas Reidemeister</a>
# \addtogroup ucomponents
# @{

# Example for Uncertain Quantities
## This example shows how uncertain values can be used as quantities.
# Instead of encapsulating instances of <tt>quantities.Quantity</tt>
# inside an instance of <tt>ucomponents.UncertainInput</tt>, you should
# always encapsulate uncertain values inside quantities. Otherwise
# this will lead to unpredicable behavior.
# \see quantities The quantities module.
# \see ucomponents The module to evaluate the uncertainty of
#      scalar models.
# \see cucomponents The module to evalute the uncertainty of
#      complex-valued models
# \author Thomas Reidemeister
# \example UncertainQuantity.py

# standard modules
import numpy

# import operator
import contextlib
import numbers
import types
import warnings

# local modules
import scuq.arithmetic as arithmetic
import scuq.quantities as quantities
import scuq.units as units
import scuq.cucomponents as cucomponents


def _require_numeric(value, name="value", allow_rational=True):
    types = (numbers.Number, arithmetic.RationalNumber) if allow_rational else numbers.Number
    if not isinstance(value, types):
        raise TypeError("%s must be numeric" % name)


def _reject_uncertain_or_quantity(value, name="value"):
    if isinstance(value, UncertainComponent):
        raise TypeError("%s must not be an UncertainComponent" % name)
    if isinstance(value, quantities.Quantity):
        raise TypeError("%s must not be a Quantity" % name)


def _require_component_operand(value, name="other"):
    if not isinstance(value, (UncertainComponent, numbers.Number, arithmetic.RationalNumber)):
        raise TypeError("%s must be an UncertainComponent or numeric value" % name)


def _require_context(value, name="context"):
    if not isinstance(value, Context):
        raise TypeError("%s must be a Context" % name)


def _require_uncertain_input(value, name="value"):
    if not isinstance(value, UncertainInput):
        raise TypeError("%s must be an UncertainInput" % name)


def _require_uncertain_component(value, name="component"):
    if not isinstance(value, UncertainComponent):
        raise TypeError("%s must be an UncertainComponent" % name)


def _deprecated_python2_method(name, replacement):
    warnings.warn(
        "%s is deprecated and kept only for Python 2 compatibility; use %s instead"
        % (name, replacement),
        DeprecationWarning,
        stacklevel=2,
    )


[docs] def coerce(x, y): t = type(x + y) return (t(x), t(y))
[docs] def clearDuplicates(alist): """Remove identical elements from a list :param alist: A list that may contain identical elements. :returns: A list that only contains unique elements. """ result = [] for newItem in alist: contained = False for oldItem in result: if oldItem is newItem: contained = True break if not contained: result += [newItem] return result
def _collect_component_tree(component): """Collect all uncertainty tree nodes reachable from *component*.""" nodes = [] seen = set() stack = [component] while stack: node = stack.pop() node_id = id(node) if node_id in seen or not isinstance(node, UncertainComponent): continue seen.add(node_id) nodes.append(node) left = getattr(node, "_left", None) right = getattr(node, "_right", None) if left is not None: stack.append(left) if right is not None: stack.append(right) return nodes @contextlib.contextmanager def _cached_component_evaluation(component): """Temporarily cache tree-node values and partial uncertainties. The cache is scoped to one uncertainty evaluation and is removed before the caller regains control. """ value_cache = {} uncertainty_cache = {} originals = [] def make_value_wrapper(original): def get_value(self): key = id(self) if key in value_cache: return value_cache[key] value = original() value_cache[key] = value return value return get_value def make_uncertainty_wrapper(original): def get_uncertainty(self, partial): key = (id(self), id(partial)) if key in uncertainty_cache: return uncertainty_cache[key] value = original(partial) uncertainty_cache[key] = value return value return get_uncertainty try: for node in _collect_component_tree(component): had_get_value = "get_value" in node.__dict__ had_get_uncertainty = "get_uncertainty" in node.__dict__ originals.append( ( node, had_get_value, getattr(node, "get_value", None), had_get_uncertainty, getattr(node, "get_uncertainty", None), ) ) node.get_value = types.MethodType( make_value_wrapper(node.get_value), node ) node.get_uncertainty = types.MethodType( make_uncertainty_wrapper(node.get_uncertainty), node ) yield finally: for node, had_get_value, get_value, had_get_uncertainty, get_uncertainty in originals: if had_get_value: node.get_value = get_value else: try: del node.get_value except AttributeError: pass if had_get_uncertainty: node.get_uncertainty = get_uncertainty else: try: del node.get_uncertainty except AttributeError: pass
[docs] class UncertainComponent: """This is the abstract base class to model components of uncertainty as described in by "The GUM Tree". measurement uncertainty"; B. D. Hall; Industrial Research Report 1291; Measurements Standards Laboratory New Zealand (2003). """
[docs] def __init__(self): """Default constructor.""" raise NotImplementedError
[docs] def arithmetic_check(self): """This method checks this instance for mathematical correctness. You should overload this method, if your class is not defined for specific argument values. If any (mathematical) invalid values have been assigned, your implementation should raise an ArithmeticError explaining the problem. This method is usually called within the constructor of a class, after the members have been initialized. """ # if not overriden, assume all arguements are possible return True
[docs] def get_value(self): """Abstract method: The implementation should return a numeric value (e.g. float,int,long,or arithmetic.RationalNumber) representing the value assigned to the component of uncertainty. :returns: A numeric value, representing the value. """ raise NotImplementedError
[docs] def get_uncertainty(self, component): """Abstract method: The implementation should return a numeric value (e.g. float,int,long,or arithmetic.RationalNumber) representing the standard uncertainty of this component. :param component: Another instance of uncertainty. If the argument is this instance the uncertainty is returned, \frac{0}{1} should be returned otherwise. This is analogous to taking the derivate of an independent variable. For further explanation see "The GUM tree". :returns: A numeric value, representing the standard uncertainty. measurement uncertainty"; B. D. Hall; Industrial Research Report 1291; Measurements Standards Laboratory New Zealand (2003). """ raise NotImplementedError
[docs] def depends_on(self): """Abstract method: The implementation should return a list of the components of uncertainty, that this component depends on. :returns: A list of the components of uncertainty. """ raise NotImplementedError
[docs] def __getstate__(self): """Serialization using pickle. :returns: A string that represents the serialized form of this instance. """ raise NotImplementedError
[docs] def __setstate__(self, state): """Deserialization using pickle. :param state: The state of the object. """ raise NotImplementedError
[docs] def value_of(value): """A factory method, that can be used to create instances of uncertain components. This method returns instances of UncertainNumber depending on the argument. :param value: An instance of UncertainNumber or a numeric value. :returns: The argument, if it is already an instance of UncertainNumber, or a new instance of UncertainInput (having an uncertainty of 0.0) if the argument is a numeric value (i.e. int,float...). encapsulate quantites in UncertainValues. Plase use Quantity(UncertainValue) instead. """ # do not encapsulate uncertain components if isinstance(value, UncertainComponent): return value # do not encapsulate quantities if isinstance(value, quantities.Quantity): raise TypeError( "You cannot encapsulate quantities in" + " Uncertain components;" + " Use Quantity(UncertainValue) instead" ) # if a numeric input is given, # assume it is an uncertain input _require_numeric(value) return UncertainInput(value, 0.0)
value_of = staticmethod(value_of)
[docs] def gaussian(value, sigma, dof=arithmetic.INFINITY): """A factory method, that can be used to create instances of uncertain components. This method returns uncertain inputs that are quantified as a gaussian distribution, centered at value, and having the uncertainty sigma. :param value: A numeric value, representing x. :param sigma: A numeric value, representing a :param dof: The assigned number of degrees of freedom. :returns: An uncertain component. """ _reject_uncertain_or_quantity(value) _reject_uncertain_or_quantity(sigma, "sigma") _require_numeric(value, allow_rational=False) _require_numeric(sigma, "sigma", allow_rational=False) return UncertainInput(value, sigma, dof)
gaussian = staticmethod(gaussian)
[docs] def uniform(value, halfwidth, dof=arithmetic.INFINITY): """A factory method, that can be used to create instances of uncertain components. This method returns uncertain inputs that are quantified as a uniform distribution, centered at x, and having the half-width a. :param value: A numeric value, representing x. :param halfwidth: A numeric value, representing a. :param dof: The assigned number of degrees of freedom. :returns: An uncertain component, having the uncertainty """ _reject_uncertain_or_quantity(value) _reject_uncertain_or_quantity(halfwidth, "halfwidth") _require_numeric(value, allow_rational=False) _require_numeric(halfwidth, "halfwidth", allow_rational=False) uncertainty = halfwidth / numpy.sqrt(3.0) return UncertainInput(value, uncertainty, dof)
uniform = staticmethod(uniform)
[docs] def triangular(value, halfwidth, dof=arithmetic.INFINITY): """A factory method, that can be used to create instances of uncertain components. This method returns uncertain inputs that are quantified as a triangular distribution, centered at x, and having the half-width a. :param value: A numeric value, representing x. :param halfwidth: A numeric value, representing a :param dof: The assigned number of degrees of freedom. :returns: An uncertain component, having the uncertainty """ _reject_uncertain_or_quantity(value) _reject_uncertain_or_quantity(halfwidth, "halfwidth") _require_numeric(value, allow_rational=False) _require_numeric(halfwidth, "halfwidth", allow_rational=False) uncertainty = halfwidth / numpy.sqrt(6.0) return UncertainInput(value, uncertainty, dof)
triangular = staticmethod(triangular)
[docs] def beta(value, p, q, dof=arithmetic.INFINITY): """A factory method, that can be used to create instances of uncertain components. This method returns uncertain inputs that are quantified as a beta distribution, having the parameters p and q . :param value: The assigned value. :param p: A numeric value, representing p. :param q: A numeric value, representing q :param dof: The assigned number of degrees of freedom. :returns: An uncertain component. """ _reject_uncertain_or_quantity(p, "p") _reject_uncertain_or_quantity(value) _reject_uncertain_or_quantity(q, "q") _require_numeric(p, "p", allow_rational=False) _require_numeric(value, allow_rational=False) _require_numeric(q, "q", allow_rational=False) uncertainty = numpy.sqrt(p * q / ((p + q) ** 2.0 * (p + q + 1.0))) return UncertainInput(value, uncertainty, dof)
beta = staticmethod(beta)
[docs] def arcsine(value, dof=arithmetic.INFINITY): """A factory method, that can be used to create instances of uncertain components. This method returns uncertain inputs that are quantified as an arcsin distribution. :returns: An uncertain component. """ _reject_uncertain_or_quantity(value) _require_numeric(value, allow_rational=False) return UncertainComponent.beta(value, 0.5, 0.5, dof)
arcsine = staticmethod(arcsine)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has equal attributes as the argument """ raise NotImplementedError
### Emulation of numeric behaviour
[docs] def __eq__(self, other): r"""This method is an alias for (self is other). It checks if the argument is identical with the current instance. Imagine you want to compare with sin(a \pm u_a) \times (b \pm u_b) with Since in the first case the values are identical, they are dependent. In the second case the values are the same, but we do not know about their independence. Therefore the second case needs a different handling. In order not to confuse these two cases, this method has to check for identity. :param other: Another instance of UncertainComponent :returns: True, if the argument is identical to the current instance. """ return self is other
[docs] def __ne__(self, other): """This method is an alias for not(self is other). It checks if the argument is not identical with the current instance. :param other: Another instance of UncertainComponent :returns: True, if the argument is not identical to the current instance. """ return not (self is other)
def __cmp__(self, other): _deprecated_python2_method("__cmp__", "the rich comparison operators") def cmp(a, b): return (a > b) - (a < b) sval = self.get_value() try: oval = other.get_value() except AttributeError: oval = other return cmp(sval, oval) def __lt__(self, other): sval = self.get_value() try: oval = other.get_value() except AttributeError: oval = other return sval < oval def __le__(self, other): sval = self.get_value() try: oval = other.get_value() except AttributeError: oval = other return sval <= oval def __gt__(self, other): sval = self.get_value() try: oval = other.get_value() except AttributeError: oval = other return sval > oval def __ge__(self, other): sval = self.get_value() try: oval = other.get_value() except AttributeError: oval = other return sval >= oval
[docs] def __add__(self, other): """This method adds the argument to this instance. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Add(self, other)
[docs] def arctan2(self, other): """This method provides an interface for numpy.arctan2. :param other: A numeric value. """ if not isinstance(other, UncertainComponent): tmp, other = coerce(self, other) return numpy.arctan2(tmp, other) return ArcTan2(self, other)
[docs] def hypot(self, other): """This method provides an interface for numpy.hypot. :param other: A numeric value. """ if not isinstance(other, UncertainComponent): tmp, other = coerce(self, other) return numpy.hypot(tmp, other) return numpy.sqrt(self * self + other * other)
[docs] def __sub__(self, other): """This method substracts the argument from this instance. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Sub(self, other)
[docs] def __mul__(self, other): """This method multiplies the argument by this instance. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Mul(self, other)
[docs] def __truediv__(self, other): """This method divides this instance by the argument. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Div(self, other)
[docs] def __pow__(self, other): """This method raises this to the power of the argument. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Pow(self, other)
[docs] def __radd__(self, other): """This method adds this instance to the argument. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Add(other, self)
[docs] def __rsub__(self, other): """This method substracts this instance from the argument. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Sub(other, self)
[docs] def __rmul__(self, other): """This method multiplies the argument by this instance. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Mul(other, self)
[docs] def __rtruediv__(self, other): """This method divides the argument by this instance. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Div(other, self)
[docs] def __rpow__(self, other): """This method raises the argument to the power of this instance. it will be converted using UncertainComponent.value_of. :param other: A numeric value. """ _require_component_operand(other) return Pow(other, self)
[docs] def __neg__(self): """This method negates this instance.""" return Neg(self)
[docs] def __invert__(self): """Inverts this instance.""" return 1.0 / self
[docs] def __abs__(self): """This method returs the absolute value of this instance.""" return Abs(self)
[docs] def set_context(self, context): """Assign a context to this component. This method is only used in combination with __str__. If a context is assigned to the instance, the correlation coefficients will be considered for __str__. Otherwise __str__ assumes that there is no correlation among the inputs. :param context: An instance of Context. """ self._context = context
[docs] def eval(self): """Factory method to get get an object with evaluated uncertainties. :returns: object with <value> and <uncertainty> """ context = None try: context = self._context except AttributeError: context = Context() _require_context(context) uncert = context.uncertainty(self) value = self.get_value() return UncertainInput(value, uncert)
[docs] def __str__(self): """This method returs the absolute value of this instance. :returns: A string of the form "<value> +- <uncertainty>" or "<value> +- <uncertainty> [NC]", if no context was provided. """ bnc = False context = None try: context = self._context except AttributeError: context = Context() bnc = len(self.depends_on()) > 1 _require_context(context) uncert = context.uncertainty(self) value = self.get_value() if bnc: return str(value) + " +/- " + str(uncert) + " [NC]" else: return str(value) + " +/- " + str(uncert)
### Numpy compliance
[docs] def arccos(self): """This method provides the broadcast interface for numpy.arccos. :returns: The inverse Cosine of this component. """ return ArcCos(self)
[docs] def arccosh(self): """This method provides the broadcast interface for numpy.arccosh. :returns: The inverse hyperbolic Cosine of this component. """ return ArcCosh(self)
[docs] def arcsin(self): """This method provides the broadcast interface for numpy.arcsin. :returns: The inverse Sine of this component. """ return ArcSin(self)
[docs] def arcsinh(self): """This method provides the broadcast interface for numpy.arcsinh. :returns: The inverse hyperbolic Sine of this component. """ return ArcSinh(self)
[docs] def arctan(self): """This method provides the broadcast interface for numpy.arctan. :returns: The inverse Tangent of this component. """ return ArcTan(self)
[docs] def arctanh(self): """This method provides the broadcast interface for numpy.arctanh. :returns: The inverse hyperbolic Tangent of this component. """ return ArcTanh(self)
[docs] def cos(self): """This method provides the broadcast interface for numpy.cos. :returns: The Cosine of this component. """ return Cos(self)
[docs] def cosh(self): """This method provides the broadcast interface for numpy.cosh. :returns: The hyperbolic Cosine of this component. """ return Cosh(self)
[docs] def tan(self): """This method provides the broadcast interface for numpy.tan. :returns: The Tangent of this component. """ return Tan(self)
[docs] def tanh(self): """This method provides the broadcast interface for numpy.tanh. :returns: The hyperbolic Tangent of this component. """ return Tanh(self)
[docs] def log10(self): """This method provides the broadcast interface for numpy.log10. :returns: The decadic Logarithm of this component. """ return Log(self) / Log(10.0)
[docs] def log2(self): """This method provides the broadcast interface for numpy.log2. :returns: The decadic Logarithm of this component. """ return Log(self) / Log(2.0)
[docs] def sin(self): """This method provides the broadcast interface for numpy.sin. :returns: The Sine of this component. """ return Sin(self)
[docs] def sinh(self): """This method provides the broadcast interface for numpy.sinh. :returns: The hyperbolic Sine of this component. """ return Sinh(self)
[docs] def sqrt(self): """This method provides the broadcast interface for numpy.sqrt. :returns: The Square Root of this component. """ return Sqrt(self)
[docs] def square(self): """This method provides the broadcast interface for numpy.sqrt. :returns: The Square Root of this component. """ return self * self
[docs] def fabs(self): """This method provides the broadcast interface for numpy.fabs. :returns: The absolute value of this component. """ return Abs(self)
[docs] def absolute(self): """This method provides the broadcast interface for numpy.absolute. :returns: The absolute value of this component. """ return Abs(self)
[docs] def exp(self): """This method provides the broadcast interface for numpy.exp. :returns: The Exponential of this component. """ return Exp(self)
[docs] def log(self): """This method provides the broadcast interface for numpy.log. :returns: The Natural Logarithm of this component. """ return Log(self)
[docs] def __coerce__(self, other): """Implementation of coercion rules. See also: Coercion - The page describing the coercion rules. """ _deprecated_python2_method("__coerce__", "explicit conversion") if isinstance(other, UncertainComponent): return (self, other) elif isinstance(other, quantities.Quantity): new_self = quantities.Quantity.value_of(self) return (new_self, other) elif isinstance(other, cucomponents.CUncertainComponent): raise NotImplementedError( "You must not mix scalar and" + " complex-valued uncertain values" ) elif ( isinstance(other, arithmetic.RationalNumber) or isinstance(other, int) or isinstance(other, int) or isinstance(other, float) ): other = UncertainComponent.value_of(other) return (self, other) elif isinstance(other, complex): raise NotImplementedError( "Please use the module cucomponents" + " to evaluate the uncertainty of complex" + "-valued quantities" ) elif isinstance(other, units.Unit): raise NotImplementedError( "You cannot declare a unit as uncertain." + " Please use the quantities module" + " for that!" ) else: raise NotImplementedError()
[docs] class UncertainInput(UncertainComponent): """This class provides the model for uncertain inputs, that are referred to as "Leafs" in "The GUM tree". measurement uncertainty"; B. D. Hall; Industrial Research Report 1291; Measurements Standards Laboratory New Zealand (2003). """ _value = 0.0 _uncertainty = 0.0 _dof = 0.0
[docs] def __init__(self, value, uncertainty, dof=arithmetic.INFINITY): """Default constructor. UncertainComponent nor quantities.Quantity. Create quantities, having an UncertainInput as numeric argument instead. :param value: The numeric value of the input. :param dof: The assigned component of degrees of freedom. :param uncertainty: The standard uncertainty of the input. """ _reject_uncertain_or_quantity(value) _reject_uncertain_or_quantity(uncertainty, "uncertainty") _reject_uncertain_or_quantity(dof, "dof") _require_numeric(value) _require_numeric(uncertainty, "uncertainty") if not isinstance(dof, numbers.Number) and dof != arithmetic.INFINITY: raise TypeError("dof must be numeric or arithmetic.INFINITY") self._value = value self._uncertainty = uncertainty self._dof = dof
[docs] def get_value(self): """Returns the assigned value. :returns: A numeric value, representing the value. """ return self._value
[docs] def get_dof(self): """Returns the assigned degrees of freedom. :returns: A numeric value or arithmetic.INFINITY, representing the value. """ return self._dof
[docs] def conjugate(self): return self._value
[docs] def get_uncertainty(self, component): """Returns the assigned uncertainty. :param component: Another component of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ if self is component: return self._uncertainty return 0.0
[docs] def depends_on(self): """Returns a list containing this element. :returns: A list of the components of uncertainty. """ return [self]
def __ceil__(self): return numpy.ceil(self._value + self._uncertainty) def __floor__(self): return numpy.ceil(self._value - self._uncertainty)
[docs] def __getstate__(self): """Serialization using pickle. :returns: A string that represents the serialized form of this instance. """ return (self._value, self._uncertainty, self._dof)
[docs] def __setstate__(self, state): """Deserialization using pickle. :param state: The state of the object. """ self._value, self._uncertainty, self._dof = state
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, UncertainInput): return False return ( self._value == other._value and self._uncertainty == other._uncertainty and self._dof == other._dof )
[docs] def __hash__(self): """Hash this instance.""" return 1
[docs] class BinaryOperation(UncertainComponent): """The abstract base class for modelling binary operations. This class provides the abstract interface for GUM-tree-nodes that have two silblings. """ ## The right silbling of the operation. _right = None ## The left silbling of the operation. _left = None
[docs] def __init__(self, left, right): """Default constructor. constructor explicitly in order to initialize the silblings! :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ if left is None: raise ValueError("left must not be None") if right is None: raise ValueError("right must not be None") self._right = UncertainComponent.value_of(right) self._left = UncertainComponent.value_of(left)
[docs] def depends_on(self): """Get the components of uncertainty, that this class depends on. :returns: A list of the components of uncertainty. """ list = self._left.depends_on() list += self._right.depends_on() return clearDuplicates(list)
[docs] def get_right(self): """Return the right silbling. :returns: The right silbling. """ return self._right
[docs] def get_left(self): """Return the left silbling. :returns: The left silbling. """ return self._left
[docs] def __getstate__(self): """Serialization using pickle. :returns: A string that represents the serialized form of this instance. """ return (self._left, self._right)
[docs] def __setstate__(self, state): """Deserialization using pickle. :param state: The state of the object. """ self._left, self._right = state
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, BinaryOperation): return False return self._right.equal_debug(other._right) and self._left.equal_debug( other._left )
[docs] class UnaryOperation(UncertainComponent): """The abstract base class for modelling unary operations. This class provides the abstract interface for GUM-tree-nodes that have one silbling. """ ## The silbling of the operation. _right = None
[docs] def __init__(self, right): """Default constructor. :param right: The silbling of this instance. """ if right is None: raise ValueError("right must not be None") self._right = UncertainComponent.value_of(right)
[docs] def depends_on(self): """Abstract method: The implementation should return a list of the components of uncertainty, that this component depends on. :returns: A list of the components of uncertainty. """ return clearDuplicates(self._right.depends_on())
[docs] def get_silbling(self): """Return the silbling. :returns: The silbling. """ return self._right
[docs] def __getstate__(self): """Serialization using pickle. :returns: A string that represents the serialized form of this instance. """ return self._right
[docs] def __setstate__(self, state): """Deserialization using pickle. :param state: The state of the object. """ self._right = state
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, UnaryOperation): return False return self._right.equal_debug(other._right)
[docs] class Add(BinaryOperation): """This class models GUM-tree nodes that add two silblings."""
[docs] def __init__(self, left, right): """Default constructor. :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ BinaryOperation.__init__(self, left, right)
[docs] def get_value(self): """Returns the sum of the silblings assigned. :returns: A numeric value, representing the sum of the silblings. """ return self.get_left().get_value() + self.get_right().get_value()
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = x_1 + x_2 then the resulting uncertainty is u(y) = u(x_1) + u(x_2) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ return self.get_left().get_uncertainty( component ) + self.get_right().get_uncertainty(component)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Add): return False return BinaryOperation.equal_debug(self, other)
[docs] class ArcTan2(BinaryOperation): """This class models the inverse two-argument tangent."""
[docs] def __init__(self, left, right): """Default constructor. :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ BinaryOperation.__init__(self, left, right)
[docs] def get_value(self): """Returns the sum of the silblings assigned. :returns: A numeric value, representing the inverse two-argument tangent of the inputs. """ return numpy.arctan2(self.get_left().get_value(), self.get_right().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = x_1 + x_2 then the resulting uncertainty is u(y) = u(x_1) + u(x_2) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ lhs = self.get_left().get_uncertainty(component) rhs = self.get_right().get_uncertainty(component) lhs_val = self.get_left().get_value() rhs_val = self.get_right().get_value() return ( -rhs_val / (lhs_val**2 + rhs_val**2) * lhs + lhs_val / (lhs_val**2 + rhs_val**2) * rhs )
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcTan2): return False return BinaryOperation.equal_debug(self, other)
[docs] class Mul(BinaryOperation): """This class models GUM-tree nodes that multiply two silblings."""
[docs] def __init__(self, left, right): """Default constructor. :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ BinaryOperation.__init__(self, left, right)
[docs] def get_value(self): """Returns the product of the silblings assigned. :returns: A numeric value, representing the product of the silblings. """ return self.get_left().get_value() * self.get_right().get_value()
[docs] def get_uncertainty(self, component): r"""Returns the uncertainty of this node. Let the node represent the operation y = x_1 \times x_2 then the resulting uncertainty is :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ return self.get_right().get_value() * self.get_left().get_uncertainty( component ) + self.get_left().get_value() * self.get_right().get_uncertainty(component)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Mul): return False return BinaryOperation.equal_debug(self, other)
[docs] class Div(BinaryOperation): """This class models GUM-tree nodes that divide two silblings."""
[docs] def __init__(self, left, right): """Default constructor. :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ BinaryOperation.__init__(self, left, right) self.arithmetic_check()
[docs] def arithmetic_check(self): """Checks for divide by zero. as value. """ if self.get_right().get_value() == 0.0: raise ArithmeticError("Divide by Zero")
[docs] def get_value(self): """Returns the fraction of the silblings assigned. :returns: A numeric value, representing the fraction of the silblings. """ return self.get_left().get_value() / self.get_right().get_value()
[docs] def get_uncertainty(self, component): r"""Returns the uncertainty of this node. Let the node represent the operation y = \frac{x_1}{x_2} then the resulting uncertainty is :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x_1 = self.get_left().get_uncertainty(component) u_x_2 = self.get_right().get_uncertainty(component) x_1 = self.get_left().get_value() x_2 = self.get_right().get_value() return u_x_1 / x_2 - u_x_2 * x_1 / (x_2 * x_2)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Div): return False return BinaryOperation.equal_debug(self, other)
[docs] class Sub(BinaryOperation): """This class models GUM-tree nodes that take the difference of the two silblings. """
[docs] def __init__(self, left, right): """Default constructor. :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ BinaryOperation.__init__(self, left, right)
[docs] def get_value(self): """Returns the difference of the silblings assigned. :returns: A numeric value, representing the difference of the silblings. """ return self.get_left().get_value() - self.get_right().get_value()
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = x_1 - x_2 then the resulting uncertainty is u(y) = u(x_1) - u(x_2) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x_1 = self.get_left().get_uncertainty(component) u_x_2 = self.get_right().get_uncertainty(component) return u_x_1 - u_x_2
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Sub): return False return BinaryOperation.equal_debug(self, other)
[docs] class Pow(BinaryOperation): """This class models GUM-tree nodes that raise the left silbling to the power of the right one. """
[docs] def __init__(self, left, right): """Default constructor. :param left: Left silbling of this instance. :param right: Right silbling of this instance. """ BinaryOperation.__init__(self, left, right)
[docs] def get_value(self): """Returns the power pow(left,right) of the silblings assigned. :returns: A numeric value, representing the power of the silblings. """ return self.get_left().get_value() ** self.get_right().get_value()
[docs] def get_uncertainty(self, component): r"""Returns the uncertainty of this node. Let the node represent the operation :: y = x_1^{x_2} then the resulting uncertainty is :: u(y) = x_2 \times x_1^{x_2-1} \times u(x_1) + x_1^{x_2} \times ln(x_1) \times u(x_2) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x_1 = self.get_left().get_uncertainty(component) u_x_2 = self.get_right().get_uncertainty(component) x_1 = self.get_left().get_value() x_2 = self.get_right().get_value() if x_1 == 0.0 and x_2 < 1.0: raise ArithmeticError( "The uncertainty of a power is not defined for zero base " "and exponent smaller than one" ) if abs(u_x_2) <= 1e-12: return x_2 * numpy.power(x_1, (x_2 - 1.0)) * u_x_1 if x_1 <= 0.0: raise ArithmeticError( "The uncertainty of a power with uncertain exponent requires " "a positive base" ) return (x_2 * numpy.power(x_1, (x_2 - 1.0)) * u_x_1 + numpy.power(x_1, x_2) * u_x_2 * numpy.log(x_1))
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Pow): return False return BinaryOperation.equal_debug(self, other)
[docs] class Cos(UnaryOperation): """This class models the GUM-tree-nodes that take the Cosine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the Cosine of the silbling. :returns: A numeric value, representing the Cosine of the silblings. """ return numpy.cos(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = cos(x) then the resulting uncertainty is u(y) = -sin(x) \times u(x) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return -numpy.sin(x) * u_x
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Cos): return False return UnaryOperation.equal_debug(self, other)
[docs] class Sin(UnaryOperation): """This class models the GUM-tree-nodes that take the Sine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the Sine of the silbling. :returns: A numeric value, representing the Sine of the silblings. """ return numpy.sin(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = sin(x) then the resulting uncertainty is u(y) = cos(x) \times u(x) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return numpy.cos(x) * u_x
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Sin): return False return UnaryOperation.equal_debug(self, other)
[docs] class Tan(UnaryOperation): r"""This class models the GUM-tree-nodes that take the Tangent of a silbling. this class may return invalid values instead of raising an OverflowError for values close to n\times\frac{\pi}{2}. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right) self.arithmetic_check()
[docs] def get_value(self): """Returns the Tangent of the silbling. :returns: A numeric value, representing the Tangent of the silblings. """ return numpy.tan(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = tan(x) then the resulting uncertainty is u(y) = \frac{u(x)}{cos^2(x)}. :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x / (numpy.cos(x) * numpy.cos(x))
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Tan): return False return UnaryOperation.equal_debug(self, other)
[docs] class Sqrt(UnaryOperation): """This class models the GUM-tree-nodes that take the square root of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
# self.arithmetic_check()
[docs] def arithmetic_check(self): """Checks for undefined arguments.""" if self.get_silbling().get_value() < 0.0: raise ArithmeticError("The argument must be positive")
[docs] def get_value(self): """Returns the square root of the silbling. :returns: A numeric value, representing the square root of the silblings. """ return numpy.sqrt(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): r"""Returns the uncertainty of this node. Let the node represent the operation y = \sqrt{x} then the resulting uncertainty is u(y) = \frac{1}{2\sqrt{x}}u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return 0.5 / numpy.sqrt(x) * u_x
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Sqrt): return False return UnaryOperation.equal_debug(self, other)
[docs] class Log(UnaryOperation): """This class models the GUM-tree-nodes that take the Natural Logarithm of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right) self.arithmetic_check()
[docs] def arithmetic_check(self): """Checks for undefined arguments.""" if self.get_silbling().get_value() < 0.0: raise ArithmeticError("The argument must be positive")
[docs] def get_value(self): """Returns the Natural Logarithm of the silbling. :returns: A numeric value, representing the Natural Logarithm of the silblings. """ return numpy.log(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = ln(x) then the resulting uncertainty is u(y) = \frac{1}{x}u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() if not isinstance(x, float): return arithmetic.RationalNumber(1) / x * u_x return u_x / x
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Log): return False return UnaryOperation.equal_debug(self, other)
[docs] class ArcSin(UnaryOperation): """This class models the GUM-tree-nodes that take the Arc Sine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right) self.arithmetic_check()
[docs] def arithmetic_check(self): """Checks for undefined arguments.""" value = self.get_silbling().get_value() if value < -1.0 or value > 1.0: raise ArithmeticError("The argument must be within [-1,1]")
[docs] def get_value(self): """Returns the Arc Sine of the silbling. :returns: A numeric value, representing the Arc Sine of the silblings. """ return numpy.arcsin(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): r"""Returns the uncertainty of this node. Let the node represent the operation y = arcsin(x) then the resulting uncertainty is u(y) = \frac{1}{\sqrt{1-x^2}}u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x / numpy.sqrt(1.0 - x * x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcSin): return False return UnaryOperation.equal_debug(self, other)
[docs] class ArcSinh(UnaryOperation): """This class models the GUM-tree-nodes that take the inverse Hyperbolic Sine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the inverse Hyperbolic Sine of a silbling. :returns: A numeric value, representing the inverse Hyperbolic Sine of a silbling. """ return numpy.arcsinh(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = arcsinh(x) then the resulting uncertainty is :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x / numpy.sqrt(1.0 + x * x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcSinh): return False return UnaryOperation.equal_debug(self, other)
[docs] class ArcCos(UnaryOperation): """This class models the GUM-tree-nodes that take the Arcus Cosine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right) self.arithmetic_check()
[docs] def arithmetic_check(self): """Checks for undefined arguments.""" value = self.get_silbling().get_value() if value < -1.0 or value > 1.0: raise ArithmeticError("The argument must be within [-1,1]")
[docs] def get_value(self): """Returns the Arc Cosine of the silbling. :returns: A numeric value, representing the Arc Cosine of the silblings. """ return numpy.arccos(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): r"""Returns the uncertainty of this node. Let the node represent the operation y = arccos(x) then the resulting uncertainty is u(y) = -\frac{1}{\sqrt{1-x^2}}u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return -u_x / numpy.sqrt(1.0 - x * x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcCos): return False return UnaryOperation.equal_debug(self, other)
[docs] class ArcCosh(UnaryOperation): """This class models the GUM-tree-nodes that take the inverse Hyperbolic Cosine. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right) self.arithmetic_check()
[docs] def arithmetic_check(self): r"""Checks for undefined arguments. within (1,\infty]. """ value = self.get_silbling().get_value() if value <= 1.0: raise ArithmeticError("The argument must be within (1,inf]")
[docs] def get_value(self): """Returns the Arc Cosine of the silbling. :returns: A numeric value, representing the Arc Cosine of the silblings. """ return numpy.arccosh(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = arccosh(x) then the resulting uncertainty is :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x / (numpy.sqrt(x - 1.0) * numpy.sqrt(x + 1.0))
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcCosh): return False return UnaryOperation.equal_debug(self, other)
[docs] class ArcTan(UnaryOperation): """This class models the GUM-tree-nodes that take the Arcus Tangent of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the Arc Tangent of the silbling. :returns: A numeric value, representing the Arc Tangent of the silblings. """ return numpy.arctan(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = arcsin(x) then the resulting uncertainty is u(y) = -\frac{1}{1+x^2}u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x / (1.0 + x * x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcTan): return False return UnaryOperation.equal_debug(self, other)
[docs] class ArcTanh(UnaryOperation): """This class models the GUM-tree-nodes that take the inverse Hyperbolic Tangent of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right) self.arithmetic_check()
[docs] def arithmetic_check(self): """Checks for undefined arguments. within (-1,1). """ value = self.get_silbling().get_value() if value <= -1.0 or value >= 1.0: raise ArithmeticError("The argument must be within (-1,1)")
[docs] def get_value(self): """Returns the Arc Tangent of the silbling. :returns: A numeric value, representing the inverse hyperbolic Tangent of the silblings. """ return numpy.arctanh(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = arctanh(x) then the resulting uncertainty is u(y) = \frac{1}{1-x^2}u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x / (1.0 - x * x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, ArcTanh): return False return UnaryOperation.equal_debug(self, other)
[docs] class Cosh(UnaryOperation): """This class models the GUM-tree-nodes that take the Hyperbolic Cosine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the Hyperbolic Cosine of the silbling. :returns: A numeric value, representing the Hyperbolic Cosine of the silblings. """ return numpy.cosh(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = cosh(x) then the resulting uncertainty is u(y) = sinh(x) u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x * numpy.sinh(x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Cosh): return False return UnaryOperation.equal_debug(self, other)
[docs] class Sinh(UnaryOperation): """This class models the GUM-tree-nodes that take the Hyperbolic Sine of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the Hyperbolic Sine of the silbling. :returns: A numeric value, representing the Hyperbolic Sine of the silbling. """ return numpy.sinh(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = sinh(x) then the resulting uncertainty is u(y) = cosh(x)u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x * numpy.cosh(x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Sinh): return False return UnaryOperation.equal_debug(self, other)
[docs] class Tanh(UnaryOperation): """This class models the GUM-tree-nodes that take the Hyperbolic Tangent of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the Hyperbolic Tangent of the silbling. :returns: A numeric value, representing the Hyperbolic Sine of the silbling. """ return numpy.tanh(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = tanh(x) then the resulting uncertainty is u(y) = (1 - tanh^{2}(x)) u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x * (1.0 - numpy.tanh(x) * numpy.tanh(x))
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Tanh): return False return UnaryOperation.equal_debug(self, other)
[docs] class Exp(UnaryOperation): """This class models the GUM-tree-nodes that take the exponential of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the exponential of the silbling. :returns: A numeric value, representing the exponential of the silbling. """ return numpy.exp(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = e^x then the resulting uncertainty is u(y) = x \times e^x \times u(x). :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) x = self.get_silbling().get_value() return u_x * numpy.exp(x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Exp): return False return UnaryOperation.equal_debug(self, other)
[docs] class Abs(UnaryOperation): """This class models the GUM-tree-nodes that take the absolute value of a silbling. """
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the exponential of the silbling. :returns: A numeric value, representing the absolute value of the silbling. """ return numpy.absolute(self.get_silbling().get_value())
[docs] def get_uncertainty(self, component): """Return the uncertainty of this node. For ``y = |x|``, this returns ``u(y) = |u(x)|``. """ u_x = self.get_silbling().get_uncertainty(component) return numpy.absolute(u_x)
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Abs): return False return UnaryOperation.equal_debug(self, other)
[docs] class Neg(UnaryOperation): """This class models the unary negation as GUM-tree-element."""
[docs] def __init__(self, right): """Default constructor. :param right: Right silbling of this instance. """ UnaryOperation.__init__(self, right)
[docs] def get_value(self): """Returns the exponential of the silbling. :returns: A numeric value, representing the negative value of the silbling. """ return -self.get_silbling().get_value()
[docs] def get_uncertainty(self, component): """Returns the uncertainty of this node. Let the node represent the operation y = -x then the resulting uncertainty is u(y) = - u(x) . :param component: Another instance of uncertainty. :returns: A numeric value, representing the standard uncertainty. """ u_x = self.get_silbling().get_uncertainty(component) return -u_x
[docs] def equal_debug(self, other): """A method that is only used for serialization checking. :param other: Another instance of UncertainComponent :returns: True, if the instance has the same attribute values as the argument """ other = UncertainComponent.value_of(other) if not isinstance(other, Neg): return False return UnaryOperation.equal_debug(self, other)
[docs] class Context: r"""This class provides the context for an uncertainty evaluation. It maintains the correlation between the inputs and can be used to evaluate the combined standard uncertainty, as shown below. Let your model be y = f(x_1,x_2,\ldots,x_N), then \left(\frac{\delta f}{\delta x_i} \right)^2 u^2(x_i) + 2 \sum_{i=1}^{N}\sum_{j=i+1}^{N} \frac{\delta f}{\delta x_i}\frac{\delta f}{\delta x_j} u(x_i,x_j). """
[docs] def __init__(self): """This method initializes the correlation matrix of this context. contexts. Thus, you could maintain various correlation models. """ self._correlationMatrix = {}
[docs] def set_correlation(self, firstItem, secondItem, corr): """This method sets the correlation coefficient r(x_1,x_2) of two inputs. Where :param firstItem: Is x_1 as denoted above. :param secondItem: Is x_2 as denoted above. :param corr: The correlation as described by r(x_1,x_2) . """ # masquerade quantities if isinstance(firstItem, quantities.Quantity) or isinstance( secondItem, quantities.Quantity ): firstItem = quantities.Quantity.value_of(firstItem) secondItem = quantities.Quantity.value_of(secondItem) firstUnit = firstItem.get_default_unit() secondUnit = secondItem.get_default_unit() firstComp = firstItem.get_value(firstUnit) secondComp = secondItem.get_value(secondUnit) self.set_correlation(firstComp, secondComp, corr) return _require_uncertain_input(firstItem, "firstItem") _require_uncertain_input(secondItem, "secondItem") # autocorrelation automatically implied if firstItem == secondItem: return # Update the covariance (lookup-table) self._correlationMatrix[(firstItem, secondItem)] = corr # ensure symmetry self._correlationMatrix[(secondItem, firstItem)] = corr
[docs] def get_correlation(self, firstItem, secondItem): """This method returns the correlation coefficient r(x_1,x_2) of two inputs. Where If no correlation has been defined before, this method returns ``0.0``, except for x_1 = x_2. In the last case this method returns ``1.0``. :param firstItem: Is x_1 as denoted above. :param secondItem: Is x_2 as denoted above. """ if isinstance(firstItem, quantities.Quantity) or isinstance( secondItem, quantities.Quantity ): firstItem = quantities.Quantity.value_of(firstItem) secondItem = quantities.Quantity.value_of(secondItem) firstUnit = firstItem.get_default_unit() secondUnit = secondItem.get_default_unit() firstComp = firstItem.get_value(firstUnit) secondComp = secondItem.get_value(secondUnit) return self.get_correlation(firstComp, secondComp) if firstItem == secondItem: return 1.0 return self._correlationMatrix.get((firstItem, secondItem), 0.0)
[docs] def uncertainty(self, component): """This method returns the combined standard uncertainty of an uncertain value. :param component: The component of uncertainty to evaluate. :returns: The standard uncertainty. """ if isinstance(component, quantities.Quantity): unit = component.get_default_unit() ucomp = component.get_value(unit) return quantities.Quantity(unit, self.uncertainty(ucomp)) _require_uncertain_component(component) components = component.depends_on() result = 0.0 with _cached_component_evaluation(component): partials = [ (comp, component.get_uncertainty(comp)) for comp in components ] if not self._correlationMatrix: result = sum(partial * partial for _comp, partial in partials) return numpy.sqrt(result) for index, (comp1, partial1) in enumerate(partials): result += partial1 * partial1 for comp2, partial2 in partials[index + 1:]: result += ( 2.0 * partial1 * self.get_correlation(comp1, comp2) * partial2 ) return numpy.sqrt(result)
[docs] def value_uncertainty_unit(self, component): """This method returns the value, combined standard uncertainty, and unit of an uncertain value. :param component: The component of uncertainty to evaluate. :returns: (value, The standard uncertainty,unit). """ # if( isinstance( component, quantities.Quantity ) ): try: unit = component.get_default_unit() except AttributeError: # does not have unit unit = None if unit: ucomp = component.get_value(unit) else: ucomp = component.get_value() try: value = ucomp.get_value() if unit: uncertainty = self.uncertainty(component).get_value(unit) else: uncertainty = self.uncertainty(component).get_value() except AttributeError: value = ucomp uncertainty = 0.0 return value, uncertainty, unit
# assert( isinstance( component, UncertainComponent ) )
[docs] def dof(self, component): r"""This method calculates the effective degrees of freedom using the Welch-Satterthwaite formulae: :: {\sum_{i=1}^N \frac{\left( \frac{\delta f}{\delta x_i}\right)^4 u^4(x_i)}{\nu_i}} Where u_c(y) is the combined standard uncertainty, no standard procedure in python to declare infinity, we use our own constant for it. :param component: The component of uncertainty. :returns: The effective degrees of freedom \nu_{eff} . """ if isinstance(component, quantities.Quantity): unit = component.get_default_unit() ucomp = component.get_value(unit) return self.dof(ucomp) _require_uncertain_component(component) # Used to calculate the nominator of the formula described above. u_c = self.uncertainty(component) components = component.depends_on() # check for inifinity (i.e. if one component is infinite, # the entire result will be infinite) and calculate the # denominator of the formula described above. sum = 0.0 for comp in components: _require_uncertain_input(comp, "comp") dof = comp.get_dof() if dof == 0.0: return arithmetic.INFINITY elif dof == arithmetic.INFINITY: continue else: sum += (component.get_uncertainty(comp)) ** 4 / dof dof_eff = u_c**4 / sum return dof_eff
## Assign the current context to the given component. # \attention This method is only useful in combination with # UncertainComponent.__str__. The context assigned is # not passed to operations performed on <tt>component</tt>. # \see UncertainComponent.__str__ # \param self # \param component The component to which the context should be # attached. # \return component having the context assigned.
[docs] def value_of(self, component): # assert(isinstance(component, UncertainComponent)) if isinstance(component, UncertainComponent): component.set_context(self) elif isinstance(component, quantities.Quantity): component._value.set_context(self) return component
## @}