Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fsolve always returning the guess/estimate

I'm using scipy's optimize.fsolve function for the first time to find the roots to an equation. The problem is that whatever number I use as the guess/estimate value is what I get back as my answer (to within about 8 decimal places). When using full_output=True, I get the exitflag to be '1', which is supposed to mean that 'The solution converged', which to the best of my understanding should mean that the output is indeed a root of the equation.

I know there are a finite number of distinct roots (that are spaced out), as when I graph the equation I can see them. Also, fsolve fails (gives error exitflags) when I input the starting point to be in a range which should return a undefined values (divide by zero, square root of a negative value). But besides that it always return the starting point as the root.

I tested fsolve with a very simple equation and it worked fine, so I know that I'm importing everything I need and should be using fsolve correctly. I also tried messing around with some of the input arguments, but I don't understand them very well and nothing seemed to change).

Below is the relevant code (E is the only variable, everything else has a non-zero value):

def func(E):
    s = sqrt(c_sqr * (1 - E / V_0))
    f = s / tan(s) + sqrt(c_sqr - s**2)
    return f

guess = 3
fsolve(func, guess)

which just outputs '3' and says 'The solution converged.', even though the closest solutions should be at about 2.8 and 4.7.

Does anyone have any idea how to fix this and get a correct answer (using fsolve)?

like image 565
scaevity Avatar asked Dec 19 '11 13:12

scaevity


2 Answers

I think your equation doesn't do what you think it does. For one thing, when I try it, it doesn't return the guess; it returns a number close to the guess. It's very unstable and that seems to be confusing fsolve. For example:

>>> V_0 = 100
>>> c_sqr = 3e8 ** 2
>>> guess = 5
>>> fsolve(func, guess)
array([ 5.00000079])

This is not 5. It is not even 5 within machine precision. It is also not a root of the equation:

>>> func(5.00000079)
2114979.3239706755

But the behavior of the equation is pretty unpredictable anyway:

>>> func(5.0000008)
6821403.0196130127
>>> func(5.0000006)
-96874198.203683496

So obviously there's a zero crossing somewhere around there. I'd say take a good look at your equation. Make sure you are specifying tan's argument in radians, for instance.

like image 67
ptomato Avatar answered Oct 20 '22 08:10

ptomato


Did you try changing your function to something really trivial? Like this:

#!/usr/bin/python
from scipy.optimize import fsolve

def func(E):
#    s = sqrt(c_sqr * (1 - E / V_0))
#    f = s / tan(s) + sqrt(c_sqr - s**2)
    f = E**2 -3.
    return f

guess = 9

sol=fsolve(func, guess)
print sol, func(sol)

For me the code above does converge to where it should.

Also, in the code you've provided --- what are c_str and V_0? If in fact your function depends on more than one variable, and you're treating all of them but one as constant parameters, then use the args argument of the fsolve, like this:

#!/usr/bin/python
from scipy.optimize import fsolve
from numpy import sqrt

def func(E,V_0):
    #s = sqrt(c_sqr * (1 - E / V_0))
    #f = s / tan(s) + sqrt(c_sqr - s**2)
    f = E**2 -V_0
    return f

VV=4.
guess = 9
sol=fsolve(func, guess, args=(VV))

print sol, func(sol,VV) 
like image 25
ev-br Avatar answered Oct 20 '22 07:10

ev-br