Integration#
Newton-Cotes methods#
A related problem to interpolation is when we need to calculate the integral of a function
given values of the function at a discrete set of points \(x_1\dots x_N\), which we’ll write as \(f_i\equiv f(x_i)\). For simplicity here we’ll assume that the spacing between points on the grid is constant \(x_{i+1}-x_i = \Delta x\), but it’s straighforward to generalize to non-uniform sampling if you need to.
To estimate the value of the integral, we need to model how the function behaves in each interval \(x_i<x<x_{i+1}\). As with interpolation, we can take \(f(x)\) in each interval to be a polynomial, including additional terms in the polynomial to increase the accuracy of our approximation.
Rectangle rule
The first approximation is to assume that \(f(x)\) is a constant \(f(x)=f_i\) in the interval \(x_i\leq x\leq x_{i+1}\). The total integral is then
Trapezoidal rule
If we make a linear approximation, we can write
Then
This is known as the trapezoidal rule because it corresponds to the area of the trapezoid formed by connecting the points \((x_i,f_i)\) and \((x_{i+1}, f_{i+1})\) by a straight line.
When we sum over all intervals, each point gets counted twice except for the left and right boundaries, so
Simpson’s rule
For the next order, we consider the double interval \(x_{i-1}<x<x_{i+1}\), and write
The reason for considering the double interval from \(x_{i-1}\) to \(x_{i+1}\) is that the linear term is odd in this interval (antisymmetric about \(x_i\)) and so does not contribute to the integral, i.e.
Taking
and simplifying then gives
Adding up the contributions from each double interval, the total integral is
where we need the total number of points \(N\) to be an odd number (so we can divide the domain into a set of double intervals).
Exercise: Newton-Cotes
Implement these three methods to calculate the integral
How does the error in each method scale with the number of points \(N\)? Is it what you expected?
Next, use your code to check the result that the average value of \(\sin^2(x)\) is \(1/2\), i.e.
Does the result surprise you? What happened?
Follow up exercise:
What kind of functions are integrated exactly (to machine precision) for each method? (Hint: polynomials of a certain order, which order?)
Gaussian quadrature#
In the previous examples, we were given the function \(f(x)\) evaluated at a pre-determined set of points \(\{ x_i\}\). But if instead we are able to choose the values of \(x\) where we can evaluate the function, we can do better using the method of Gaussian quadratures.
The simplest example is the integral
(which is quite general because for different integration limits you can make a change of variables to bring the limits to \(-1\) and \(+1\)). We write the integral as
For a suitable choice of the weights \(w_i\) and the locations \(x_i\) it can be shown that this expression is exact when \(f(x)\) is a polynomial of order \(2N-1\) or less.
Question
This means that with 2 evaluations of \(f(x)\) we can exactly evaluate the integral of a cubic polynomial! How does this compare with Simpson’s method?
The proof that this works and the calculation of the values of \(w_i\) and \(x_i\) is quite involved. [It uses the theory of orthogonal polynomials, so for example for this particular form of the integral, the values of \(x_i\) are the roots of the Legendre Polynomial \(P_N(x)\).] However, we can look up \(w_i\) and \(x_i\) using numpy.polynomial.legendre.leggauss
For example,
>>> np.polynomial.legendre.leggauss(2)
(array([-0.57735027, 0.57735027]), array([1., 1.]))
gives the \(N=2\) values. In this case, the weights are both 1, and the \(x\) values are \(\pm 1/\sqrt{3}\).
Exercise: Gaussian quadrature
Using numpy.polynomial.legendre.leggauss
to get the locations and weights for different choices of \(N\), implement Gaussian quadratures.
Check that the answer is indeed exact for polynomials of degree \(2N-1\) or less. What happens for higher order polynomials?
Try a function that is not a simple polynomial, e.g. \(e^{-x^2}\). What is the error in the approximation and how does it scale with \(N\)?
Hints:
to get the correct value of the integral to compare with to see how accurate your approximation is, you could use the general purpose integrator
scipy.integrate.quad
to generate a polynomial with degree
N
and random coefficients between -10 and +10 (for example) you can usenp.polynomial.Polynomial(np.random.randint(-10,high=10,size=N+1))
Gaussian quadratures can be applied more generally to integrals of the form
for some weight function \(W(x)\) (in the previous example we had \(W(x)=1\)). We write the integral as a sum
and find the choices of \(w_i\) and \(x_i\) that make the sum exact for a polynomial of degree \(2N-1\) or less.
One example is \(W(x)=e^{-x^2}\), ie. integrals
In this case, the weights and locations are given by numpy.polynomial.hermite.hermgauss
. [The locations \(x_i\) are the roots of the \(N\)th Hermite polynomial, which are the polynomials that are orthogonal under an inner product defined with weight function \(W(x)\).]
Exercise: Gauss-Hermite
Modify your code to use the Gauss-Hermite coefficients and check that you can get an exact answer for the integral of \(e^{-x^2}\).
Hint: If you want to use scipy.integrate.quad
again to get the value of the integral as a comparison, note that you can give it limits of \(-\infty\) to \(+\infty\) using -np.inf
and np.inf
.
Other examples are
\(W(x)=e^{-x}\) with integration limits \(0\) to \(\infty\). In this case, we need Gauss-Laguerre integration – see
numpy.polynomial.laguerre.laggauss
\(W(x)=1/\sqrt{1-x^2}\) from \(x=-1\) to \(1\) is Gauss-Chebyshev quadrature – see
numpy.polynomial.chebyshev.chebgauss
Integration challenge#
Exercise: Average velocity of the Maxwell-Boltzmann distribution.
Use Simpson’s rule, Gaussian quadrature, and the general purpose integrator scipy.integrate.quad
to evaluate the average velocity \(\langle\left|v\right|\rangle\) for the 3D Maxwell-Boltzmann distribution.
For each method, check the numerical error comparing to the analytic result. How many points do you need to get to \(0.1\)% accuracy?
For Simpson’s rule you can use your own implementation from above or you could try scipy.integrate.simpson
.
For Gaussian quadrature, try both Gauss-Hermite and Gauss-Laguerre. Which one is best?
Further reading#
Integration methods are covered in Chapter 7 of Gezerlis.
Overview of `scipy.integrate’
QUADPACK is the Fortran 77 library that is used by
scipy.integrate.quad
under the hood.