I'm encountering a scipy function that seems to return a numpy array no matter what's passed to it. In my application I need to be able to pass scalars and lists only, so the only "problem" is that when I pass a scalar to the function an array with one element is returned (when I would expect a scalar). Should I ignore this behaviour, or hack up the function to ensure that when a scalar is passed a scalar is returned?
Example code:
#! /usr/bin/env python
import scipy
import scipy.optimize
from numpy import cos
# This a some function we want to compute the inverse of
def f(x):
y = x + 2*cos(x)
return y
# Given y, this returns x such that f(x)=y
def f_inverse(y):
# This will be zero if f(x)=y
def minimize_this(x):
return y-f(x)
# A guess for the solution is required
x_guess = y
x_optimized = scipy.optimize.fsolve(minimize_this, x_guess) # THE PROBLEM COMES FROM HERE
return x_optimized
# If I call f_inverse with a list, a numpy array is returned
print f_inverse([1.0, 2.0, 3.0])
print type( f_inverse([1.0, 2.0, 3.0]) )
# If I call f_inverse with a tuple, a numpy array is returned
print f_inverse((1.0, 2.0, 3.0))
print type( f_inverse((1.0, 2.0, 3.0)) )
# If I call f_inverse with a scalar, a numpy array is returned
print f_inverse(1.0)
print type( f_inverse(1.0) )
# This is the behaviour I expected (scalar passed, scalar returned).
# Adding [0] on the return value is a hackey solution (then thing would break if a list were actually passed).
print f_inverse(1.0)[0] # <- bad solution
print type( f_inverse(1.0)[0] )
On my system the output of this is:
[ 2.23872989 1.10914418 4.1187546 ]
<type 'numpy.ndarray'>
[ 2.23872989 1.10914418 4.1187546 ]
<type 'numpy.ndarray'>
[ 2.23872989]
<type 'numpy.ndarray'>
2.23872989209
<type 'numpy.float64'>
I'm using SciPy 0.10.1 and Python 2.7.3 provided by MacPorts.
SOLUTION
After reading the answers below I settled on the following solution. Replace the return line in f_inverse
with:
if(type(y).__module__ == np.__name__):
return x_optimized
else:
return type(y)(x_optimized)
Here return type(y)(x_optimized)
causes the return type to be the same as the type the function was called with. Unfortunately this does not work if y is a numpy type, so if(type(y).__module__ == np.__name__)
is used to detect numpy types using the idea presented here and exclude them from the type conversion.