root-finding algorithm for a complex polynomial equation in python - python

I am trying to solve for the following equation with a simple algorithm. I am not sure if the algorithm that I'm using is the best one or not but it is the only way that I could think of.
In this equation, everything other than P is known, and I am trying to solve for that. N is an array of counts, an i is the channel number. S(n) is the probability of having a certain n and C is binomial coefficient of (n, r). Pi is the probability in i channel and Pj is the probability in the previous channels with D distance to i. The code itself is not working but I believe that the main problem is in the way that I am trying to solve for it.
import numpy as np
import matplotlib.pyplot as plt
import math as ms
from scipy.misc import derivative
import scipy as sp
def next_guess(f, x):
slop = derivative(f, x, dx = 0.01)
return x - float(f(x))/slop
def my_newton(f, guess):
for i in range(30):
#print(guess)
guess = next_guess(f, guess)
return guess
def binomial(n, r):
dif = ms.factorial(n - r)
n = ms.factorial(n)
r = ms.factorial(r)
return (n/(r*dif))
def wrap_func(x, S = np.array([0.1, 0.5, 0.2, 0.1, 0.1]), D = 1, N = np.array([10, 15, 20, 1, 13])):
if type(x) == float:
z = np.zeros(1)
else:
z = np.zeros(x.shape[0])
N_tot = N.sum()
n_max = S.shape[0]
for i in range(z.shape[0]):
z[i] += my_newton(func(x, S = S, D = 1, N = N[i], n_max = n_max, N_tot = N_tot, i = i), i/100)
return z
def func(x, S = np.array([0.1, 0.5, 0.2, 0.1, 0.1]), D = 1, N = 0, n_max = 5, N_tot = 10, i = 0):
S_sum = 0
binom_sum = 0
y = 0
for n in range(n_max):
S_sum += S[n]
for r in range(n):
binom_sum += binomial(n, r)
y += S_sum * binom_sum * (x**r) * (1 - x - summ_x(x, D, i, S, N, n_max, N_tot))**(n-r)
return N_tot * y - N
def summ_x(x, D, i, S, N, n_max, N_tot):
j_min = max(i - D - 1, 0)
j_max = i - 1
x_values = 0
if i == 0:
return x_values
else:
for j in range(j_min, j_max):
x_values += func(x, S, D, N, n_max, N_tot, i)
return x_values
x = np.linspace(0, 1, 1000)
S = np.array([0.1, 0.5, 0.2, 0.1, 0.1])
N = np.random.choice(50, size = 1000)
print(my_newton(wrap_func, 0.1))
plt.plot(x, wrap_func(x, S = S, D = 1, N = N ))
plt.axhline(0, lw = 0.5, color = 'grey')
#plt.plot(my_newton(wrap_func, 1), wrap_func(my_newton(wrap_func, 1), S = S, D = 1, N = N), 'd')
plt.show()

Related

Alternatives for the 1D heat equation

I am trying to figure to find out an alternative way to rewrite
Initial and boundary condition for the 1 dimensional heat eqaution
I have the following examples for 1D
#Methodd used during classes
import math
import numpy as np
import matplotlib.pyplot as plt
#D, Nx, Nt, L, T = 1.0, 14, 100, 1.0, 0.1
D, Nx, Nt, L, T = 1.0, 20, 250, 1.0, 0.1
#D, Nx, Nt, L, T = 1.0, 40, 500, 1.0, 0.1
t = np.linspace(0, T, num=Nt+1, dtype = float)
x = np.linspace(0, L, num=Nx+1, dtype = float)
dx = x[1] - x[0]
dt = t[1] - t[0]
r = D*dt/ (dx*dx)
print('r = {}'.format(r))
assert r < 0.5
#u = np.zeros((Nx+1, Nt+1), dtype = float)
u = np.empty((Nx+1, Nt+1), dtype = float)
#initial condition
#u[:,0] = 4.0*x*(1-x)
#u[:,0] = 0.5(np.sign(x-0.4) + np.sign(0.6 - x))
#u[:,0] = np.where(x < 0.5, 2*x, 2*(x -1))
u[:,0] = np.where(x < 0.5, 0, 1)
#boundary conditon
u[0,:] = 0.0
u[Nx,:] = 0.0
#u[Nx,:] = 1.0
#iteration solution
for j in range (Nt):
#for i in range(1, Nx):
#u[i, j+1] = r*u[i - 1, j] + (1 -2r)*u[i, j] + r*u[i + 1, j]
#vectorization
u[1:-1,j+1] = r*u[:-2,j] + (1-2*r)*u[1:-1,j] + r*u[2:,j]
#visualization
print(u)
plt.title("1D heat equation")
plt.xlabel("time")
plt.ylabel("X")
plt.imshow(u[:,::3], cmap = "hot", interpolation = "nearest")
#plt.imshow(u[:,::3], cmap = "hot", interpolation = "bilinear")
#plt.imshow(u[:,::3], cmap = "hot", interpolation = "hamming")
#plt.imshow(u[:,::5], cmap = "hot", interpolation = "nearest")
As you could see I have different choices to pick up. But I would like to add some alternative initial and boundary conditions. The graphics I should get are like the following one:
Could anyone possibly suggest any alternative patterns for them? Thank you so much.

