Scipy Newton with Derived: TypeError: Object 'numpy.float64' could not be called
I have a problem with scipy newton method. I am getting an error when using newton with a given derivative (see below for error output).
I am trying to calculate the root x ** 2 with a starting value of x0 = 2.0:
def test_newtonRaphson():
def f(x):
resf = x**2
return resf
assert(derivative(f, 1.0)) == 2.0
assert(round(newton(f, 0.0), 10)) == 0.0
dfx0 = derivative(f, 2.0)
assert(round(newton(f, 2.0, dfx0), 10)) == 0.0
The whole error looks like this:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
func = <function f at 0x04049EF0>, x0 = 2.0, fprime = 4.0, args = ()
tol = 1.48e-08, maxiter = 50, fprime2 = None
def newton(func, x0, fprime=None, args=(), tol=1.48e-8, maxiter=50,
fprime2=None):
"""
Find a zero using the Newton-Raphson or secant method.
Find a zero of the function `func` given a nearby starting point `x0`.
The Newton-Raphson method is used if the derivative `fprime` of `func`
is provided, otherwise the secant method is used. If the second order
derivate `fprime2` of `func` is provided, parabolic Halley method
is used.
Parameters
----------
func : function
The function whose zero is wanted. It must be a function of a
single variable of the form f(x,a,b,c...), where a,b,c... are extra
arguments that can be passed in the `args` parameter.
x0 : float
An initial estimate of the zero that should be somewhere near the
actual zero.
fprime : function, optional
The derivative of the function when available and convenient. If it
is None (default), then the secant method is used.
args : tuple, optional
Extra arguments to be used in the function call.
tol : float, optional
The allowable error of the zero value.
maxiter : int, optional
Maximum number of iterations.
fprime2 : function, optional
The second order derivative of the function when available and
convenient. If it is None (default), then the normal Newton-Raphson
or the secant method is used. If it is given, parabolic Halley's
method is used.
Returns
-------
zero : float
Estimated location where function is zero.
See Also
--------
brentq, brenth, ridder, bisect
fsolve : find zeroes in n dimensions.
Notes
-----
The convergence rate of the Newton-Raphson method is quadratic,
the Halley method is cubic, and the secant method is
sub-quadratic. This means that if the function is well behaved
the actual error in the estimated zero is approximately the square
(cube for Halley) of the requested tolerance up to roundoff
error. However, the stopping criterion used here is the step size
and there is no guarantee that a zero has been found. Consequently
the result should be verified. Safer algorithms are brentq,
brenth, ridder, and bisect, but they all require that the root
first be bracketed in an interval where the function changes
sign. The brentq algorithm is recommended for general use in one
dimensional problems when such an interval has been found.
"""
if tol <= 0:
raise ValueError("tol too small (%g <= 0)" % tol)
if fprime is not None:
# Newton-Rapheson method
# Multiply by 1.0 to convert to floating point. We don't use float(x0)
# so it still works if x0 is complex.
p0 = 1.0 * x0
fder2 = 0
for iter in range(maxiter):
myargs = (p0,) + args
fder = fprime(*myargs)
E TypeError: Object 'numpy.float64' could not be called
File "C:\Anaconda\lib\site-packages\scipy\optimize\zeros.py", line 116
TypeError
source to share
I think what is happening is that you are passing a value to the derivative, not a function that represents the derivative. You need something "callable", and the value (more precisely, the value dfx0 = derivative(f, 2.0)
) cannot be "called" as a function.
FYI: If you haven't already, it might be a good idea to take a look at these examples .
source to share
You can use SymPy to evaluate the derivative and then use it lambdify
to convert that expression into a function that can be used with scipy. Note that it lambdify
is currently unaware of SciPy by default, so you will need to add a translation dictionary for scipy special functions manually:
In [23]: expr = gamma(1+3/x)/gamma(1+1/x)**3
In [24]: print(expr.diff(x))
3*gamma(1 + 3/x)*polygamma(0, 1 + 1/x)/(x**2*gamma(1 + 1/x)**3) - 3*gamma(1 + 3/x)*polygamma(0, 1 + 3/x)/(x**2*gamma(1 + 1/x)**3)
In [25]: f = lambdify(x, expr.diff(x), ['numpy', {'gamma': scipy.special.gamma, 'polygamma': scipy.special.polygamma}])
At this point, I cannot find any roots of this expression using the function newton
. Based on the original graph from Wolfram Alpha , I don't see any obvious points where the derivative is 0, so I wouldn't be surprised if there are no real roots.
source to share