Consider the following snipped of code:
import random
from uncertainties import unumpy, ufloat
x = [random.uniform(0,1) for p in range(1,8200)]
y = [random.randrange(0,1000) for p in range(1,8200)]
xerr = [random.uniform(0,1)/1000 for p in range(1,8200)]
yerr = [random.uniform(0,1)*10 for p in range(1,8200)]
x = unumpy.uarray(x, xerr)
y = unumpy.uarray(y, yerr)
diff = sum(x*y)
u = ufloat(0.0, 0.0)
for k in range(len(x)):
u+= (diff-x[k])**2 * y[k]
print(u)
If I try to run it on my computer it takes up to 10 minutes to produce a result. I'm not really sure why this is the case and would appreciated some kind of explanation.
If I had to guess I'd say the computation of the uncertainties is for some reason more complicated than one would think, but like I said, it's just a guess. Interestingly enough the code is almost immediately done if if remove the print
instruction at the end, which honestly confuses me more than it helps...
In case you don't know it, this is the uncertainties library's repo.
I can reproduce this, the print is what is taking forever. Or rather, it is the conversion to string implicitly called by print. I used line_profiler to measure the time of the
__format__
function ofAffineScalarFunc
. (It is called by__str__
, which is called by print) I decreased the array size from 8200 to 1000 to make it go a bit faster. This is the result (pruned for readability):You can see that almost all of the time is taken in line 1967, where the standard deviation is computed. If you dig a bit deeper, you will find that the
error_components
property is the problem, where thederivatives
property is the problem, in which_linear_part.expand()
is the problem. If you profile that, you begin to get to the root of the problem. Most work here is evenly-ish distributed:You can see that there are a lot of calls to
expanded
, which callsisinstance
, which is slow. Also note the comments, which hint that this library actually only calculates the derivatives when it is required (and is aware that it is really slow otherwise). This is why the conversion to string takes so long, and the time is not taken before.In
__init__
ofAffineScalarFunc
:In
std_dev
ofAffineScalarFunc
:In
expand
ofLinearCombination
:So all in all, this is somewhat expected, since the library handles these non-native numbers that require a lot of operations to handle (apparently).