How to generate a multidimensional cube in Python

This program creates a cube of size Gridsize**3 with user choice of starting point and space between point (even if they are not function parameters there isn't difficult to implement).
import numpy as np
def CreateMap(Gridsize):
X = Y = Z = Gridsize
M = np.zeros(shape=(X*Y*Z, 3))
d_x = 5 / Gridsize # increment of the cube x dimension
d_y = 5 / Gridsize
d_z = 5 / Gridsize
x0 = -1.0
y0 = 1.0
z0 = 0
x = np.arange(x0, X * d_x, d_x, dtype=float)
y = np.arange(y0, Y * d_y, d_y, dtype=float)
z = np.arange(z0, Z * d_z, d_z, dtype=float)
g = 0
for i in range(X):
for j in range(Y):
for k in range(Z):
M[g, 0] = x[i]
M[g, 1] = y[j]
M[g, 2] = z[k]
g = g + 1
print(M)
return 0
I was wondering what was the best method to create an hyper cube of size Gridsize**n were n will also be user defined?
Check out np.meshgrid. Instead of your for loops, you can just do
M = np.stack(np.meshgrid(x, y, z))
If you guys have optimization advice...
import numpy as np
def CreateMap(Gridsize, x0, xf):
k = np.shape(x0)[0]
M = np.zeros(shape=(Gridsize**k, k))
d_x = np.zeros(k)
for i in range(k):
d = 0
j = 0
d_x[i] = (xf[i] - x0[i]) / (Gridsize - 1) # increment of the cube x dimension
x = np.arange(x0[i], xf[i]+d_x[i], d_x[i], dtype=float)
for v in range(Gridsize ** (k - i - 1)):
for j in range(Gridsize):
temp = x[j]
for z in range(Gridsize ** i):
M[d, i] = temp
d = d + 1
print(M)
return 0
x0 = np.array([-1, 0, 1])
xf = np.array([10, 2, 5])
CreateMap(4, x0, xf)

Python Scipy Minimize Not Working

I try to minimize the vectors x,y, but they just satisfied constraints with no work for minimizing.
e.g:
input init: x=[0.2,0.3,0.5] (sum of elements is 1) ,feedback: res.x=[0.,0.3,0.5],it hasn't changed at all!
# -*- coding:utf8-*-
import random
import numpy as np
from scipy import optimize
import networkx as nx
import matplotlib.pyplot as plt
def Ud(x, X, Aj, G, p):
lost = G.node[Aj[-1]]["weight"]
Aj = Aj[:-1]
P = 1
sum = 0
for xi in x:
for Xi in X:
N = set(Aj).intersection(set(Xi))
# N=[random.randint(90,120) for _ in range(0,1)]
for n in N:
P *= (1 - p[n - 1])
sum += xi * P
P = 1
return -lost * sum
### objective function for defenders ###
def min_Ud(x, X, A, G, p):
min = float("inf")
for Aj in A:
temp_min = Ud(x, X, Aj, G, p)
if temp_min < min:
min = temp_min
return -min
### objective function for attackers ###
def Ua(a, X, A, G, p):
sum = 0
P = 1
for aj, Aj in a, A:
for Xi in X:
N = set(Aj[:-1]).intersection(set(Xi))
for n in N:
P *= (1 - p[n - 1])
sum += G.node[Aj[-1]]["weight"] * aj * P
P = 1
return sum
### fun for LP ###
def coreLP(X, A, G, p):
x0 = np.array([0.7, 0.2, 0.1])
a0 = np.array([0.5, 0.2, 0.3])
x_res = float("inf")
a_res = float("inf")
def c1(x):
return x.sum() - 1
cons = ({'type': 'eq', 'fun': c1})
Ud_star = optimize.minimize(min_Ud, x0, args=(X, A, G, p), constraints=cons, bounds=((0, 1), (0, 1), (0, 1)))
Ua_star = optimize.minimize(min_Ud, a0, args=(X, A, G, p), constraints=cons, bounds=((0, 1), (0, 1), (0, 1)))
print Ud_star
print Ua_star
return Ud_star.x, Ua_star.x

Lotka-Volterra equations(predator prey) using Runge-Kutta in Python

I am trying to write a program using the Lotka-Volterra equations for predator-prey interactions. Solve Using ODE's:
dx/dt = a*x - B*x*y
dy/dt = g*x*y - s*y
Using 4th order Runge-Kutta method
I need to plot a graph showing both x and y as a function of time from t = 0 to t=30.
a = alpha = 1
b = beta = 0.5
g = gamma = 0.5
s = sigma = 2
initial conditions x = y = 2
Here is my code so far but not display anything on the graph. Some help would be nice.
#!/usr/bin/env python
from __future__ import division, print_function
import matplotlib.pyplot as plt
import numpy as np
def rk4(f, r, t, h):
""" Runge-Kutta 4 method """
k1 = h*f(r, t)
k2 = h*f(r+0.5*k1, t+0.5*h)
k3 = h*f(r+0.5*k2, t+0.5*h)
k4 = h*f(r+k3, t+h)
return (k1 + 2*k2 + 2*k3 + k4)/6
def f(r, t):
alpha = 1.0
beta = 0.5
gamma = 0.5
sigma = 2.0
x, y = r[2], r[2]
fxd = x*(alpha - beta*y)
fyd = -y*(gamma - sigma*x)
return np.array([fxd, fyd], float)
tpoints = np.linspace(0, 30, 0.1)
xpoints = []
ypoints = []
r = np.array([2, 2], float)
for t in tpoints:
xpoints += [r[2]]
ypoints += [r[2]]
r += rk4(f, r, t, h)
plt.plot(tpoints, xpoints)
plt.plot(tpoints, ypoints)
plt.xlabel("Time")
plt.ylabel("Population")
plt.title("Lotka-Volterra Model")
plt.savefig("Lotka_Volterra.png")
plt.show()
A simple check of your variable tpoints after running your script shows it's empty:
In [7]: run test.py
In [8]: tpoints
Out[8]: array([], dtype=float64)
This is because you're using np.linspace incorrectly. The third argument is the number of elements desired in the output. You've requested an array of length 0.1.
Take a look at np.linspace's docstring. You won't have a problem figuring out how to adjust your code.
1) define 'h' variable.
2) use
tpoints = np.arange(30) #array([0, 1, 2, ..., 30])
not
np.linspace()
and don't forget to set time step size equal to h:
h=0.1
tpoints = np.arange(0, 30, h)
3) be careful with indexes:
def f(r,t):
...
x, y=r[0], r[1]
...
for t in tpoints:
xpoints += [r[0]]
ypoints += [r[1]]
...
and better use .append(x):
for t in tpoints:
xpoints.append(r[0])
ypoints.append(r[1])
...
Here's tested code for python 3.7 (I've set h=0.001 for more presize)
import matplotlib.pyplot as plt
import numpy as np
def rk4(r, t, h): #edited; no need for input f
""" Runge-Kutta 4 method """
k1 = h*f(r, t)
k2 = h*f(r+0.5*k1, t+0.5*h)
k3 = h*f(r+0.5*k2, t+0.5*h)
k4 = h*f(r+k3, t+h)
return (k1 + 2*k2 + 2*k3 + k4)/6
def f(r, t):
alpha = 1.0
beta = 0.5
gamma = 0.5
sigma = 2.0
x, y = r[0], r[1]
fxd = x*(alpha - beta*y)
fyd = -y*(gamma - sigma*x)
return np.array([fxd, fyd], float)
h=0.001 #edited
tpoints = np.arange(0, 30, h) #edited
xpoints, ypoints = [], []
r = np.array([2, 2], float)
for t in tpoints:
xpoints.append(r[0]) #edited
ypoints.append(r[1]) #edited
r += rk4(r, t, h) #edited; no need for input f
plt.plot(tpoints, xpoints)
plt.plot(tpoints, ypoints)
plt.xlabel("Time")
plt.ylabel("Population")
plt.title("Lotka-Volterra Model")
plt.savefig("Lotka_Volterra.png")
plt.show()
You can also try to plot "cycles":
plt.xlabel("Prey")
plt.ylabel("Predator")
plt.plot(xpoints, ypoints)
plt.show()
https://i.stack.imgur.com/NB9lc.png

