Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AttributeError in python/numpy when constructing function for certain values

I'm writing Python code to generate and plot 'super-Gaussian' functions, as:

def supergaussian(x, A, mu, sigma, offset, N=8):
    """Supergaussian function, amplitude A, centroid mu, st dev sigma, exponent N, with constant offset"""
    return A * (1/(2**(1+1/N)*sigma*2*scipy.special.gamma(1+1/N))) * numpy.exp(-numpy.absolute(numpy.power(x-mu,N))/(2*sigma**N)) + offset

init_x = numpy.arange(-100,100,1.0)
init_y = supergaussian(init_x, 1, 0, 25, 0, N=12)

Following code just makes a plot of it. For a reason I cannot fathom, this code works fine when using the default value of 8 for N, or for values of N up to 13. When N is 14 or higher, the function crashes with an error message:

AttributeError: 'float' object has no attribute 'exp'

At the return line in the function definition. Any ideas? Since the only thing in that line that use .exp is the numpy.exp the error message seems to imply that numpy is being interpreted as a float, but only for large values of N...

I'm running python 3.3.2 with numpy 1.7.1 and scipy 0.12.0

like image 592
Alex Z Avatar asked Sep 16 '13 17:09

Alex Z


1 Answers

The error is due to some numpy dtype weirdness. I'm not sure exactly how it works internally, but for some reason 2*25**14 triggers a change in how Numpy handles the datatypes:

>>> type(np.max(-numpy.absolute(numpy.power(init_x-0,13)))/(2*25**13))
<type 'numpy.float64'>
>>> type(np.max(-numpy.absolute(numpy.power(init_x-0,14)))/(2*25**14))
<type 'float'>

With 13, it still uses Numpy's float64 type, but with 14 it somehow reverts back to regular float. This is why you get the AttributeError: a normal Python float doesn't have the exp method, which is a numpy ufunc method. (The error is not due to the name numpy being interpreted as a float. Sometimes these numpy-internal errors are unhelpful in that they don't tell you what the object is that doesn't have the attribute.)

However, this is only happening because the number 2*25**N is a regular Python long, not a value of a numpy datatype. You can fix it by pre-wrapping that value in a numpy dtype, like this:

def supergaussian(x, A, mu, sigma, offset, N=8):
    """Supergaussian function, amplitude A, centroid mu, st dev sigma, exponent N, with constant offset"""
    denom = np.float64(2*sigma**N)
    return A * (1/(2**(1+1/N)*sigma*2*scipy.special.gamma(1+1/N))) * numpy.exp(-numpy.absolute(numpy.power(x-mu,N))/denom) + offset

Now it works fine for large values.

The conversion failure appears to be due to the fact that 2*25**14 is too big to fit in a numpy int64. This looks like a bug to me: if it's too big for int64, it should fall back to float64 or raise an error, not silently fall back to plain float. It looks like there is a related bug on the numpy tracker, but that looks slightly different. You might want to raise the issue on the numpy tracker and/or mailing list.

like image 165
BrenBarn Avatar answered Sep 24 '22 01:09

BrenBarn