Make dependeny return optional => predictable.

This commit is contained in:
Valentin Boettcher 2019-05-15 07:07:17 +02:00
parent e97c1d8838
commit 246a226c49
3 changed files with 35 additions and 22 deletions

View file

@ -28,7 +28,7 @@ result = x(a=(1, 20), b=(2, 30), c=2)
# used if present. This may be useful to calculate statistical and systemic
# errors in one go.
print(result)
# >> array([ 1.41421356, 35.35533906])
# >> (1.41421356, 35.35533906)
# As a goodie, you can print out the gaussian error distribution in
# symbolic form. (Works best in Jupyter Notebooks)
@ -82,6 +82,10 @@ x(a=([1,2,3], [1,2,3]), b=([1,2,3], 1))
x(a=([1,2,3], [1,2,3]), b=([1,2], 1))
```
If all the returned arrays in the tuple have the same shape, you can
easily convert that tuple to a numpy array:
`np.array(x(a=([1,2,3], [1,2,3]), b=([1,2,3], 1)))`
### Dependencies
To make the calculation of complex values easier, one can define
dependencies for a `SecondaryValue`:
@ -90,14 +94,22 @@ dependencies for a `SecondaryValue`:
from SecondaryValue import SecondaryValue
dep = SecondaryValue('u')
x = SecondaryValue("a + b", dependencies={'a': dep})
x = SecondaryValue("a + b", dependencies=dict(a=dep))
# x will now accept u as an additional kwarg and calculate d==dep on the fly
# and return a dictionary containing it as a second return value.
# and return a dictionary containing it as a second return value if you
# specify `retdeps=True`.
print(x(b=1, u=(1, 2), retdeps=True))
# >> ((2.0, 2.0), {'a': ((1.0, 2.0), {})})
# To make the output predictable, the dependencies aren't returned by deafult.
print(x(b=1, u=(1, 2)))
# >> (array([2., 2.]), {'a': array([1., 2.])})
# >> (2.0, 2.0)
# you can overwrite the dependency calculation
print(x(b=1/2, a=1/2))
# >> 1.0
```
If there are no dependency values, an empty dict will be returned when
`retdeps=True` is specified.

View file

@ -66,9 +66,9 @@ class SecondaryValue:
if name in kwargs:
continue
tmp = sec_val(**kwargs)
kwargs[name] = tmp[0] if (len(tmp) > 1 and isinstance(tmp, tuple)) \
else tmp
# we always calculate the depndencies
tmp = sec_val(retdeps=True, **kwargs)
kwargs[name] = tmp[0]
calc_deps[name] = tmp
return kwargs, calc_deps
@ -111,6 +111,7 @@ class SecondaryValue:
dep_values (the values and errors of the dependencies)
:rtype: Tuple
"""
kwargs, dep_values = self._calc_deps(**kwargs)
@ -125,7 +126,6 @@ class SecondaryValue:
kwargs = {var: val for var, val in kwargs.items() \
if var in self._symbols}
max_uncertainties = max([len(val) for _, val in kwargs.items() \
if isinstance(val, Iterable)] or [0])
@ -158,7 +158,6 @@ class SecondaryValue:
central_value = np.empty(value_length)
for i in range(0, value_length):
current_values = join_row(scalar_values, vector_values, i)
central_value[i] = self._parsed_lambda(**current_values)
else:
central_value = self._dtype(self._parsed_lambda(**scalar_values))
@ -204,21 +203,23 @@ class SecondaryValue:
return terms
def __call__(self, *args, **kwargs):
def __call__(self, *args, retdeps=False, **kwargs):
"""Calculates a value from the expression by substituting
variables by the values of the given keyword arguments. If an
argument is specified as a tuplpe of (value, error) the
gausssian error propagation will be computed.
The values and errors can be iterable, but must compatible shapes.
The values and errors can be iterable, but must compatible
shapes.
:returns: value or [value, error] or [value, error], dependencies
:param retdeps: wether to return a dictionary with the
calculated dependencies
:returns: value or [value, error] or [value, error, ...],
dependencies
:rtype: numpy data type or np array of [value, errors, ...] or
a tuple the beforementioned as first element and a
dictionary with the calculated dependencies as a second value
dictionary with the calculated dependencies as a
second value
"""
# process the keyword arguments
values, errors, dep_values = self._process_args(*args, **kwargs)
@ -237,7 +238,7 @@ class SecondaryValue:
result.insert(0, central_value)
result = tuple(result)
if dep_values:
if retdeps:
return result, dep_values
return result

View file

@ -6,7 +6,7 @@ def readme():
return f.read()
setup(name='SecondaryValue',
version='0.1.3',
version='0.1.4',
description='A helper to calculate the gaussian error propagation.',
long_description=readme(),
long_description_content_type='text/markdown',