How to solve symbolic equations on numpy arrays? - python

I try to solve an equation with solve from Sympy. But my approach doesn't work as desired.
My equation : 0.00622765954483725 = (x * 24.39 * 0.921107170819325) / 143860432.178345.
My code :
from sympy import symbols, solve
import numpy as np
x = symbols('x')
sol = solve((np.array([[x],[x]]) * np.array([[24.39],[293.6]]) * np.array([[0.921107170819325],[1]])) / np.array([[143860432.178345],[143860432.178345]]) - np.array([[0.00622765954483725],[0.0089267519953503]]))
I had success with a linear expression, but I have a DataFrame and I want to solve all data at the same time.
from sympy import symbols, solve
x = symbols('x')
sol = solve((x * 24.39 * 0.921107170819325) / 143860432.178345 - 0.00622765954483725)

Numpy doesn't understand about sympy's symbols, nor does sympy understand about numpy arrays. The only way to make them work together, is with sympy's lambdify which can convert a symbolic sympy expression to a numpy function. In your case, you first need to create a symbolic solution, lambdify it, and call it on your arrays:
from sympy import symbols, solve, Eq, lambdify
a, b, c, d = symbols('a b c d', real=True)
x = symbols('x')
sol = solve(Eq(x * a * b / c, d), x) # solve returns a list of solutions, in this case a list with just one element
np_sol = lambdify((a, b, c, d), sol[0]) # convert the first solution to a (numpy) function
# everything before is only sympy, everything from here is only numpy
import numpy as np
a_np = np.array([[24.39], [293.6]])
b_np = np.array([[0.921107170819325], [1]])
c_np = np.array([[143860432.178345], [143860432.178345]])
d_np = np.array([[0.00622765954483725], [0.0089267519953503]])
np_sol(a_np, b_np, c_np, d_np)
Result:
array([[39879.],
[ 4374.]])

Related

Sympy dsolve with plots

I am solving an ODE with Sympy. The equation is
ODE
To solve it, I used this little code, which returns this result.
from sympy import *
from numpy import *
import matplotlib.pyplot as plt
x = symbols('x')
y = Function('y')
f = y(x)
print(f)
edo = Eq(f.diff()+3*x**2*f, 6*x**2)
print(edo)
edoSolve = dsolve(edo, f)
print(edoSolve)
C1*exp(-x**3) + 2
My question is, how can I plot the result with x being a range from 0 to 10?
Firstly it's problematic to combine these two lines:
from sympy import *
from numpy import *
These two libraries define many functions with the same names and mixing those together will lead to problems. For clarity it is better to do something like:
import sympy as sym
import numpy as np
You can only plot a sympy expression if you give numbers for all of the symbols apart from the one that you want to plot against (i.e. x in this example). That means that you need to have a concrete value for the integration constant C1. You can get that by giving an initial conditions (ics) argument to dsolve. Also since dsolve returns an equation you need to choose a side of the equation as the expression that you want to plot. Having done that the sym.plot function will do precisely what you ask for:
In [10]: import sympy as sym
In [11]: sol = sym.dsolve(edo, f, ics={f.subs(x, 0): 1})
In [12]: sol
Out[12]:
3
-x
y(x) = 2 - ℯ
In [13]: sym.plot(sol.rhs, (x, 0, 10))
Out[13]: <sympy.plotting.plot.Plot at 0x7f346de1caf0>
If you want to show solutions for multiple values for C1 together, you could append plots:
from sympy import symbols, Function, Eq, dsolve, plot
x = symbols('x')
y = Function('y')
f = y(x)
edo = Eq(f.diff() + 3 * x ** 2 * f, 6 * x ** 2)
edoSolve = dsolve(edo, f)
plot1 = plot(show=False)
for c1 in range(-5, 6):
plotc1 = plot(edoSolve.subs('C1', c1).rhs, (x, 0, 10), show=False)
plot1.append(plotc1[0])
plot1.show()

How to substitute an equation in python?

