Initial value problems for ordinary differential equations (or systems) hardly need any motivation. They arise naturally in almost all sciences. In this chapter, we will focus on mastering numerical methods to solve these equations.
Throughout the chapter, we will explore all the techniques implemented in the SciPy stack through three common examples:
Higher-order differential equations can always be transformed into (non-necessarily autonomous) systems of differential equations. In turn, nonautonomous systems of differential equations can always be turned into autonomous by including a new variable in a smart way. The techniques to accomplish these transformations are straightforward, and explained in any textbook on differential equations.
We have the possibility of solving some differential equations analytically via SymPy. Although this is hardly the best way to solve initial value problems computationally—even when analytical solutions are available—we will illustrate some examples for completion. Reliable solvers are numerical in nature, and in this setting, there are mainly two ways to approach this problem—through analytic approximation methods, or with discrete-variable methods.
Symbolic treatment of a few types of differential equations is coded in the SciPy stack through the module sympy.solvers.ode
. At this point, only the following equations are accessible with this method:
In addition to these, other equations might be solvable with the following techniques:
Let's see these techniques in action with our one-dimensional examples, y' = y and the Bernoulli equation. Note the method of inputting a differential equation. We write it in the form F(t,y,y') = 0, and we feed the expression F(t,y,y') to the solver (see line 3 that follows). Also, notice how we code derivatives of a function using SymPy; the expression f(t).diff(t)
represents the first derivative of f(t), for instance:
In [1]: from sympy.solvers import ode In [2]: t = symbols('t'); ...: f = Function('f') In [3]: equation1 = f(t).diff(t) - f(t) In [4]: ode.classify_ode(equation1) Out[4]: ('separable', '1st_exact', '1st_linear', 'almost_linear', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_homogeneous', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'almost_linear_Integral')
The equation has been classified as a member of several types. We can now solve it according to the proper techniques of the corresponding type. For instance, we choose to solve this equation by first assuming that it is separable, and then by computing an approximation of degree four (n=4
) to the solution with a power series representation (hint='1st_power_series'
) around x0=0
:
In [5]: ode.dsolve(equation1, hint='separable') Out[5]: f(t) == C1*exp(t) In [6]: ode.dsolve(equation1, hint='1st_power_series', n=4, x0=0.0) Out[6]: f(t) == C0 + C0*t + C0*t**2/2 + C0*t**3/6 + O(t**4)
Solving initial value problems is also possible, but only for solutions computed as a power series of first order differential equations:
In [7]: ode.dsolve(equation1, hint='1st_power_series', n=3, x0=0, ...: ics={f(0.0): 1.0}) Out[7]: f(t) == 1.0 + 1.0*t + 0.5*t**2 + O(t**3)
Let's explore the second example with these techniques:
In [8]: equation2 = t*f(t).diff(t) + 6*f(t) - 3*t*f(t)**(0.75) In [9]: ode.classify_ode(equation2) Out[9]: ('Bernoulli', 'lie_group', 'Bernoulli_Integral') In [10]: dsolve(equation2, hint='Bernoulli') Out[10]: f(t) == (t**(-1.5)*(C1 + 0.3*t**2.5))**4.0 In [11]: dsolve(equation2, hint=lie_group') Out[11]: f(t) == -5/(3*t*(C1*t**5 - 1)) [f(t) == 6.25e-6*(t**6*(625.0*C1**4 + 5400.0*C1*t**5 + 1296.0*t**10) - 120.0*sqrt(C1*t**17*(25.0*C1 + 36.0*t**5)**2))/t**12, f(t) == 6.25e-6*(t**6*(625.0*C1**4 + 5400.0*C1*t**5 + 1296.0*t**10) + 120.0*sqrt(C1*t**17*(25.0*C1 + 36.0*t**5)**2))/t**12]
Of course, although the functional expressions of both solutions in lines 10 and 11 are different, they represent the same function.
For more information on how to use these techniques and code your own symbolic solvers, refer to the excellent documentation from the official SymPy pages at http://docs.sympy.org/dev/modules/solvers/ode.html.
3.133.134.17