views:

306

answers:

1

I would like to provide "all" mathematical functions for the number-like objects created by a module (the uncertainties.py module, which performs calculations with error propagation)—these objects are numbers with uncertainties.

What is the best way to do this?

Currently, I redefine most of the functions from math in the module uncertainties.py, so that they work on numbers with uncertainties. One drawback is that users who want to do from math import * must do so after doing import uncertainties.

The interaction with NumPy is, however, restricted to basic operations (an array of numbers with uncertainties can be added, etc.); it does not (yet) include more complex functions (e.g. sin()) that would work on NumPy arrays that contain numbers with uncertainties. The approach I have taken so far consists in suggesting that the user define sin = numpy.vectorize(math.sin), so that the new math.sin function (which works on numbers with uncertainties) is broadcast to the elements of any Numpy array. One drawback is that this has to be done for each function of interest by the user, which is cumbersome.

So, what is the best way to extend mathematical functions such as sin() so that they work conveniently with simple numbers and NumPy arrays?

The approach chosen by NumPy is to define its own numpy.sin, rather than modifying math.sin so that it works with Numpy arrays. Should I do the same for my uncertainties.py module, and stop redefining math.sin?

Furthermore, what would be the most efficient and correct way of defining sin so that it works both for simple numbers, numbers with uncertainties, and Numpy arrays? My redefined math.sin already handles simple numbers and numbers with uncertainties. However, vectorizing it with numpy.vectorize is likely to be much slower on "regular" NumPy arrays than numpy.sin.

A: 

It looks like following what NumPy itself does keeps things clean: "extended" mathematical operations (sin…) that work on new objects can be put in a separate name space. Thus, NumPy has numpy.sin, etc. These operations are mostly compatible with those from math, but also work on NumPy arrays.

Therefore, it seems to me that mathematical functions that should work on usual numbers and NumPy arrays and their counterparts with uncertainties are best defined in a separate name space. For instance, the user could do:

from uncertainties import sin

or

from uncertainties import *  # sin, cos, etc.

For optimization purposes, an alternative might be to provide two distinct sets of mathematical functions: those that generalize functions to simple numbers with uncertainties, and those that generalize them to arrays with uncertainties:

from uncertainties.math_ops import *  # Work on scalars and scalars with uncertainty

or

from uncertainties.numpy_ops import *  # Work on everything (scalars, arrays, numbers with uncertainties, arrays with uncertainties)
EOL