Source code for error_solver.solvers.error_solver_py
"""
Copyright (c) 2019, Matt Pewsey
"""
import numpy as np
from ._base_error_solver import _BaseErrorSolver
__all__ = ['ErrorSolverPy']
[docs]class ErrorSolverPy(_BaseErrorSolver):
"""
A class for solving systems of equations for their propagation errors
using Python functions.
Parameters
----------
equations : list
A list of equation functions.
partials : list
A list of dictionaries of partial derivative functions.
combos : dict
A dictionary of equation combinations.
tol : float
The tolerance used for verifying that values satisfy equations.
Examples
--------
.. literalinclude:: ../../examples/error_solver_py_ex1.py
In lieu of defining the equation methods manually, the :class:`.ErrorSolver`
class may be used to automatically calculate the partial derivatives
from an input system of equations and write methods to a Python module
for use by :class:`ErrorSolverPy`. This can be done as follows:
.. literalinclude:: ../../examples/error_solver_py_ex2.py
"""
def __init__(self, equations, partials, combos={}, tol=0.01):
self._equations = equations
self._partials = partials
self.combos = combos
self.tol = tol
def __repr__(self):
s = (
('equations', self._equations),
('combos', self.combos),
('tol', self.tol),
)
s = ', '.join('{}: {!r}'.format(x, y) for x, y in s)
return '{}({})'.format(type(self).__name__, s)
[docs] @classmethod
def from_module(cls, module, **kwargs):
"""
Initializes an object from an imported Error Solver Python module.
Parameters
----------
module
An imported Python module with the requisite EQUATIONS, PARTIALS,
and COMBOS global variables.
kwargs
Additional arguments accepted by the default initializer.
"""
return cls(
equations=module.EQUATIONS,
partials=module.PARTIALS,
combos=module.COMBOS,
**kwargs
)
def _check_values(self, values, combo):
"""
Checks that the input values satisfy all equations within the
specified tolerances.
Parameters
----------
values : dict
A dictionary mapping variable names to values.
combo : str
The name of the equation combination to be applied.
"""
for i, eq in enumerate(self.get_equations(combo)):
v = eq(**values)
if abs(v) > self.tol:
raise ValueError('Equation {}: {} value check tolerance '
'exceeded:: |{}| > {}.'.format(i, eq, v, self.tol))
[docs] def check(self, values, errors, combo=None):
"""
Checks that the input parameters are correct to carry out a solution.
Parameters
----------
values : dict
A dictionary mapping variable names to values.
errors : dict
A dictionary mapping variable names to errors.
combo : str
The name of the equation combination to be applied.
"""
self._check_values(values, combo)
self._check_determinancy(values, errors, combo)
[docs] def equation_vars(self, combo=None):
"""
Returns a set of all variables in the equations.
Parameters
----------
combo : str
The name of the equation combination to be applied.
"""
var = set()
for p in self.get_partials(combo):
var |= p.keys()
return var
[docs] def jacobian(self, values, errors, combo=None):
"""
Returns the Jacobian matrix for the system of equations.
Parameters
----------
values : dict
A dictionary mapping variable names to values.
errors : dict
A dictionary mapping variable names to errors.
combo : str
The name of the equation combination to be applied.
"""
partials = self.get_partials(combo)
val, err = self.used_vars(values, errors, combo)
var = {x: i for i, x in enumerate(val + err)}
n, m = len(partials), len(var)
jac = np.zeros((n, m), dtype='float')
for i, p in enumerate(partials):
for k, v in p.items():
j = var[k]
jac[i, j] = v(**values)
return jac