passing numpy ndarray as inputs of a fsolve function - python

I want to numerically solve a system of nonlinear equations and pass numpy ndarrays as inputs. Consider the arbitrary code below:
import numpy as np
from scipy.optimize import fsolve
def eqs(A, B, C, D):
eq1 = (A - B * np.sin(C)).tolist()
eq2 = [5 * B + D * np.sum(A * np.cos(C))]
return eq1 + eq2
n = 3
A = np.zeros((n))
A0 = np.random.rand(n)
B = 0.0
B0 = np.random.rand(1)[0]
C = np.random.rand(n)
D = np.random.rand(1)[0]
sol = fsolve(func = eqs, x0 = [A0, B0], args = [C, D])
which leads to
missing required positional arguments
error and changing the function to:
def eqs(A, B, C, D):
eq1 = A - B * np.sin(C)
eq2 = C[0] * B + D * np.sum(A * np.cos(C))
return [eq1, eq2]
also doesn't help. However, I highly doubt that the error has anything to do with passing ndarrays. One approach could be to change all the ndarrays to python lists back and forth. But then I would not be able to use numpy's vectorized functions like np.sin()...
I would appreciate if you could help me know how this should be done.
P.S. Equations above are just arbitrary and they may not have solutions at all.

Check if this solve your equation:
import numpy as np
from scipy.optimize import fsolve
def eqs(X, Y):
A, B = X[:3], X[3]
C, D = Y[:3], Y[3]
eq1 = A - B * np.sin(C)
eq2 = C[0] * B + D * np.sum(A * np.cos(C))
return np.append(eq1, eq2)
n = 3
A = np.zeros((n))
A0 = np.random.rand(n)
B = 0.0
B0 = np.random.rand(1)[0]
C = np.random.rand(n)
D = np.random.rand(1)[0]
sol = fsolve(func = eqs, x0 = np.append(A0, B0), args = np.append(C, D))
sol
Output:
array([ 0.e+000, -1.e-323, 5.e-324, -1.e-323])

These scipy.optimize functions require a function with a signature like
f(x, *args)
x is a array (often 1d) that the solver will vary; args is a tuple of arguments that are just passed through from the outside.
Change your eqs to fit this pattern
In [11]: def eqs(X, C, D):
...: A, B = X[:-1], X[-1]
...: eq1 = (A - B * np.sin(C)).tolist()
...: eq2 = [5 * B + D * np.sum(A * np.cos(C))]
...: return eq1 + eq2
...: n = 3
...: A0 = np.random.rand(n)
...: B0 = np.random.rand(1)
...:
...: C = np.random.rand(n)
...: D = np.random.rand(1)
Make a test call to eqs:
In [12]: eqs(np.concatenate((A0,B0)),C,D)
Out[12]:
[-0.28460532658572657,
-0.03649115738682615,
0.7625781482352719,
array([5.46430853])]
Now try it in the fsolve:
In [13]: fsolve(eqs, np.concatenate((A0,B0)), args=(C,D))
Out[13]: array([0., 0., 0., 0.])

Related

Numpy to solve multi-variable algebraic function

Let's assume we know the following:
a = 1
b = 4
c = 7
d = 2
e = 2
f = 9
With these six variables, we can solve for X, Y, and Z as follows:
X = (b - a) / (d + e)
Y = 2 * np.sin(X/2) * ((c / X) + f)
Z = 2 * np.sin(X/2) * ((a / X) + d)
print(X)
print(Y)
print(Z)
0.75
13.42999273315508
2.4418168605736503
Now, let's flip things around and assume that we're given the values of X, Y, and Z, as well as d, e, and f.
How would we solve for the values of a, b, and c? My algebra is shaky. Is this something that Numpy can handle?
Thanks!
Numpy, no. (Or rather, not as easily, or accurately.)
Sympy, yes.
Declare a, b and c as symbols.
Create expressions that should equal to zero (by moving the left hand side of the equation to the right hand side and changing the sign).
Use sympy.sin instead of math.sin or np.sin.
Use sympy.solve to get the solution of the system.
import sympy
from sympy.abc import a, b, c
X = 0.75
Y = 13.42999273315508
Z = 2.4418168605736503
d = 2
e = 2
f = 9
e1 = (b - a) / (d + e) - X
e2 = 2 * sympy.sin(X/2) * ((c / X) + f) - Y
e3 = 2 * sympy.sin(X/2) * ((a / X) + d) - Z
sympy.solve([e1, e2, e3])
# => {a: 1.00000000000000, b: 4.00000000000000, c: 7.00000000000000}
Solving equations with unknown variables can be done in Sympy.
from sympy import symbols, solve, Eq, sin
a, b, c, d, e, f, X, Y, Z = symbols("a b c d e f X Y Z")
eqns = [
Eq(X, (b - a) / (d + e)),
Eq(Y, 2 * sin(X / 2) * ((c / X) + f)),
Eq(Z, 2 * sin(X / 2) * ((a / X) + d)),
]
assignments = {a: 1, b: 4, c: 7, d: 2, e: 2, f: 9}
print(solve([eq.subs(assignments) for eq in eqns], [X, Y, Z]))
Output:
[(3/4, 110*sin(3/8)/3, 20*sin(3/8)/3)]
To solve for a, b, c just replace X, Y, Z in solve and add their values in the assignments dict.

