def test_wrapped_func_with_kwargs(): """ Test wrapped functions with keyword args """ def cos_plain(angle): return math.cos(angle) def cos_kwargs(angle, **kwargs): return math.cos(angle) def use_kwargs(angle, cos=True): if cos: return math.cos(angle) else: return math.sin(angle) # wrappings of these functions wrap_cos_plain = wrap(cos_plain) wrap_cos_wderiv = wrap(cos_plain, [math.cos]) wrap_cos_kwargs = wrap(cos_kwargs) wrap_use_kwargs = wrap(use_kwargs) umath_cos = umath.cos umath_sin = umath.sin # now test that the wrapped functions give the same results # as the umath versions for a variety of input values for a in (ufloat((0.2, 0.01)), ufloat((0.7, 0.00001)), #ufloat((0.9, 0.3)), ufloat((1.e-4, 0.3)), #ufloat((200.0, 0.3)), ufloat((1.e5, 0.3)), #0, 2, 1.25, 0.0, 1.e-5, 0.707, 1.5708 ): ucos = umath_cos(a) usin = umath_sin(a) assert _numbers_close(ucos, wrap_cos_plain(a)) assert _numbers_close(ucos, wrap_cos_wderiv(a)) assert _numbers_close(ucos, wrap_cos_kwargs(a)) assert _numbers_close(ucos, wrap_cos_kwargs(a, opt=None)) assert _numbers_close(ucos, wrap_cos_kwargs(a, opt=None, opt2=True)) assert _numbers_close(ucos, wrap_use_kwargs(a, cos=True)) assert _numbers_close(usin, wrap_use_kwargs(a, cos=False)) # affirm that calling a wrapped function with unsupported # keyword args raises a TypeError raised = False try: wrap_use_kwargs(a, other=False) except TypeError: raised = True assert raised
def wrapped_fsum(): """ Returns an uncertainty-aware version of math.fsum, which must be contained in _original_func. """ # The fsum function is flattened, in order to use the # wrap() wrapper: flat_fsum = lambda *args: original_func(args) flat_fsum_wrap = wrap(flat_fsum, itertools.repeat(lambda *args: 1)) return wraps(lambda arg_list: flat_fsum_wrap(*arg_list), original_func)
def wrapped_fsum(): """ Returns an uncertainty-aware version of math.fsum, which must be contained in _original_func. """ # The fsum function is flattened, in order to use the # wrap() wrapper: flat_fsum = lambda *args: original_func(args) flat_fsum_wrap = wrap( flat_fsum, itertools.repeat(lambda *args: 1)) return wraps(lambda arg_list: flat_fsum_wrap(*arg_list), original_func)
def test_wrapped_func(): """ Test uncertainty-aware functions obtained through wrapping. """ # This function can be wrapped so that it works when 'angle' has # an uncertainty (math.cos does not handle numbers with # uncertainties): def f(angle, list_var): return math.cos(angle) + sum(list_var) f_wrapped = wrap(f) my_list = [1, 2, 3] # Test of a wrapped function that only calls the original function: assert f_wrapped(0, my_list) == 1 + sum(my_list) # As a precaution, the wrapped function does not venture into # calculating f with uncertainties when one of the argument is not # a simple number, because this argument might contain variables: angle = ufloat((0, 0.1)) assert f_wrapped(angle, [angle, angle]) == NotImplemented assert f_wrapped(angle, my_list) == NotImplemented
# for (name, attr) in vars(math).items(): for name in dir(math): if name in fixed_derivatives: # Priority to functions in fixed_derivatives derivatives = fixed_derivatives[name] elif name in num_deriv_funcs: # Functions whose derivatives are calculated numerically by # this module fall here (isinf, fmod,...): derivatives = None # Means: numerical calculation required else: continue # 'name' not wrapped by this module (__doc__, e, etc.) func = getattr(math, name) setattr(this_module, name, wraps(wrap(func, derivatives), func)) many_scalars_to_scalar_funcs.append(name) ############################################################################### ######################################## # Special cases: some of the functions from no_std_wrapping: ########## # The math.factorial function is not converted to an uncertainty-aware # function, because it does not handle non-integer arguments: it does # not make sense to give it an argument with a numerical error # (whereas this would be relevant for the gamma function). ##########