Fitting a polynomial function for a vector field in python

At first, thank you everybody for the amazing work on stackoverflow... you guys are amazing and have helped me out quite some times already. Regarding my problem: I have a series of vectors in the format (VectorX, VectorY, StartingpointX, StartingpointY)
data = [(-0.15304757819399128, -0.034405679205349315, -5.42877197265625, 53.412933349609375), (-0.30532995491023485, -0.21523935094046465, -63.36669921875, 91.832427978515625), (-0.15872430479453215, -0.077999419482978283, -67.805389404296875, 81.001983642578125), (-0.36415549211687903, -0.33757147194808113, -59.015228271484375, 82.976226806640625), (0.0, 0.0, 0.0, 0.0), (-0.052973530805275004, 0.098212384392411423, 19.02667236328125, -13.72125244140625), (-0.34318724086483599, 0.17123742336019632, 80.0394287109375, 108.58499145507812), (0.19410169197834648, -0.17635303976555861, -55.603790283203125, -76.298828125), (-0.38774018337716143, -0.0824692384322816, -44.59942626953125, 68.402496337890625), (0.062202543524108478, -0.37219011831012949, -79.828826904296875, -10.764404296875), (-0.56582988168383963, 0.14872365390732512, 39.67657470703125, 97.303192138671875), (0.12496832467900276, -0.12216653754859408, 24.65948486328125, -30.92584228515625)]
When I plot the vectorfield it looks like this:
import numpy as np
import matplotlib.pyplot as plt
def main():
# Format Data...
numdata = len(data)
x = np.zeros(numdata)
y = np.zeros(numdata)
u = np.zeros(numdata)
v = np.zeros(numdata)
for i,el in enumerate(data):
x[i] = el[2]
y[i] = el[3]
# length of vector
z[i] = math.sqrt(el[0]**2+el[1]**2)
u[i] = el[0]
v[i] = el[1]
# Plot
plt.quiver(x,y,u,v )
# showing the length with color
plt.scatter(x, y, c=z)
plt.show()
main()
I want to create a polynomial function to fit a continous vector field for the whole area. After some research I found the following functions for fitting polynoms in two dimensions. The problem is, that it only accepts one value for the value that is fitted.
def polyfit2d(x, y, z, order=3):
ncols = (order + 1)**2
G = np.zeros((x.size, ncols))
ij = itertools.product(range(order+1), range(order+1))
for k, (i,j) in enumerate(ij):
G[:,k] = x**i * y**j
m, _, _, _ = np.linalg.lstsq(G, z)
return m
def polyval2d(x, y, m):
order = int(np.sqrt(len(m))) - 1
ij = itertools.product(range(order+1), range(order+1))
z = np.zeros_like(x)
for a, (i,j) in zip(m, ij):
z += a * x**i * y**j
return z
Also when I tried to fit the one dimensional length of the vectors, the values returned from the polyval2d were completely off. Does anybody know a method to get a fitted function that will return a vector (x,y) for any point in the grid?
Thank you!
A polynomial to fit a 2-d vector field will be two bivariate polynomials - one for the x-component and one for the y-component. In other words, your final polynomial fitting will look something like:
P(x,y) = ( x + x*y, 1 + x + y )
So you will have to call polyfit2d twice. Here is an example:
import numpy as np
import itertools
def polyfit2d(x, y, z, order=3):
ncols = (order + 1)**2
G = np.zeros((x.size, ncols))
ij = itertools.product(range(order+1), range(order+1))
for k, (i,j) in enumerate(ij):
G[:,k] = x**i * y**j
m, _, _, _ = np.linalg.lstsq(G, z)
return m
def fmt1(x,i):
if i == 0:
return ""
elif i == 1:
return x
else:
return x + '^' + str(i)
def fmt2(i,j):
if i == 0:
return fmt1('y',j)
elif j == 0:
return fmt1('x',i)
else:
return fmt1('x',i) + fmt1('y',j)
def fmtpoly2(m, order):
for (i,j), c in zip(itertools.product(range(order+1), range(order+1)), m):
yield ("%f %s" % (c, fmt2(i,j)))
xs = np.array([ 0, 1, 2, 3] )
ys = np.array([ 0, 1, 2, 3] )
zx = np.array([ 0, 2, 6, 12])
zy = np.array([ 1, 3, 5, 7])
mx = polyfit2d(xs, ys, zx, 2)
print "x-component(x,y) = ", ' + '.join(fmtpoly2(mx,2))
my = polyfit2d(xs, ys, zy, 2)
print "y-component(x,y) = ", ' + '.join(fmtpoly2(my,2))
In this example our vector field is:
at (0,0): (0,1)
at (1,1): (2,3)
at (2,2): (6,5)
at (3,3): (12,7)
Also, I think I found a bug in polyval2d - this version gives more accurate results:
def polyval2d(x, y, m):
order = int(np.sqrt(len(m))) - 1
ij = itertools.product(range(order+1), range(order+1))
z = np.zeros_like(x)
for a, (i,j) in zip(m, ij):
z = z + a * x**i * y**j
return z

Categories

Resources