Analytic approximation methods

Analytic approximation methods try to compute approximations to the exact solutions on suitable domains, in the form of truncated series expansions over a system of basis functions. In the SciPy stack, we have an implementation based on the Taylor series, through the routine odefun in the module sympy.mpmath.

Note

mpmath is a Python library for arbitrary-precision floating-point arithmetic, hosted inside the sympy module. Although it is independent of the numpy machinery, they both work well together.

For more information about this library, read the official documentation at http://mpmath.org/doc/current/.

Let's see it in action, first with our trivial example y'(t) = y(t), y(0) = 1. The key here is to assess the speed and the accuracy of the approximation, as compared to the actual solution in the interval [0, 1]. Its syntax is very simple, we assume the equation is always in the form of y' = F, and we provide the routine odefun with this functional F and the initial conditions (in this case, 0 for the t-value, and 1 for the y-value):

In [1]: import numpy as np, matplotlib.pyplot as plt; 
   ...: from sympy import mpmath
In [2]: def F(t, y): return y
In [3]: f = odefun(F, 0, 1)

We proceed to compare the results of the solver f with the actual analytical solution np.exp:

In [4]: t = np.linspace(0, 1, 1024); 
   ...: Y1 = np.vectorize(f)(t); 
   ...: Y2 = np.exp(t)
In [5]: (np.abs(Y1-Y2)).max()
Out[5]: mpf('2.2204460492503131e-16')

Let's examine our second example. We evaluate the time of execution and accuracy of approximation, as compared with the actual solution in the interval [1, 2]:

In [6]: def F(t, y): return 3.0*y**0.75 - 6.0*y/t
In [7]: def g(t): return (3.0*t**2.5 + 7)**4.0/(10000.0*t**6.)
In [8]: f = mpmath.odefun(F, 1.0, 1.0)
In [9]: t = np.linspace(1, 2, 1024); 
   ...: Y1 = np.vectorize(f)(t); 
   ...: Y2 = np.vectorize(g)(t)
In [9]: (np.abs(Y1-Y2)).max()
Out[9]: mpf('5.5511151231257827e-16')

Now let's address the example with the Latko-Volterra system. We compute the solutions and plot them for a time range of 0 to 10 units of time:

In [10]: def F(t, y): return [y[0]  - 0.1*y[0]*y[1],
   ....:                      0.075*y[0]*y[1] - 1.5*y[1]]
In [11]: f = mpmath.odefun(F, 0.0, [10.0, 5.0])
In [12]: T = [10.0*x/1023. for x in range(1024)]
   ....: X = [f(10.0*x/1023.)[0] for x in range(1024)]; 
   ....: Y = [f(10.0*x/1023.)[1] for x in range(1024)]
In [13]: plt.plot(T, X, 'r--', linewidth=2.0, label='predator'); 
   ....: plt.plot(T, Y, 'b-',  linewidth=2.0, label='prey'); 
   ....: plt.legend(loc=9); 
   ....: plt.grid(); 
   ....: plt.show()

This last command presents us with the following graph. The dotted line represents the amount of predators with respect to time, and the solid line represents the prey. First note the periodicity of the solution. Also, note the behavior of both functions—when the number of predators is high, the amount of prey is low. At that point, predators have a harder time finding food and their numbers start decreasing, while that of the prey starts rising:

Analytic approximation methods
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.51.36