Sympy dsolve with plots - python

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()

Related

Is there a more elegant way to apply complicated functions to meshgrid?

My goal is to plot the function $f(x,y) = 3^{\min\{x,2\}}t_0 y$
where $t_0$
is the smallest solution of $2t^x-3t-1=0$ (it's just a MWE; I didn't check the existence of the root(s). )
I did it. But in somehow an ugly way.
My approach is to apply the function element-wise. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
def equ(t,*data): # 2t^x - 3t -1
x = data
return 2*(t ** x) - 3*t - 1
def t0(t): # call fslove to solve the equation
return fsolve(equ, 1.5, args=(t))[0] # 1.5 is randomly choosed
xx = np.linspace(1,3,50) # range of x
yy = np.linspace(1,3,50) # range of y
ff = [] # the value of f at each (x, y)
# compute the value of f element-wise
for x in xx:
for y in yy:
f = (3 ** np.minimum(x, 2)) * t0(x) * y
ff.append(f)
fv = np.split(np.array(ff), np.size(xx)) # split ff to make it conform with meshgrid
xv, yv = np.meshgrid(xx, yy)
plt.pcolormesh(xv, yv, fv)
plt.colorbar()
plt.show()
But I think the elegancy of numpy is to avoid writing loops manually and to manipulate lists as a whole. So, is there a more elegant way to do that?

plug np.array into sympy expression

I need to subs a numpy.array into an indexed symbol of Sympy expression to numerically calculate the sum. (1+2+3+4+5=15).
My below code still produce symbolic expression. Please help~
from sympy import *
import numpy as np
i = Symbol("i")
y = Symbol("y")
y_ = np.array([1,2,3,4,5])
h = Sum(Indexed("y","i"),(i,0,4))
h.subs([(y,y_)])
smichr answer is solid, however considering that the numerical values of h_ are going to be converted by SymPy to symbolic numbers, the easiest and fastest way is to do this:
new_h = h.subs(y, Array(y_))
# out: Sum([1, 2, 3, 4, 5][i], (i, 0, 4))
# alternatively:
# new_h = h.subs(y, sympify(y_))
new_h.doit()
# out: 15
Another alternative is to convert your symbolic expression to a numerical function with lambdify. However, this approach works as long as the there is not infinity on the bounds of the summation:
f = lambdify([y], h)
f(y_)
# out: 15
Perhaps something like this will work?
>>> y = IndexedBase("y")
>>> h = Sum(y[i],(i,0,4));h.doit()
y[0] + y[1] + y[2] + y[3] + y[4]
>>> _.subs(dict(zip([y[i] for i in range(len(y_))],y_)))
15

How to Insert an Array of Values to a Symbolic Function in Python

I want to study symbolic functions in python. I want to create y(x) = x^2 + 2x + 3 and plot it in the range [1, 255]. I want to use the subs() function to calculate the values by using the for loop. However, when I run that I get this error:
IndexError('list index out of range')
Can you help me please?
import numpy as np
import matplotlib.pyplot as plot
from sympy import *
a = [1,2,3]
x = Symbol('x')
fx = a[0]*x**2 + a[1]*x + a[2]
t = list(range(1,256))
y = np.zeros(256)
for i in t:
y[i] = fx.subs({x:t[i]})
plot.plot(t,y)
plot.show()
Just replace with the following lines:
y = np.zeros(len(t))
for i in range(len(t)):
y[i] = fx.subs({x:t[i]})
The problem was that the length of t was only 255 but the len of y was 256 in your code because you define y = np.zeros(256), hence the Index Error because there is no t[256]. I am using y = np.zeros(len(t)) because you have as many y points as t (or x) points. By the way, you are most likely to get an error in your plot command the way it is right now because you have called import matplotlib.pyplot as plot. I would simply call it plt instead of plot
Output

Using scipy to integrate a function?

I am trying to use SciPy to integrate this function:
y(x) = (e^-ax)*cos(x) between 0 and 4pi.
Here is the code I have so far:
from numpy import *
from scipy.integrate import simps
a = 0
x = linspace(0 , 4*pi, 100)
y = (e^-(a*x))*cos(x)
integral_value = simps(y,x)
print integral_value
However it doesn't seem to be working. Any help would be appreciated, thanks!
Well if you run the program you obtain the following error:
TypeError: ufunc 'bitwise_xor' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
So you know the problem is with the ^ (bitwise xor) in your function. In Python one uses ** to take the exponent.
If one writes:
y = (e**-(a*x))*cos(x)
instead, one gets:
>>> print integral_value
-0.000170200006112
The full program:
from numpy import *
from scipy.integrate import simps
a = 0
x = linspace(0 , 4*pi, 100)
y = (e**-(a*x))*cos(x)
integral_value = simps(y,x)
print integral_value
You can also make explicit use of numpy functions with:
from numpy import *
from scipy.integrate import simps
a = 0
x = linspace(0 , 4*pi, 100)
y = exp(-a*x)*cos(x)
integral_value = simps(y,x)
print integral_value
In order to increase the precision, you can increase the number of points (100 is not that much).
import numpy as np
import math
from scipy.integrate import simps
a = 0
x = np.linspace(0 , 4*math.pi, 100)
#create a vectorized function which can be applied directly to an array
fn = np.vectorize(lambda x: math.exp(-a*x)*math.cos(x))
y = fn(x)
integral_value = simps(y, x)
print integral_value
this indeed yields value of -0.000170200006112. Note that for a=0, the integral is equal to zero, so in order to get "closer" you would need to refine the grid...
Cracking a nut with a sledgehammer ...
>>> from sympy import *
>>> var('a x')
(a, x)
>>> y = exp(-a*x)*cos(x)
>>> y.subs(a,0)
cos(x)
Should it surprise any of us to find that this integrates to 0 (zero) over the given interval?

Python -- sympy solve() returning another equation instead of value

This creates a list of points and the sympy solve() method should be returning the value of x. Instead it's returning yet another equation, and I'm not sure why. The ogrid() and ravel() are creating a list of points in the plot and this is on Matplotlib, if that makes a difference but I don't think it should. It should be finding root(s) of the equation. I'm not sure what I'm doing wrong here that causes it to not return a value, but instead returns another equation:
from mpl_toolkits.axes_grid.axislines import SubplotZero
from pylab import *
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
from matplotlib import rc
import random
from sympy.solvers import solve
from sympy import *
a = -2; b = 1
y, x = np.ogrid[-10:10:100j, -10:10:100j]
xlist = x.ravel(); ylist = y.ravel()
elliptic_curve = pow(y, 2) - pow(x, 3) - x * a - b
plt.contour(xlist, ylist, elliptic_curve, [0])
randmid = random.randint(30,70)
#y = ylist[randmid]; x = xlist[randmid]
xsym, ysym = symbols('x ylist[randmid]')
x_result = solve(pow(ysym, 2) - pow(xsym, 3) - xsym * a - b, xsym) # 11/5/13 needs to return a value
I'm teaching myself Python so this is probably something a junior programmer can help me out with, but if a pro sees this and can spare a moment to help that'd be great.
EDIT:
Returns a value for y roughly 3.xx where there's not 3 possible x-values:
x_result is a list of expressions, which is the solutions of your equation. It's not a list of value because ysym is a symbol. If you want the numeric results, you need call subs() and evalf():
[e.subs({ysym:ylist[randmid]}).evalf() for e in x_result]
output:
[0.0871073310916539 - 8.0e-17*I,
1.36864647418387 + 4.37e-17*I,
-1.45575380527552 + 3.63e-17*I]

Categories

Resources