from sympy import symbols, Eq, solve, sin, sqrt
x = symbols('x')
D = symbols('d')
C = symbols('c')
eq1 = 2*sin(x)+sqrt(1-sin^2(x))+D*sin(x/2)-sin(2*x)-1-C
sol = solve(eq1)
print(sol)
Actually in the equation eq1=0. And I was trying to find a function for x which I couldn't find by mathematics. So I was thinking if it is possible in Python. My friend was saying that we actually deal with numbers in Python so he said it would be good if he can get some value of x. In that equation C and D is constant. He was saying that they are height. So we can consider that C,D=1 to 1000 (we can choose whatever we wish). Is there really possible way to substitute that function to find a value of x?
You can use fsolve to numerically solve the non-linear equation. The subs attribute of a sympy expression can be used to substitute a value to a variable.
from sympy import symbols, Eq, solve, sin, sqrt
from scipy.optimize import fsolve
x = symbols('x')
D = symbols('d')
C = symbols('c')
eq1 = 2*sin(x)+sqrt(1-(sin(x))**2)+D*sin(x/2)-sin(2*x)-1-C
values = {
C: 500,
D: 1000
}
eq1_in_x = eq1.subs(values)
def f(y):
return float(eq1_in_x.subs(x,y[0]))
sol = fsolve(f,1) # Here, 1 is an initial guess.
print(sol)
Outout:
[1.04635456]
So, 1.04635456 is a value of x that satisfies the equation with C and D values being 500 and 1000, respectively.
Take a look at sympy tutorial: https://docs.sympy.org/latest/tutorial/index.html
also Itk this should solve your problem: With #Oscar Benjamin advice:
from sympy import nsolve, sin, sqrt
from sympy.abc import x, C, D
eq1 = 2*sin(x)+sqrt(1-sin(x)**2)+C*sin(x/2)-sin(2*x)-1-D
sol = nsolve(eq1.subs({C: C_value, D: D_value}, x0)
print(sol)
x0 is the initialization of x, depending on the value of x0 you can end with different value of x verifying eq = 0.

Derivative and how to convert symbolic expression of it

I need to obtain a derivative to use it later in numerical calculations. And my code doesn't work at all. I tried to use lambdify but the error is "can't convert symbols int". I read other answers for similar questions but it still doesn't work.
import numpy as np
from scipy.integrate import odeint
from scipy.integrate import quad
from scipy.integrate import solve_bvp as bvp
import matplotlib.pyplot as plt
from scipy.special import genlaguerre as L
from scipy.special import gamma as G
from math import factorial
from math import sqrt
import sympy as sym
from sympy.utilities.lambdify import lambdify
mp = 938.2720813
mn = 939.5654133
mu = (mn + mp)/4
hbar = 197.3270533
h2m = hbar**2/(2*mu)
V0 = 20
Rv = 1.5
Q0 = 1.5
Rq = 4.5
EIm = 0.3
ERe = 1
V = lambda r : -V0*np.exp(-r/Rv)
Q = lambda r : -Q0*np.exp(-r/Rq)
chi = lambda r, l : sqrt(factorial(l)*beta**3/(G(3 + l))) * r * L(l,2)(beta * r) * np.exp(- beta * r / 2)
r, l, beta = sym.symbols('r, l, beta')
def chifD(r, l, beta):
return sqrt(factorial(l)*beta**3/(G(3 + l))) * r * L(l,2)(beta * r) * np.exp(- beta * r / 2)
def chiD(r, l, beta):
return sym.diff(chifD(r ,l, beta), r)
print(chiD(r, l, beta))
chiLambdified = lambdify(((r,l, beta),),chiD(r,l, beta),"numpy")
print(chiD(1, 1, 1))
I'm pretty sure you're mixing modules you shouldn't. I kept modifying your chi function until I got something that works. Nothing short of removing all math and scipy functions returned something that wasn't a TypeError.
# works with sympy sqrt.
chi = lambda r, l : sym.sqrt(l*r)
print(chi(r,l))
# doesn't work with math or numpy sqrt.
chi = lambda r, l : math.sqrt(l*r)
print(chi(r,l))
If you want to use functions, you'll have to use the ones that come with sympy, define your own using basic operators (so that sympy objects will be accepted) or find simpler ways to define your operations: sqrt() can simply be substituted by **(1/2).
Maybe you should look for a way that can make sympy accept functions from other modules because writing all of the special functions from scipy yourself looks like it will be a pain.

Solving Non-Linear Differential Equation Sympy

This code only works for solving the differential equation v_equation if v(t) isn't squared. When I squared it it returned the error PolynomialDivisionFailed. Is there another way of doing this with Sympy or should I find a different python package for doing these sorts of calculations.
from sympy import *
from matplotlib import pyplot as plt
import numpy as np
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f1 = g * m
t = Symbol('t')
v = Function('v')
v_equation = dsolve(f1 - k * (v(t) ** 2) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(v_equation.rhs.subs({t:0}),C1)[0]
v_equation = v_equation.subs({C1:C1_ic})
func = lambdify(t, v_equation.rhs,'numpy')
From my experience with symbolic math packages, I would not recommend performing (symbolic) calculations using floating point constants. It is better to define equations using symbolic constants, perform calculations as far as possible, and then substitute with numerical values.
With this approach, Sympy can provide a solution for this D.E.
First, define symbolic constants. To aid calculations, note that we can provide additional information about these constants (e.g., real, positive, e.t.c)
import sympy as sp
t = sp.symbols('t', real = True)
g, k, m = sp.symbols('g, k, m', real = True, positive = True)
v = sp.Function('v')
The symbolic solution for the DE can be obtained as follows
f1 = g * m
eq = f1 - k * (v(t) ** 2) - m * sp.Derivative(v(t))
sol = sp.dsolve(eq,v(t)).simplify()
The solution sol will be a function of k, m, g, and a constant C1. In general, there will be two, complex C1 values corresponding to the initial condition. However, both values of C1 result in the same (real-valued) solution when substituted in sol.
Note that if you don't need a symbolic solution, a numerical ODE solver, such as Scipy's odeint, may be used. The code would be the following (for an initial condition 0):
from scipy.integrate import odeint
def fun(v, t, m, k, g):
return (g*m - k*v**2)/m
tn = np.linspace(0, 10, 101)
soln = odeint(fun, 0, tn, args=(1000, 0.2, 9.8))
soln is an array of samples v(t) corresponding to the tn elements

Matrix of polynomial elements

I am using NumPy for operations on matrices, to calculate matrixA * matrixB, the trace of the matrix, etc... And elements of my matrices are integers. But what I want to know is if there is possibility to work with matrices of polynomials. So for instance I can work with matrices such as [x,y;a,b], not [1,1;1,1], and when I calculate the trace it provides me with the polynomial x + b, and not 2. Is there some polynomial class in NumPy which matrices can work with?
One option is to use the SymPy Matrices module. SymPy is a symbolic mathematics library for Python which is quite interoperable with NumPy, especially for simple matrix manipulation tasks such as this.
>>> from sympy import symbols, Matrix
>>> from numpy import trace
>>> x, y, a, b = symbols('x y a b')
>>> M = Matrix(([x, y], [a, b]))
>>> M
Matrix([
[x, y],
[a, b]])
>>> trace(M)
b + x
>>> M.dot(M)
[a*y + x**2, a*b + a*x, b*y + x*y, a*y + b**2]

Categories

Resources