Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def check_op(op, num_args):
"""
Makes sure that the derivatives for function '__op__' of class
AffineScalarFunc, which takes num_args arguments, are correct.
If num_args is None, a correct value is calculated.
"""
op_string = "__%s__" % op
func = getattr(AffineScalarFunc, op_string)
numerical_derivatives = uncertainties.NumericalDerivatives(
# The __neg__ etc. methods of AffineScalarFunc only apply,
# by definition, to AffineScalarFunc objects: we first map
# possible scalar arguments (used for calculating
# derivatives) to AffineScalarFunc objects:
lambda *args: func(*map(uncertainties.to_affine_scalar, args)))
_compare_derivatives(func, numerical_derivatives, [num_args])
args = [
random.choice(range(-10, 10))
if arg_num in integer_arg_nums
else uncertainties.Variable(random.random()*4-2, 0)
for arg_num in range(num_args)]
# 'args', but as scalar values:
args_scalar = [uncertainties.nominal_value(v)
for v in args]
func_approx = func(*args)
# Some functions yield simple Python constants, after
# wrapping in wrap(): no test has to be performed.
# Some functions also yield tuples...
if isinstance(func_approx, AffineScalarFunc):
# We compare all derivatives:
for (arg_num, (arg, numerical_deriv)) in (
enumerate(zip(args, numerical_derivatives))):
# Some arguments might not be differentiable:
if isinstance(arg, int):
continue
fixed_deriv_value = func_approx.derivatives[arg]
num_deriv_value = numerical_deriv(*args_scalar)
# This message is useful: the user can see that
# tests are really performed (instead of not being
# performed, silently):
def test_basic_access_to_data():
"Access to data from Variable and AffineScalarFunc objects."
x = ufloat((3.14, 0.01), "x var")
assert x.tag == "x var"
assert x.nominal_value == 3.14
assert x.std_dev() == 0.01
# Case of AffineScalarFunc objects:
y = x + 0
assert type(y) == AffineScalarFunc
assert y.nominal_value == 3.14
assert y.std_dev() == 0.01
# Details on the sources of error:
a = ufloat((-1, 0.001))
y = 2*x + 3*x + 2 + a
error_sources = y.error_components()
assert len(error_sources) == 2 # 'a' and 'x'
assert error_sources[x] == 0.05
assert error_sources[a] == 0.001
# Derivative values should be available:
assert y.derivatives[x] == 5
# Modification of the standard deviation of variables:
x.set_std_dev(1)
Version of frexp that works for numbers with uncertainty, and also
for regular numbers.
"""
# The code below is inspired by uncertainties.wrap(). It is
# simpler because only 1 argument is given, and there is no
# delegation to other functions involved (as for __mul__, etc.).
aff_func = to_affine_scalar(x)
if aff_func.derivatives:
result = math.frexp(aff_func.nominal_value)
# With frexp(x) = (m, e), dm/dx = 1/(2**e):
factor = 1/(2**result[1])
return (
AffineScalarFunc(
result[0],
# Chain rule:
dict((var, factor*deriv)
for (var, deriv) in aff_func.derivatives.items())),
# The exponent is an integer and is supposed to be
# continuous (small errors):
result[1])
else:
# This function was not called with an AffineScalarFunc
# argument: there is no need to return numbers with uncertainties:
return math.frexp(x)
non_std_wrapped_funcs.append('frexp')
# AffineScalarFunc objects. The approach followed here is to
# progressively build the matrix of derivatives, by
# progressively adding the derivatives with respect to
# successive variables.
for (var, deriv_wrt_var) in zip(variables, func_and_derivs):
# Update of the list of variables and associated
# derivatives, for each element:
for (derivative_dict, derivative_value) in zip(
derivatives.flat, deriv_wrt_var.flat):
if derivative_value:
derivative_dict[var] = derivative_value
# An array of numbers with uncertainties are built from the
# result:
result = numpy.vectorize(uncertainties.AffineScalarFunc)(
func_nominal_value, derivatives)
# Numpy matrices that contain numbers with uncertainties are
# better as unumpy matrices:
if isinstance(result, numpy.matrix):
result = result.view(matrix)
return result
Author: Georg Brandl .
This file has been placed in the public domain.
"""
import re
import sys
from math import pi
import numpy as np
from functools import reduce
# allow uncertain values if the "uncertainties" package is available
try:
from uncertainties import ufloat, Variable, AffineScalarFunc
import uncertainties.umath as unp
uncertain = (Variable, AffineScalarFunc)
def valuetype(vu):
v,u = vu
if isinstance(v, uncertain):
return v
return ufloat((v, u))
except ImportError:
uncertain = ()
valuetype = lambda vu: vu[0]
unp = np
class UnitError(ValueError):
pass
# Adapted from ScientificPython:
# Written by Konrad Hinsen
Version of modf that works for numbers with uncertainty, and also
for regular numbers.
"""
# The code below is inspired by uncertainties.wrap(). It is
# simpler because only 1 argument is given, and there is no
# delegation to other functions involved (as for __mul__, etc.).
aff_func = to_affine_scalar(x)
(frac_part, int_part) = math.modf(aff_func.nominal_value)
if aff_func.derivatives:
# The derivative of the fractional part is simply 1: the
# derivatives of modf(x)[0] are the derivatives of x:
return (AffineScalarFunc(frac_part, aff_func.derivatives), int_part)
else:
# This function was not called with an AffineScalarFunc
# argument: there is no need to return numbers with uncertainties:
return (frac_part, int_part)
array_like -- array-like object that contains numbers with
uncertainties (list, Numpy ndarray or matrix, etc.).
args -- additional arguments that are passed directly to
func_with_derivatives.
"""
# So that .flat works even if array_like is a list. Later
# useful for faster code:
array_version = numpy.asarray(array_like)
# Variables on which the array depends are collected:
variables = set()
for element in array_version.flat:
# floats, etc. might be present
if isinstance(element, uncertainties.AffineScalarFunc):
variables |= set(element.derivatives.iterkeys())
array_nominal = nominal_values(array_version)
# Function value, and derivatives at array_nominal (the
# derivatives are with respect to the variables contained in
# array_like):
func_and_derivs = func_with_derivatives(
array_nominal,
type(array_like),
(array_derivative(array_version, var) for var in variables),
*args)
func_nominal_value = func_and_derivs.next()
if not variables:
return func_nominal_value
def ldexp(x, y):
# The code below is inspired by uncertainties.wrap(). It is
# simpler because only 1 argument is given, and there is no
# delegation to other functions involved (as for __mul__, etc.).
# Another approach would be to add an additional argument to
# uncertainties.wrap() so that some arguments are automatically
# considered as constants.
aff_func = to_affine_scalar(x) # y must be an integer, for math.ldexp
if aff_func.derivatives:
factor = 2**y
return AffineScalarFunc(
math.ldexp(aff_func.nominal_value, y),
# Chain rule:
dict((var, factor*deriv)
for (var, deriv) in aff_func.derivatives.items()))
else:
# This function was not called with an AffineScalarFunc
# argument: there is no need to return numbers with uncertainties:
# aff_func.nominal_value is not passed instead of x, because
# we do not have to care about the type of the return value of
# math.ldexp, this way (aff_func.nominal_value might be the
# value of x coerced to a difference type [int->float, for
# instance]):
return math.ldexp(x, y)
many_scalars_to_scalar_funcs.append('ldexp')