The code that I am using work fine for 2 of the 4 roots of my function, I can't seem to make it work for all 4 roots.
from numpy import *
from scipy import *
import numpy as np
def f(x):
return np.arctan(2*(x - 1)) - np.log(abs(x))
def fprime(x):
return (16/5)*((x - (5/4))**2)-1
def newtonRaphson(x0,e=1.0e-3):
for val in range(1, 15):
dx = - f(x0)/fprime(x0)
print(dx)
x0 = x0 + dx
if abs(dx) < e:
return x0,val
print('Too many iterations\n')
root,numIter = newtonRaphson(-1.0)
print ('Root =',root)
print ('Number of iterations =',numIter)
The roots should be -0.300098, 0.425412, 1, 4.09946
When I use -1.0, I get the root -0.300098, and when I use 1, I get the root 1, but I can't seem to get the other 2 roots. What do I need to do to my code to get it to work? Thanks
Your code is good, the problem is your function - it's too complicated for the method. You can either use a more sophisticated root finding method or you can decrease dx and increase the number of iterations. For instance you can use dx/1000 and 1.5 million maximum iterations. That will give you all the roots. For roots 1 and 4.0996 you will have to use a very close guess. The code works well for simple functions like simple quadratic functions.
Related
Currently I am using the following function but I am wondering if there is a more efficient way or a simple formula to accomplish this?
from scipy.stats import poisson
def calc_expected_value(event_proba):
x = 0.01
while round(1 - poisson.pmf(0, x), 2) != round(event_proba, 2):
x += 0.01
return x
P(X = 0) = exp(-lambda), hence P(X > 0) = 1 - exp(-lambda). If you call this probability event_proba, then
exp(-lambda) = 1 - event_proba
hence
lambda = -log(1 - event_proba)
Of course, in actual Python code you should avoid the name lambda since it has a built-in meaning.
Here it is as a simple formula:
from math import log
def calc_lambda(p_gt_0):
return -log(1.0 - p_gt_0)
This is derived from the fact that P{X=0} = 1 - P{X>0}.
Plug in the formula for a Poisson probability and solve to yield the implementation given above.
I need tangent, arctangent functions for my Python program. I tried np.arctan and np.tan but observed a strange behaviour. In principle, the arctangent of tangent of some number is the number itself, but the code below doesn't give a precise value.
import numpy as np
x = 10
print(np.arctan(np.tan(x)))
When I change x to 2*x or 3*x, then the result is even more inaccurate.
I tried math.tan, math.atan but the result was the same.
Can someone please explain why it happens(which of the two functions is wrong), and under which condition one should be careful about using the arctangent and tangent functions?
three things to note:
in python (as in all programming languages i have ever looked at) trigonometric functions work with angles in radians i.e. the range [0, 2*pi) represents the 'full circle'
tan is periodic: tan(x) = tan(pi + x) (again note that this is in radians; in python tan(x) = tan(180 + x) will not be true!).
arctan returns a value in [-pi/2, pi/2).
in your example you fall back on the correct result in [-pi/2, pi/2):
import numpy as np
x = 10
print(np.arctan(np.tan(x))) # 0.575222039231
print(10 % (np.pi / 2)) # 0.5752220392306207
your function np.arctan(np.tan(x)) is equivalent to (the computationally less expensive)
def arctan_tan(x):
ret = x % np.pi
if ret > np.pi / 2:
ret -= np.pi
return ret
Given this function:
def f(x):
return (1-x**2)**m * ((1-x)/2)**n
where m and n are constants, let's say both 0.5 for the sake of an example.
I'm trying to use functions from scipy.optimize to solve for x given a value of y. I'm only interested in xvalues from -1 to 1. Plotting the function with
x = numpy.arange(0, 1, 0,1)
matplotlib.pyplot.plot(x, f(x))
shows that the function is a kind of distorted parabola covering the range about 0 to 0.65. So lets try solving it for y = 0.3:
def f(x):
return (1 - x**2)**m * ((1-x)/2)**n - 0.3
print(scipy.optimize.newton_krylov(f, 0.5))
0.6718791645800665
This looks about right for one of the possible solutions. But there are two. The second should be around -0.9. Try what I might for an initial guess, I can't get it to find this second solution. The Newton-Krylov method gives no convergence at all for xin < 0 but none of the solvers can find this second solution.
Am I missing something? What am I doing wrong?
The method converges at least for x=-0.9:
scipy.optimize.newton_krylov(f, -0.9)
#array(-0.9527983).
It diverges for x approximately in [-0.85...0.06].
This is because, newton_krylov uses the Jacobian of the function. This makes it a gradient decent method consequently your solutions always converge to a local minima. Furthermore, because your function is parabolic you have a very interesting option!
The first is to find the maxima of f(x) and split your search domain into to. Next you can make an initial guess in each domain and solve with newton_krylov.
def f(x):
# Here is our function
return (1-x**2)**m * ((1-x)/2)**n
def minf(x):
# Here is where we find an optima and split the domain
return -f(x)
def fy(x):
# This is where you want your y value target defined
return abs(f(x) - .3)
if __name__ == "__main__":
x = numpy.arange(-1., 1., 1e-3, dtype=float)
# pyplot.plot(x, f(x))
# pyplot.show()
minx = minimize(minf, 0.0)['x']
# Make an initial guess in each domain
a1 = minx - 1.6 * minx
a2 = minx + 1.6 * minx
print(newton_krylov(fy, a1))
print(newton_krylov(fy, a2))
The output then is:
[0.67187916]
[-0.95279992]
I'm trying to model a pursuit problem of bugs chasing one another in a 2 dimensional plane and I'm using SciPY.odeint to help me with this. With the following code, the model works however as the bugs get closer together the model breaks down and emits the excess work done on this call (perhaps wrong Dfun type) error.
import numpy as np
from scipy.integrate import odeint
def split_list(a_list):
half = len(a_list)//2
return a_list[:half], a_list[half:]
def diff(w, t):
x_points, y_points = split_list(w)
def abso(f, s):
return np.sqrt((x_points[f] - x_points[s])**2 + (y_points[f] - y_points[s])**2)
x_funct = [(x_points[i+1] - x_points[i]) / abso(i+1, i) for i in range(len(x_points) - 1)]
x_funct.append((x_points[0] - x_points[-1]) / abso(0,-1))
y_funct = [(y_points[i+1] - y_points[i]) / abso(i+1,i) for i in range(len(x_points) - 1)]
y_funct.append((y_points[0] - y_points[-1]) / abso(0,-1))
funct = x_funct + y_funct
return funct
def ode(tstart, tend, init_cond):
t = np.linspace(tstart, tend, step_size)
wsol = odeint(diff, init_cond, t)
sols = [wsol[:,i] for i in range(len(init_cond))]
x_sols, y_sols = split_list(sols)
return x_sols, y_sols, t, tend
bug_init_cond = [[-0.5, 1],
[0.5, 1],
[0.5, -1],
[-0.5, -1],]
amount_of_bugs = 4
step_size = 10000
x_sols, y_sols, t, tend = ode(0, 5, [bug_init_cond[i][j] for j in range(2) for i in range(amount_of_bugs)])
As I'm quite new with using the Scipy.odeint function, I was wondering if there is a solution to this excess work done? Thank-you for your time.
Your problem is that in the exact solution the paths meet at time t=1.48 to t=1.5. In an exact solution, you would get a division by zero error, with floating point noise that is "degraded" to a stiff situation where the step size is regulated down until the output time step requires more than mxstep=500 internal steps.
You could add conditions so that the right side is set to zero if the positions get to close. One quick hack to achieve that is to modify the distance function abso to
def abso(f, s):
return np.sqrt(1e-12+(x_points[f] - x_points[s])**2 + (y_points[f] - y_points[s])**2)
so that you never divide by zero, and for visible distances the perturbation is negligible.
I'm trying to implement euler's method to approximate the value of e in python. This is what I have so far:
def Euler(f, t0, y0, h, N):
t = t0 + arange(N+1)*h
y = zeros(N+1)
y[0] = y0
for n in range(N):
y[n+1] = y[n] + h*f(t[n], y[n])
f = (1+(1/N))^N
return y
However, when I try to call the function, I get the error "ValueError: shape <= 0". I suspect this has something to do with how I defined f? I tried inputting f directly when euler is called, but gave me errors related to variables not being defined. I also tried defining f as its own function, which gave me a division by 0 error.
def f(N):
for n in range(N):
return (1+(1/n))^n
(not sure if N was the appropriate variable to use here...)
The formula you are trying to use is not Euler's method, but rather the exact value of e as n approaches infinity wiki,
$n = \lim_{n\to\infty} (1 + \frac{1}{n})^n$
Euler's method is used to solve first order differential equations.
Here are two guides that show how to implement Euler's method to solve a simple test function: beginner's guide and numerical ODE guide.
To answer the title of this post, rather than the question you are asking, I've used Euler's method to solve usual exponential decay:
$\frac{dN}{dt} = -\lambda N$
Which has the solution,
$N(t) = N_0 e^{-\lambda t}$
Code:
import numpy as np
import matplotlib.pyplot as plt
from __future__ import division
# Concentration over time
N = lambda t: N0 * np.exp(-k * t)
# dN/dt
def dx_dt(x):
return -k * x
k = .5
h = 0.001
N0 = 100.
t = np.arange(0, 10, h)
y = np.zeros(len(t))
y[0] = N0
for i in range(1, len(t)):
# Euler's method
y[i] = y[i-1] + dx_dt(y[i-1]) * h
max_error = abs(y-N(t)).max()
print 'Max difference between the exact solution and Euler's approximation with step size h=0.001:'
print '{0:.15}'.format(max_error)
Output:
Max difference between the exact solution and Euler's approximation with step size h=0.001:
0.00919890254720457
Note: I'm not sure how to get LaTeX displaying properly.
Are you sure you are not trying to implement the Newton's method? Because Newton's method is used to approximate the roots.
In case you decide to go with Newton's method, here is a slightly changed version of your code that approximates the square-root of 2. You can change f(x) and fp(x) with the function and its derivative you use in your approximation to the thing you want.
import numpy as np
def f(x):
return x**2 - 2
def fp(x):
return 2*x
def Newton(f, y0, N):
y = np.zeros(N+1)
y[0] = y0
for n in range(N):
y[n+1] = y[n] - f(y[n])/fp(y[n])
return y
print Newton(f, 1, 10)
gives
[ 1. 1.5 1.41666667 1.41421569 1.41421356 1.41421356
1.41421356 1.41421356 1.41421356 1.41421356 1.41421356]
which are the initial value and the first ten iterations to the square-root of two.
Besides this a big problem was the usage of ^ instead of ** for powers which is a legal but a totally different (bitwise) operation in python.