sympy solving matrix equations as empty?

trying to solve A # B = 0 type of equation in here, A is a known matrix and B matrix contains unknowns, But code gives [] output, with subs(b,1) true solutions must be [0.618,1.0] and [-1.62,1.0] thanks.
from scipy import linalg
import numpy as np
import math
from sympy import *
import matplotlib.pyplot as plt
M = np.diag([2,2]) # ton
K = np.array([[600,-300],
[-300,300]
])
M_inv = linalg.inv(M)
la, v = linalg.eig(M_inv # K)
wn = np.sqrt(la)
wn.sort()
def matris(w):
A = K - w**2*M
return A
matris_1 = matris(wn[0])
matris_2 = matris(wn[1])
a, b, c, d, e, f = symbols('a,b,c,d,e,f', commutative=False)
fi_matris = Matrix([a, b])
def mod(matris_n):
eq1 = matris_n # fi_matris
eq2 = eq1.subs(b,1)
eq3 = Eq(eq2,0)
solv1 = solve([eq3],(fi_matris))
return solv1
mod_1 = mod(matris_1)
mod_2 = mod(matris_2)
after putting a zeros vector my equation to be solved is:
Eq(Matrix([
[485.410196624968*a - 300.0],
[185.410196624968 - 300.0*a]]), Matrix([
[0],
[0]]))
so a must be 0.618 and b is already set as 1.0
but gives []
btw i edited one of the functions to get that:
zeros_matrice = zeros(2,1)
def mod(matris_n):
eq1 = matris_n # fi_matris
eq2 = eq1.subs(b,1)
eq3 = Eq(eq2,zeros_matrice)
solv1 = solve(eq3)
return solv1
to be more precise eq above is eq3 in this case
i again edited the function as just to solve one row:
def mod(matris_n):
eq1 = matris_n[:1] # fi_matris
eq2 = eq1.subs(b,1)
eq3 = Eq(eq2,0)
solv1 = solve(eq3)
return solv1,eq3
mod_1 = mod(matris_1)
mod_2 = mod(matris_2)
in this case output is ([], False)

How to find point where an unlinear function equals zero

I have an unlinear function from neuroscience. ad is a parameter and t is the time.
def alpha(t, ad):
if t < 0:
return 0
else:
return pow(ad, 2) * t * np.exp(-1 * ad * t)
With ad = 2 It rises from x = 0, increases to 0.7 and becomes near 0 at x=3.
I can find when this function is near or equal to 0 by iterating by intervals. But I just need to know where the function is near or equal to 0. I was wondering if there is any way to find it without iterating ex) intersecting with x = 0 function, or when derivative equals 0 ...
I presume that you want to find when the derivative is equal to zero. You can do that with sympy:
In [12]: from sympy import exp, Symbol, nsolve
In [13]: ad = 2
In [14]: t = Symbol('t')
In [15]: f = pow(ad, 2) * t * exp(-1 * ad * t)
In [16]: f
Out[16]:
-2⋅t
4⋅t⋅ℯ
In [17]: f.diff(t)
Out[17]:
-2⋅t -2⋅t
- 8⋅t⋅ℯ + 4⋅ℯ
In [18]: solve(f.diff(t), t)
Out[18]: [1/2]
EDIT: Your answer below suggests a different question from the one in the OP so I'll update this:
You want to find the zeros of this:
In [5]: ad = Symbol('ad')
In [6]: t = Symbol('t')
In [7]: epsilon = Symbol('epsilon')
In [8]: f = pow(ad, 2) * t * exp(-1 * ad * t) - epsilon
In [9]: f
Out[9]:
2 -ad⋅t
ad ⋅t⋅ℯ - ε
We can solve this analytically using solve:
In [10]: sol, = solve(f, t)
In [11]: sol
Out[11]:
⎛-ε ⎞
-W⎜───⎟
⎝ ad⎠
────────
ad
This answer is given in terms of the Lambert W function. You can substitute for ad and epsilon to get the answer for any particular values:
In [12]: sol.subs({ad:2, epsilon:0.01})
Out[12]: 0.00251259459155665
This is giving you the root near zero though because it's branch W0 of the Lambert W function. The other root is given in by branch W_{-1} and is
In [32]: -LambertW(-epsilon/ad, -1)/ad
Out[32]:
⎛-ε ⎞
-W⎜───, -1⎟
⎝ ad ⎠
────────────
ad
In [28]: (-LambertW(-epsilon/ad, -1)/ad).subs({ad:2, epsilon:0.01}).n()
Out[28]: 3.64199856754954
If you just want to solve for these numerically then you can use nsolve:
In [29]: nsolve(f.subs({ad:2, epsilon:0.01}), t, 0)
Out[29]: 0.00251259459155665
In [30]: nsolve(f.subs({ad:2, epsilon:0.01}), t, 1)
Out[30]: 3.64199856754954
I was able to find a solution using Oscar's answer.
The function was exponential, so it never reaches 0 after 0
I just pulled the function a bit with a minus epsilon
(epsilon is user defined)
There will be two zeros, and I just need the second one.
from sympy import exp, Symbol, solve
epsilon = 0.01
ad = 2
t = Symbol('t')
f = pow(ad, 2) * t * exp(-1 * ad * t) - epsilon
print(solve([f], t, dict=True, quick=True))
#print(solve([t > 0, f], t, dict=True, quick=True)) i get an error if i use this
But this solution to finding a near-zero x took much more time than just iterating by interval of 0.01 over the function.
from sympy import exp, Symbol, solve, Piecewise
import numpy as np
epsilon = 0.01
ad = 2
t = Symbol('t')
f = pow(ad, 2) * t * exp(-1 * ad * t) - epsilon
#print(solve([f], t, dict=True, quick=True))
def alpha(t, ad):
if t < 0:
return 0
else:
return pow(ad, 2) * t * np.exp(-1 * ad * t)
def find(function, farg, arange, epsilon):
xs = []
for x in arange:
if function(x, **farg) < epsilon:
xs.append(x)
return xs
if __name__ == "__main__":
import timeit
print(timeit.timeit("solve([f], t, dict=True)",
setup="from __main__ import solve, f, t",
number=100))
print(timeit.timeit("solve([f], t, dict=True, quick=True)",
setup="from __main__ import solve, f, t",
number=100))
print(timeit.timeit("find(alpha, {'ad':ad}, np.arange(0, 4, 0.01), 0.01)",
setup="from __main__ import find, alpha, ad , t, f, np",
number=100))
Outputs
24.860103617
24.020882552
0.10911201300000073

