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)?
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.
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)
Related
Say I have an equation:
a^x + b^x + c^x = n
Since I know a, b, c and n, is there a way to solve for x?
I have been struggling with this problem for a while now, and I can't seem to find a solution online.
My current method is to iterate over X until the left side is "close enough" to n. The method is pretty slow and in an already computationally difficult algorithm.
Example:
3^x + 5^x + 7^x = 83
How do i go about solving for x. (2 in this case)
I tried the equation in WolframAlpha and it seems to know how to solve it, but any other program fails to do so.
I probably should also mention that X is not an integer (mostly in 0.01 to 0.05 range in my case).
You can use scipy library. You can install it using command pip install scipy
Then, this code will work:
from scipy.optimize import root
def eqn(x):
return 3**x + 5**x + 7**x - 83
myroot = root(eqn, 2)
print(myroot.x)
Here, root takes two arguments root(fun, x0) where fun is the function of the equation and x0 is an rough estimate of the root value. For example if you know that your root will fall in range of (0,1) then you can enter 0 as rough estimate.
Also make sure the equation entered in the code is such that R.H.S. is equal to 0.
In our case 3^x + 5^x + 7^x = 83 becomes 3^x + 5^x + 7^x - 83 = 0
Reference Documentation
If you want to stick to base Python, it is easy enough to implement Newton's method for this problem:
from math import log
def solve(a,b,c,n,guess,tol = 1e-12):
x = guess
for i in range(100):
x_new = x - (a**x + b**x + c**x - n)/(log(a)*a**x + log(b)*b**x + log(c)*c**x)
if abs(x-x_new) < tol: return x_new
x = x_new
return "Doesn't converge on a root"
Newton's method might fail to converge in some pathological cases, hence an escape valve for such cases. In practice it converges very rapidly.
For example:
>>> solve(3,5,7,83,1)
2.0
Despite all this, I think that Cute Panda's answer is superior. It is easy enough to do a straight-forward implementation of such numerical algorithms, one that works adequately in most cases, but naive implementations such as the one give above tend to be vulnerable to excessive round-off error as well as other problems. scipy uses highly optimized routines which are implemented in a much more robust way.
I am very new to programming, and had to use sympy for a school project.
I think I get that using nonlinsolve to return an angle gives an ImageSet with the angle + 2n*pi. However I want it to return only the value of the angle (in the interval [0,pi/2]), and as one value and not an interval.
from sympy import nonlinsolve, symbols,cos
x=symbols('x')
print(nonlinsolve([cos(x)-1],[x]).args[0][0])
I want the result to be 0 and not 2*n*pi.
Clarification : I know that the result is correct, but I only want one value, that I can use algebraically, and I don't know how Sympy works (how to manipulate ImageSets)
So I might be wrong because i dont use sympy, but the solution that solvers return seems to be corect to me.
ImageSet(Lambda(_n, 2*_n*pi), Integers)
From what I understand solver returned lambda function. Cosinus is a cyclic function which means it reapeats it's value every 2PI. So the solver says first solution (_n = 0) is 0, second (_n = 1) is 2pi and so on.
look at the function plot and it will hopefully make sense:
Wolfram Alpha - (cos(x) - 1)
EDIT: I think you need to use intersect method of imageset like this( note that intersect returns all the intersections, here i selected just the first one):
from sympy import nonlinsolve, symbols,cos, Interval
import math
x = symbols('x')
f = nonlinsolve([cos(x)-1], [x]).args[0][0]
sol = f.intersect(Interval(0, math.pi/2)).args[0]
print(sol)
I am using Sympy to evaluate some symbolic sums that involve manipulations of the gamma functions but I noticed that in this case it's not evaluating the sum and keeps it unevaluated.
import sympy as sp
a = sp.Symbol('a',real=True)
b = sp.Symbol('b',real=True)
d = sp.Symbol('d',real=True)
c = sp.Symbol('c',integer=True)
z = sp.Symbol('z',complex=True)
t = sp.Symbol('t',complex=True)
sp.simplify(t-sp.summation((sp.exp(-d)*(d**c)/sp.gamma(c+1))/(z-c-a*t),(c,0,sp.oo)))
I then need to lambdify this expression, and unfortunately this becomes impossible to do.
With Matlab symbolic toolbox however I get the following answer:
Matlab
>> a=sym('a')
>> b=sym('b');
>> c=sym('c')
>> d=sym('d');
>> z=sym('z');
>> t=sym('t');
>> symsum((exp(-d)*(d^c)/factorial(c))/(z-c-a*t),c,0,inf)
ans =
(-d)^(z - a*t)*exp(-d)*(gamma(a*t - z) - igamma(a*t - z, -d))
The formula involves lower incomplete gamma functions, as expected.
Any idea why of this behaviour? I thought sympy was able to do this summation symbolically.
Running your code with SymPy 1.2 results in
d**(-a*t + z)*exp(-I*pi*a*t - d + I*pi*z)*lowergamma(a*t - z, d*exp_polar(I*pi)) + t
By the way, summation already attempts to evaluate the sum (and succeeds in case of SymPy 1.2), subsequent simplification is cosmetic. (And can sometimes be harmful).
The presence of exp_polar means that SymPy found it necessary to consider the points on the Riemann surface of logarithmic function instead of regular complex numbers. (Related bit of docs). The function lower_gamma is branched and so we must distinguish between "the value at -1, if we arrive to -1 from 1 going clockwise" from "the value at -1, if we arrive to -1 from 1 going counterclockwise". The former is exp_polar(-I*pi), the latter is exp_polar(I*pi).
All this is very interesting but not really helpful when you need concrete evaluation of the expression. We have to unpolarify this expression, and from what Matlab shows, simply replacing exp_polar with exp is a correct way to do so here.
rv = sp.simplify(t-sp.summation((sp.exp(-d)*(d**c)/sp.gamma(c+1))/(z-c-a*t),(c,0,sp.oo)))
rv = rv.subs(sp.exp_polar, sp.exp)
Result: d**(-a*t + z)*exp(-I*pi*a*t - d + I*pi*z)*lowergamma(a*t - z, -d) + t
There is still something to think about here, with complex numbers and so on. Is d positive or negative? What does raising it to the power -a*t+z mean, what branch of multivalued power function do we take? The same issues are present in Matlab output, where -d is raised to a power.
I recommend testing this with floating point input (direct summation of series vs evaluation of the SymPy expression for it), and adding assumptions on the sign of d if possible.
I am trying to create a program that will work out how long it will take for something to hit the ground when dropped from a particular height and it uses the known quadratic formula. The program appears to be doing what I want of it until it reaches line 7 where there is a math issue I beleive involving sqrt. Can anybody help?
So far I have come up with...
v = float(input())
lowerSum = 2*(-4.9)
upperSum1 = -4*(-4.9)
upperSum2 = (upperSum1)*(11000)
upperSum3 = (v)**2 - (upperSum2)
from math import sqrt
upperSum4 = (v) - sqrt(upperSum3)
t = (upperSum4) / (lowerSum)
print (t)
When I run the program it states that there is a math domain error; I'm new to programming and I do not know what this means.
I am trying to print out the value of t.
You misread the formula (bottom of page).
Specifically, you are applying the minus sign after v**2 twice:
First you apply it here (incorrectly, as if it was a negative sign):
upperSum1 = -4*(-4.9)
Then you apply it again here (correctly, as a minus symbol).
upperSum3 = (v)**2 - (upperSum2)
upperSum1 should be:
upperSum1 = 4*(-4.9)
The 'math domain error' is telling you that you've passed the sqrt function a value that is outside it's "domain". The domain of the sqrt function is the positive numbers. At some point upperSum3 becomes negative, which makes the sqrt rather unhappy, so it throws an error at you.
You could fix this by adding an if statement to change what your code does if upperSum3 is less than 0, for example:
if upperSum3 < 0:
#do something other than take the sqrt
else:
upperSum4 = (v) - sqrt(upperSum3)
Just going a bit deeper into the problem by doing the math...
v = float(input())
lowerSum = -9.8
upperSum1 = 19.6
upperSum2 = 215600
upperSum3 = (v)**2 - (215600)
from math import sqrt
upperSum4 = (v) - sqrt(upperSum3)
t = (upperSum4) / (lowerSum)
print (t)
So you have to have the square of v in line 5 be more than 215600 for the equation to not return a negative number to sqrt(), which is what is causing the error.
V has to be greater than 465 for the upperSum3 to be positive, and by running various numbers, it never actually becomes positive, so there's definitely something wrong with the equation you are using, or the set-up itself.
Without knowing the formula myself (which I can't find) there's no way for me to tell which part of the code is actually wrong.
import math
v=float(input())
t=float()
Result1=float(v-(math.sqrt(float(v**2)-float(4*(-4.9))*(11000))))
Result2=float(2*(-4.9))
t=float(Result1/Result2)
print(t)
This works. However, I'm new to python and was having trouble with my results converting to an integer. So.... if my use of "float" seems excessive, it's cause it is :-) For a good half an hour I was trying to perform all of the calculations on one line but gave up and broken it down. If anyone has a better solution that performs the calculation on one line I'm all ears.
I'm trying to code this expression in python but I'm having some difficulty.
This is the code I have so far and wanted some advice.
x = 1x2 vector
mu = 1x2 vector
Sigma = 2x2 matrix
xT = (x-mu).transpose()
sig = Sigma**(-1)
dotP = dot(xT ,sig )
dotdot = dot(dotP, (x-mu))
E = exp( (-1/2) dotdot )
Am I on the right track? Any suggestions?
Sigma ** (-1) isn't what you want. That would raise each element of Sigma to the -1 power, i.e. 1 / Sigma, whereas in the mathematical expression it means the inverse, which is written in Python as np.linalg.inv(Sigma).
(-1/2) dotdot is a syntax error; in Python, you need to always include * for multiplication, or just do - dotdot / 2. Since you're probably using python 2, division is a little wonky; unless you've done from __future__ import division (highly recommended), 1/2 will actually be 0, because it's integer division. You can use .5 to get around that, though like I said I do highly recommend doing the division import.
This is pretty trivial, but you're doing the x-mu subtraction twice where it's only necessary to do once. Could save a little speed if your vectors are big by doing it only once. (Of course, here you're doing it in two dimensions, so this doesn't matter at all.)
Rather than calling the_array.transpose() (which is fine), it's often nicer to use the_array.T, which is the same thing.
I also wouldn't use the name xT; it implies to me that it's the transpose of x, which is false.
I would probably combine it like this:
# near the top of the file
# you probably did some kind of `from somewhere import *`.
# most people like to only import specific names and/or do imports like this,
# to make it clear where your functions are coming from.
import numpy as np
centered = x - mu
prec = np.linalg.inv(Sigma)
E = np.exp(-.5 * np.dot(centered.T, np.dot(prec, centered)))