Simplify solution for Symbolic solver for system of equations in Python (with symbolic output)

I have the following system of equations :
-2yz = a
-2xy = b
-x^2 + y^2 - z^2 = c
How can I simplify the solution for these equations using SymPy? x, y, z are unknowns. I have the following script:
from sympy import *
x, y, z = var('x y z')
a, b, c = var('a b c')
E1 = -2 * y * z - a
E2 = -2 * x * y - b
E3 = -x**2 + y ** 2 - z ** 2 - c
sols = solve([E1, E2, E3], [x, y, z])
The simplifies solution is not really palatable. Any idea?
You might consider running cse over your solutions. I will let you see what the replacments are, but here is the result:
>>> r, e = cse(flatten(sols))
>>> reshape(e, (3,)) # restore tuples of 3 solutions
[
(x1*x9, -x11*x13, x9),
(-x1*x13, x11*x9, -x13),
(-x16, x12*x17, -x15),
(x16, x17*x8, x15)]

Need help solving a second order non-linear ODE in python

I don't really know where to start with this problem, as I haven't had much experience with this but it is required to solve this part of the project using a computer.
I have a 2nd order ODE which is:
m = 1220
k = 35600
g = 17.5
a = 450000
and b is between 1000 and 10000 with increments of 500.
x(0)= 0
x'(0)= 5
m*x''(t) + b*x'(t) + k*x(t)+a*(x(t))^3 = -m*g
I need to find the smallest b such that the solution is never positive. I know what the graph should look like, but I just don't know how to use odeint to get a solution to the differential equation.
This is the code I have so far:
from numpy import *
from matplotlib.pylab import *
from scipy.integrate import odeint
m = 1220.0
k = 35600.0
g = 17.5
a = 450000.0
x0= [0.0,5.0]
b = 1000
tmax = 10
dt = 0.01
def fun(x, t):
return (b*x[1]-k*x[0]-a*(x[0]**3)-m*g)*(1.0/m)
t_rk = arange(0,tmax,dt)
sol = odeint(fun, x0, t_rk)
plot(t_rk,sol)
show()
Which doesn't really produce much of anything.
Any thoughts? Thanks
To solve a second-order ODE using scipy.integrate.odeint, you should write it as a system of first-order ODEs:
I'll define z = [x', x], then z' = [x'', x'], and that's your system! Of course, you have to plug in your real relations:
x'' = -(b*x'(t) + k*x(t) + a*(x(t))^3 + m*g) / m
becomes:
z[0]' = -1/m * (b*z[0] + k*z[1] + a*z[1]**3 + m*g)
z[1]' = z[0]
Or, just call it d(z):
def d(z, t):
return np.array((
-1/m * (b*z[0] + k*z[1] + a*z[1]**3 + m*g), # this is z[0]'
z[0] # this is z[1]'
))
Now you can feed it to the odeint as such:
_, x = odeint(d, x0, t).T
(The _ is a blank placeholder for the x' variable we made)
In order to minimize b subject to the constraint that the maximum of x is always negative, you can use scipy.optimize.minimize. I'll implement it by actually maximizing the maximum of x, subject to the constraint that it remains negative, because I can't think of how to minimize a parameter without being able to invert the function.
from scipy.optimize import minimize
from scipy.integrate import odeint
m = 1220
k = 35600
g = 17.5
a = 450000
z0 = np.array([-.5, 0])
def d(z, t, m, k, g, a, b):
return np.array([-1/m * (b*z[0] + k*z[1] + a*z[1]**3 + m*g), z[0]])
def func(b, z0, *args):
_, x = odeint(d, z0, t, args=args+(b,)).T
return -x.max() # minimize negative max
cons = [{'type': 'ineq', 'fun': lambda b: b - 1000, 'jac': lambda b: 1}, # b > 1000
{'type': 'ineq', 'fun': lambda b: 10000 - b, 'jac': lambda b: -1}, # b < 10000
{'type': 'ineq', 'fun': lambda b: func(b, z0, m, k, g, a)}] # func(b) > 0 means x < 0
b0 = 10000
b_min = minimize(func, b0, args=(z0, m, k, g, a), constraints=cons)
I don't think you can solve your problem as stated: your initial conditions, with x = 0 and x' > 0 imply that the solution will be positive for some values very close to the starting point. So there is no b for which the solution is never positive...
Leaving that aside, to solve a second order differential equation, you first need to rewrite it as a system of two first order differential equations. Defining y = x' we can rewrite your single equation as:
x' = y
y' = -b/m*y - k/m*x - a/m*x**3 - g
x[0] = 0, y[0] = 5
So your function should look something like this:
def fun(z, t, m, k, g, a, b):
x, y = z
return np.array([y, -(b*y + (k + a*x*x)*x) / m - g])
And you can solve and plot your equations doing:
m, k, g, a = 1220, 35600, 17.5, 450000
tmax, dt = 10, 0.01
t = np.linspace(0, tmax, num=np.round(tmax/dt)+1)
for b in xrange(1000, 10500, 500):
print 'Solving for b = {}'.format(b)
sol = odeint(fun, [0, 5], t, args=(m, k, g, a, b))[..., 0]
plt.plot(t, sol, label='b = {}'.format(b))
plt.legend()

Categories