Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Introduction

In this chapter, for a given function f(x)f(x) we will compute the definite integral:

∫ab f(x) dx\int_a^b\,f(x)\,\textrm{d}x

where aa and bb are the limits of integration, and f(x)f(x) are the function values obtained either from a table of values or from an analytical function.

In numerical integration, the integral is estimated by II, and the following holds:

∫ab f(x) dx=I+E,\int_a^b\,f(x)\,\textrm{d}x= I + E,

where EE is the error of the integral estimate.

We will compute the numerical integral based on a discrete sum:

I=∑i=0mAi f(xi),I=\sum_{i=0}^{m}A_i\,f(x_i),

where AiA_i are the weights, xix_i are the nodes on the interval [a,b][a, b], and m+1m+1 is the number of nodes.

We will look at two different approaches to numerical integration:

  1. the Newton-Cotes approach, which is based on equidistant nodes (a constant integration step), and

  2. the Gaussian integration approach, where the nodes are placed so as to achieve exactness for polynomials.

Motivational example

For numerical integration, we will use a concrete example to guide us:

∫12x sin⁡(x) dx\int_1^2 x\,\sin(x)\,\textrm{d}x

Let us prepare the nodes. Let the basic step be h=0.25h=0.25; in this case we have four subintervals and five nodes, at step 2h2h there are three nodes, and at step 4h4h only two (the endpoints):

Let us also prepare the function values:

Let us prepare a plot of the data:

Let us display the data:

<Figure size 640x480 with 1 Axes>

Let us compute the exact result analytically:

Loading...

Newton-Cotes approach

The figure shows a general case in which the distance between the nodes xix_i is equal to hh (this is an equidistant partition). Integration

In this chapter we will first look at the trapezoidal and the composite trapezoidal rule, and later the Simpson’s and Romberg methods will follow.

Trapezoidal rule

The trapezoidal rule interpolates the values of the integrand f(x)f(x) on the (sub)interval [x0,x1][x_0, x_1] with a linear function. For two nodes, this means that we approximate the area under the graph of the function as:

Itrapezno=∑i=01Ai f(xi)=h2⋅(f(x0)+f(x1)).I_{\textrm{trapezno}}=\sum_{i=0}^{1}A_i\,f(x_i)=\frac{h}{2}\cdot\left(f(x_0)+f(x_1)\right).

And the weights are:

A0=A1=12 h.A_0 = A_1 = \frac{1}{2}\,h.

Numerical implementation

The numerical implementation is:

Numerical example

In our concrete case this means that we weight the first and last function value by h/2h/2. In our example h=1h=1:

Loading...

Let us prepare a figure:

We display:

<Figure size 640x480 with 1 Axes>

Error of the trapezoidal rule

The difference between the analytical value of the integral and the numerical approximation II is the error of the method:

E=∫abf(x) dx−I,E = \int_a^bf(x)\,d x-I,

If the function f(x)f(x) is at least twice differentiable, one can derive (see, e.g., the reference: Burden, Faires, Burden: Numerical Analysis 10th Ed) an error estimate that applies only to the trapezoidal approximation over the entire integration interval:

Etrapezno=−h312f′′(ξ),E_{\textrm{trapezno}}=-\frac{h^3}{12}f''(\xi),

where h=b−ah=b-a and ξ\xi is an unknown value on the interval [a,b][a,b].

Composite trapezoidal rule

If we divide the interval [a,b][a, b] into nn subintervals and apply the trapezoidal rule of integration on each of them, we speak of the composite trapezoidal rule.

In this case, for each subinterval ii we apply the trapezoidal rule, and thus for the bounds of the subinterval xix_i and xi+1x_{i+1} we use the weights Ai=Ai+1=h/2A_i=A_{i+1}=h/2. Since the interior nodes are doubled, it follows that:

A0=An=h2and for the other nodes:Ai=h.A_0=A_{n}=\frac{h}{2}\quad\textrm{and for the other nodes:}\quad A_i=h.

Here we have assumed subintervals of equal width:

h=xn−x0nh=\frac{x_{n}-x_0}{n}

It therefore follows that:

Itrapezno sest=∑i=0nAi f(xi)=(y02+y1+y2+⋯+yn−1+yn2) h.I_{\textrm{trapezno sest}}=\sum_{i=0}^{n}A_i\,f(x_i)=\left(\frac{y_0}{2} + y_1+y_2+\cdots+y_{n-1}+\frac{y_{n}}{2}\right)\,h.

Numerical implementation

The numerical implementation is:

Numerical example

Above we already prepared the data for two subintervals (three nodes):

array([1. , 1.5, 2. ])
Loading...

Let us compute the estimate of the integral with the composite trapezoidal rule:

Loading...

Let us prepare a figure:

We display:

<Figure size 640x480 with 1 Axes>

Error of the composite trapezoidal rule

The error of the composite trapezoidal rule stems from the error of the trapezoidal rule; here we make such an error nn times.

Since h⋅n=b−ah\cdot n=b-a holds, we derive the error of the composite trapezoidal rule as:

Etrapezno sest=−h2(b−a)12f′′(η),E_{\textrm{trapezno sest}}=-\frac{h^2(b-a)}{12}f''(\eta),

η\eta is a value on the interval [a,b][a,b]. The error is of second order O(h2)\mathcal{O}(h^2).

A better approximation of the integral

Next we will look at the so-called Richardson extrapolation, in which we compute a better approximation from the integral estimates with step hh and 2h2h.

If we compute the integral II numerically at two different steps hh and 2 h2\,h, the following holds:

∫abf(x) dx=Ih+Eh=I2h+E2h,\int_a^b f(x)\,\textrm{d}x = I_h + E_h = I_{2h} + E_{2h},

where IhI_h and I2hI_{2h} are the approximations of the integral with step hh and 2h2h, and EhE_h and E2hE_{2h} are the error estimates at step hh and 2h2h. We derive I2h−Ih=Eh−E2hI_{2h}-I_{h} = E_{h}-E_{2h}

Next we write:

Eh=−h2(b−a)12f′′(η)=h2 K.E_h=-\frac{h^2(b-a)}{12}f''(\eta)=h^2\,K.

Under the assumption that f′′(η)f''\left (\eta \right ) is the same at step hh and 2h2h (η\eta is actually different at step hh and 2h2h), we write:

E2h=−(2h)2(b−a)12f′′(η)=4 h2 KE_{2h}=-\frac{(2h)^2(b-a)}{12}f''(\eta)=4\,h^2\,K

It follows that:

I2h−Ih=−3K h2.I_{2h}-I_h=-3K\,h^2.

Now we can estimate the error at step hh:

Eh=h2 K=Ih−I2h3.E_h=h^2\,K=\frac{I_h-I_{2h}}{3}.

Based on the error estimate, we can compute a better numerical approximation Ih∗I_{h}^*:

Ih∗=Ih+13 (Ih−I2h)I_h^* = I_h + \frac{1}{3}\,(I_{h}-I_{2h})

or

Ih∗=43 Ih−13 I2hI_h^* = \frac{4}{3}\,I_h - \frac{1}{3}\,I_{2h}

Numerical example

We previously computed the integral with the trapezoidal rule at step h=1h=1 and at step h=0.5h=0.5 already; the results were:

Loading...

Using the formula above, we compute a better approximation:

Exact result:        1.4404224209802097
Better approximation: 1.4408392930139313

The composite trapezoidal rule is also implemented in the numpy package, via the numpy.trapezoid function (numpy.trapz in older versions):

trapezoid(y, x=None, dx=1.0, axis=-1)
  • y represents the table of function values,

  • x is an optional parameter and defines the nodes; if the parameter is not defined, equidistant nodes spaced by dx are assumed,

  • dx defines the (constant) integration step, with a default value of 1,

  • axis defines the axis along which to integrate (in case y is a multidimensional numeric array).

The function returns the computed integral according to the composite trapezoidal rule. More information can be found in the documentation.

numpy implementation of the composite trapezoidal rule

Let us look at an example:

Loading...

Simpson’s and other methods

Above we looked at the trapezoidal rule, which is based on a linear interpolating function on an individual subinterval. With higher-order interpolation we can derive further integration methods.

We need to compute:

∫abf(x) dx.\int_{a}^b f(x)\,dx.

We tabulate the integrand f(x)f(x) and interpolate the table with the Lagrange interpolating polynomial Pn(x)P_n(x) of degree nn:

Pn(x)=∑i=0n f(xi) li(x),P_n(x)=\sum_{i=0}^{n}\,f(x_i)\,l_i(x),

where yi=f(xi)y_i=f(x_i) are the function values at the nodes xix_i and the Lagrange polynomial lil_i is defined as:

li(x)=∏j=0,j≠inx−xjxi−xj.l_i(x)=\prod_{j=0, j\ne i}^n \frac{x-x_j}{x_i-x_j}.

For the numerical computation of the integral ∫abf(x) dx\int_{a}^b f(x)\,dx (the limits are: a=x0a=x_0, b=xnb=x_n), instead of the function f(x)f(x) we substitute the interpolating polynomial Pn(x)P_n(x) into the integral:

I=∫x0xnPn(x) dx=∫x0xn∑i=0n f(xi) li(x) dx.I=\int_{x_0}^{x_{n}} P_n(x)\,dx=\int_{x_0}^{x_{n}} \sum_{i=0}^{n}\,f(x_i)\,l_i(x)\,dx.

Since integration is a linear operation, we can swap the integration and the sum:

I=∑i=0n f(xi) ∫x0xnli(x) dx⏟Ai.I=\sum_{i=0}^{n}\,f(x_i)\,\underbrace{\int_{x_0}^{x_{n}} l_i(x)\,dx}_{A_i}.

We integrate the Lagrange polynomial and obtain the weights AiA_i:

Ai=∫x0xnli(x) dxA_i = \int_{x_0}^{x_{n}} l_i(x)\,dx

Derivation of the trapezoidal rule using Lagrange polynomials

Let us look at how we can computationally derive the weights AiA_i for the case of the trapezoidal rule using a first-degree Lagrange interpolating polynomial.

First, let us define the variable x, the nodes x0 and x1, and the step h in symbolic form:

Let us prepare a Python function that returns, in symbolic form, a list of nn coefficients of the Lagrange polynomials [l0(x),l1(x),…,ln−1(x)][l_0(x), l_1(x),\dots, l_{n-1}(x)] of degree n−1n-1:

First, let us look at the Lagrange polynomials for linear interpolation (n=2n=2):

Loading...

Now we integrate the Lagrange polynomial l0(x)l_0(x) over the entire interval:

Loading...

We simplify the expression and obtain:

Loading...

Since the width of the subinterval is constant, x1=h0+hx_1=h_0+h, we perform the substitution:

Loading...

The steps above for the Lagrange polynomial l0(x)l_0(x) can be generalized to a list of Lagrange polynomials:

Loading...

We derived the weights that we used in the trapezoidal method:

A0=h/2A1=h/2.A_0=h/2\qquad A_1=h/2.

The trapezoidal rule is:

Itrapezno=h2(y0+y1)I_{\textrm{trapezno}}=\frac{h}{2}\left(y_0+y_1\right)

The error estimate is (reference: Burden, Faires, Burden: Numerical Analysis 10th Ed):

Etrapezno=−h312f′′(ξ).E_{\textrm{trapezno}}= -\frac{h^3}{12}f''(\xi).

Computing the weights for Simpson’s rule

After showing the concise computation for the trapezoidal rule above, we can proceed similarly for quadratic interpolation over three points (n=3n=3).

The computation of the weights is analogous to the one above:

Loading...

Simpson’s rule (this rule is also called Simpson’s 1/3 rule) is:

ISimpsonovo=h3(y0+4 y1+y2)I_{\textrm{Simpsonovo}}=\frac{h}{3}\left(y_0+4\,y_1+y_2\right)

The error estimate is (reference: Burden, Faires, Burden: Numerical Analysis 10th Ed):

ESimpsonovo=−h590f(4)(ξ).E_{\textrm{Simpsonovo}}= -\frac{h^5}{90}f^{(4)}(\xi).

It should be pointed out that the error is locally of fifth order O(h5)\mathcal{O}(h^5) and is defined by the unknown value of the fourth derivative f(4)(ξ)f^{(4)}(\xi); consequently, this rule is exact for polynomials of degree 3 or less.

Example of use:

Loading...

Let us prepare a figure. Since Simpson’s rule is based on quadratic interpolation, we must first prepare the interpolating polynomial (we use scipy.interpolate):

We display:

<Figure size 640x480 with 1 Axes>

scipy.integrate.newton_cotes

The coefficients of the Newton-Cotes integration approach can also be obtained using scipy.integrate.newton_cotes() (documentation):

newton_cotes(rn, equal=0)

where the parameters are:

  • rn, which defines the number of subintervals (a non-constant step is also possible, see the documentation),

  • equal, which defines whether equally wide subintervals are required.

The function returns a tuple, in which the first element represents the numeric array of weights and the second element the error estimate.

Let us look at an example:

(array([0.33333333, 1.33333333, 0.33333333]), -0.011111111111111112)

Computing the weights for Simpson’s 3/8 rule

We can continue with cubic interpolation over four points (n=4n=4):

Loading...

Simpson’s 3/8 rule is:

ISimpsonovo 3/8=3h8(y0+3 y1+3 y2+y3)I_{\textrm{Simpsonovo 3/8}}=\frac{3h}{8}\left(y_0+3\,y_1+3\,y_2+y_3\right)

The error estimate is (reference: Burden, Faires, Burden: Numerical Analysis 10th Ed):

ESimpsonovo 3/8=−3 h580f(4)(ξ).E_{\textrm{Simpsonovo 3/8}}= -\frac{3\,h^5}{80}f^{(4)}(\xi).

Let us look at an example of use. We use the previously prepared table of function values at four points:

array([0.84147098, 1.2959172 , 1.65901326, 1.81859485])
Loading...

Let us also prepare a plot:

We display:

<Figure size 640x480 with 1 Axes>

Composite Simpson’s rule

We divide the interval [a,b][a, b] into an even number nn of subintervals of equal width h=(b−a)/nh=(b - a)/n, which defines the nodes xi=a+i hx_i=a+i\,h for i=0,1,…,ni=0,1,\dots,n. In this case we write the composite Simpson’s rule:

∫abf(x) dx=h3(f(x0)+4∑i=1n/2f(x2i−1)+2∑i=1n/2−1f(x2i)+f(xn))−b−a180h4 f(4)(η)⏟ESestavljeno Simpsonovo 1/3,\int_{a}^{b}f(x)\,\textrm{d}x= \frac{h}{3}\left( f(x_0) +4\sum_{i=1}^{n/2}f(x_{2i-1}) +2\sum_{i=1}^{n/2-1}f(x_{2i}) +f(x_n) \right) \underbrace{ -\frac{b-a}{180}h^4\,f^{(4)}(\eta) }_{E_{\textrm{Sestavljeno Simpsonovo 1/3}}} ,

where η\eta is an unknown value on the interval [a,b][a, b]. The error is of fourth order O(h4)\mathcal{O}(h^4).

Numerical implementation:

Loading...

Let us prepare a figure:

We display:

<Figure size 640x480 with 1 Axes>

A better estimate of the integral

The error of the composite Simpson’s method is defined by:

ESestavljeno Simpsonovo 1/3=−b−a180h4 f(4)(η),E_{\textrm{Sestavljeno Simpsonovo 1/3}}= -\frac{b-a}{180}h^4\,f^{(4)}(\eta),

where η\eta is an unknown value on the interval [a,b][a, b].

We determine an improved estimate of the integral in a manner similar to the composite trapezoidal method; we estimate the integral II at two different steps hh and 2 h2\,h, and the following holds exactly:

∫abf(x) dx=Ih+Eh=I2h+E2h,\int_a^b f(x)\,\textrm{d}x = I_h + E_h = I_{2h} + E_{2h},

where IhI_h is the approximation of the integral with step hh and EhE_h is the error estimate at step hh; the same holds analogously for I2hI_{2h} and E2hE_{2h}.

If we assume that f(4)(η)f^{(4)}\left (\eta \right ) is the same in both cases, we can determine the difference I2h−Ih=Eh−E2hI_{2h}-I_{h} = E_{h}-E_{2h}.

Next we write:

Eh=−b−a180h4 f(4)(η)=h4 K.E_h=-\frac{b-a}{180}h^4\,f^{(4)}(\eta)=h^4\,K.

Under the assumption that f(4)(η)f^{(4)}\left (\eta \right ) is the same at step hh and 2h2h (η\eta is actually different at step hh and 2h2h), we write:

E2h=−(b−a)180(2h)4 f(4)(η)=16 h4 KE_{2h}=-\frac{(b-a)}{180}(2h)^4\,f^{(4)}(\eta)=16\,h^4\,K

It follows that:

I2h−Ih=−15K h4.I_{2h}-I_h=-15K\,h^4.

Now we can estimate the error at step hh:

Eh=h4 K=Ih−I2h15.E_h=h^4\,K=\frac{I_h-I_{2h}}{15}.

Based on the error estimate, we can compute a better approximation Ih∗I_{h}^*:

Ih∗=Ih+115 (Ih−I2h)I_h^* = I_h + \frac{1}{15}\,(I_{h}-I_{2h})

or

Ih∗=1615 Ih−115 I2hI_h^* = \frac{16}{15}\,I_h - \frac{1}{15}\,I_{2h}

Numerical example

We previously computed the integral with Simpson’s rule at step h=0.5h=0.5 and at step h=0.25h=0.25 already; the results were:

Loading...

Using the formula above, we compute a better approximation:

Exact result:        1.4404224209802097
Better approximation: 1.4404218714139077

We obtain a better numerical approximation, but we lose the error estimate!

Simpson’s method in scipy.integrate.simpson

The composite Simpson’s rule is implemented in scipy in scipy.integrate.simpson() (documentation):

simpson(y, x=None, *, dx=1.0, axis=-1)

where the parameters are:

  • y the table of function values that we integrate,

  • x the nodes, an optional parameter; if x=None, equidistant subintervals of width dx are assumed,

  • dx the width of the equidistant subintervals, i.e., the integration step,

  • axis the integration axis (important in the case of a multidimensional numeric array).

In older SciPy versions the function was called simps and also had the parameter even; both were removed in SciPy 1.14.

Let us look at an example; first we import the simpson function:

Loading...

Romberg method

The Romberg method is based on Richardson extrapolation. Let us assume that we integrate the integral ∫abf(x)dx\int_a^b f(x)\textrm{d}x on the interval [a,b][a,b], which we divide into 2n−12^{n-1} subintervals (n=1,2,4,8,…n=1,2,4,8, \dots).

We denote the result of the trapezoidal rule at n=1n=1 by R1⏟n,1⏟jR_{\underbrace{1}_{n},\underbrace{1}_{j}}, where jj denotes the accuracy of the obtained result O(h2j)\mathcal{O}(h^{2j}).

If we apply the trapezoidal integration rule at n=1,2,4…n=1,2,4 \dots subintervals, we compute:

  • R1,1R_{1,1}, step h1=hh_1=h, order of accuracy O(h12)\mathcal{O}(h_1^2),

  • R2,1R_{2,1}, step h2=h/2h_2=h/2, order of accuracy O(h22)\mathcal{O}(h_2^2),

  • R3,1R_{3,1}, step h3=h/4h_3=h/4, order of accuracy O(h32)\mathcal{O}(h_3^2),

  • R4,1R_{4,1}, step h4=h/8h_4=h/8, order of accuracy O(h42)\mathcal{O}(h_4^2),

  • …\dots

  • Rn,1R_{n,1}, step h4=h/(2n−1)h_4=h/(2^{n-1}), order of accuracy O(hn2)\mathcal{O}(h_n^2).

Based on Richardson extrapolation we compute a better approximation

  • R2,2=R2,1+13(R2,1−R1,1)R_{2,2} = R_{2,1} + \frac{1}{3}\left(R_{2,1}-R_{1,1}\right), step h2=h/2h_2=h/2, order of accuracy O(h24)\mathcal{O}(h_2^4),

  • R3,2=R3,1+13(R3,1−R2,1)R_{3,2} = R_{3,1} + \frac{1}{3}\left(R_{3,1}-R_{2,1}\right), step h3=h/4h_3=h/4, order of accuracy O(h34)\mathcal{O}(h_3^4),

  • …\dots

  • Rn,2=Rn,1+13(Rn,1−Rn−1,1)R_{n,2} = R_{n,1} + \frac{1}{3}\left(R_{n,1}-R_{n-1,1}\right), step hn=h/(2n−1)h_n=h/(2^{n-1}), order of accuracy O(hn4)\mathcal{O}(h_n^4).

Then we continue with Richardson extrapolation:

  • R3,3=R3,2+115(R3,2−R2,2)R_{3,3} = R_{3,2} + \frac{1}{15}\left(R_{3,2}-R_{2,2}\right), step h3=h/4h_3=h/4, order of accuracy O(h36)\mathcal{O}(h_3^6),

  • …\dots

  • Rn,3=Rn,2+115(Rn,2−Rn−1,2)R_{n,3} = R_{n,2} + \frac{1}{15}\left(R_{n,2}-R_{n-1,2}\right), step hn=h/(2n−1)h_n=h/(2^{n-1}), order of accuracy O(hn6)\mathcal{O}(h_n^6).

Richardson extrapolation can be generalized:

  • Rn,j=Rn,j−1+14j−1−1(Rn,j−1−Rn−1,j−1)R_{n,j} = R_{n,j-1} + \frac{1}{4^{j-1}-1}\left(R_{n,j-1}-R_{n-1,j-1}\right), step hn=h/(2n−1)h_n=h/(2^{n-1}), order of accuracy O(hn2j)\mathcal{O}(h_n^{2j})

Here, the better approximation R2,2R_{2,2} at step h/2h/2 is equal to the result obtained by Simpson’s method at step h/2h/2. Similarly, the better approximation R3,2R_{3,2} at step h/4h/4 is equal to the numerical integral of Simpson’s method at step h/4h/4. And further, R3,3R_{3,3} is equal to the corrected approximation of Simpson’s method at step h/4h/4.

Let us prepare the numerical data:

Let us look at the example from above. First, we compute the integral with the composite trapezoidal method at different steps (second-order error):

Loading...

Then we compute better approximations (we obtain a fourth-order error):

Loading...

The results represent the result of Simpson’s method at step h=0.5h=0.5, h=0.25h=0.25 and h=0.125h=0.125:

Loading...

We again compute better approximations (we obtain a sixth-order error):

Loading...

The result represents the better result of Simpson’s method at step h=0.25h=0.25 and h=0.125h=0.125:

Loading...

We again compute better approximations (we obtain an eighth-order error):

Loading...

The Romberg method thus offers high result accuracy at a relatively low numerical cost. The error is estimated by:

E=∣Rn,n−Rn−1,n−1∣.E = \left|R_{n,n}-R_{n-1,n-1}\right|.

Romberg method in scipy.integrate.romb

The Romberg method is implemented in scipy in scipy.integrate.romb() (documentation):

romb(y, dx=1.0, axis=-1, show=False)

where the parameters are:

  • y the table of function values that we integrate,

  • dx the width of the equidistant subintervals, i.e., the integration step,

  • axis the integration axis (important in the case of a multidimensional numeric array),

  • show if True, displays the elements of the Richardson extrapolation.

Let us look at the example from above:

array([0.84147098, 1.01505104, 1.18623077, 1.34872795, 1.49624248, 1.62261343, 1.72197541, 1.78891084, 1.81859485])
Richardson Extrapolation Table for Romberg Integration
======================================================
 1.33003 
 1.41314  1.44084 
 1.43362  1.44045  1.44042 
 1.43872  1.44042  1.44042  1.44042 
======================================================
Loading...

Gaussian integration approach

The Newton-Cotes approach is based on a polynomial of degree nn, and the error is of degree n+1n+1. This means that the integration yields an exact result if the integrated function is a polynomial of degree nn or less; for even nn, owing to symmetry, even of degree n+1n+1 (Simpson’s rule, n=2n=2, is e.g. exact also for cubic polynomials).

The Gaussian integration approach is fundamentally different: the goal is to replace the integral of the function f(x)f(x) with a weighted sum of function values at discrete values f(xi)f(x_i):

∫abf(x) dx≈∑i=0n−1Ai f(xi).\int_a^bf(x)\,\textrm{d}x\approx \sum_{i=0}^{n-1} A_i\, f(x_i).

Here both the weight AiA_i and the location of the node xix_i are unknown. For polynomials of degree nn we will also need more points (xi,f(xi))(x_i, f(x_i)).

In what follows, we will learn that we can compute a numerically exact integral very efficiently. An additional advantage of Gaussian integration is that it can compute the integral of functions with singularities (e.g.: ∫01sin⁡(x)/(x) dx\int_0^1\sin(x)/\sqrt{(x)}\,dx).

Gaussian quadrature with one node

Let us assume that we want to integrate a polynomial of degree n=1n=1 (a linear function):

f(x)=P1(x)=a0+a1 x.f(x)=P_1(x)=a_0+a_1\,x.

Let us compute:

∫xLxDP1(x) dx=(a0 x+a1 x22)xLxD=−a0 xL+a0 xD−a1 xL22+a1 xD22.\int_{x_L}^{x_D}P_1(x)\,\textrm{d}x=\left(a_0\,x+a_1\,\frac{x^2}{2}\right)_{x_L}^{x_D}=-a_0\,x_L+a_0\,x_D-\frac{a_1\,x_L^2}{2}+\frac{a_1\,x_D^2}{2}.

On the other hand, we want to compute the integral from the appropriately weighted A0A_0 value of the function f(x0)f(x_0) at an unknown node x0x_0 (only one node!):

∫xLxDP1(x) dx=A0 P1(x0)=A0 a0+A0 a1 x0.\int_{x_L}^{x_D}P_1(x)\,\textrm{d}x = A_0\,P_1(x_0)= A_0\,a_0+A_0\,a_1\,x_0.

By equating the expressions above, we derive:

−a0 xL+a0 xD−a1 xL22+a1 xD22=A0 a0+A0 a1 x0.-a_0\,x_L+a_0\,x_D-\frac{a_1\,x_L^2}{2}+\frac{a_1\,x_D^2}{2}=A_0\,a_0+A_0\,a_1\,x_0.

a0a_0 and a1a_1 are the coefficients of the linear function, which can take arbitrary values, so it holds that:

a0 (−xL+xD−A0)=0anda1(−xL22+xD22−A0 x0)=0.a_0\,\left(-x_L+x_D-A_0\right)=0\qquad\textrm{and}\qquad a_1\left(-\frac{x_L^2}{2}+\frac{x_D^2}{2}-A_0\,x_0\right)=0.

This is a system of linear equations with the solution:

A0=xD−xL,x0=xL+xD2.A_0= x_D-x_L, \qquad x_0=\frac{x_L+x_D}{2}.

If the integrated function is linear, we will compute the true value based only on the value at a single point!

So that the Gaussian integration approach is independent of the integration limits xLx_L, xDx_D, we introduce standard limits.

Standard limits: xL=−1x_L=-1 and xD=1x_D=1

For generality, we transform the limits x∈[xL,xD]x\in[x_L, x_D] into ξ∈[−1,+1]\xi\in[-1, +1] using:

x=xD+xL2+xD−xL2ξx=\frac{x_D+x_L}{2}+\frac{x_D-x_L}{2}\xi

and

dx=xD−xL2dξ.\textrm{d}x=\frac{x_D-x_L}{2}\textrm{d}\xi.

The following holds:

∫xLxDf(x) dx=∫−11g(ξ) dξ,\int_{x_L}^{x_D}f(x)\,\textrm{d}x=\int_{-1}^1 g\left(\xi\right)\,\textrm{d}\xi,

where:

g(ξ)=xD−xL2 f(xL+xD2+xD−xL2ξ).g(\xi)=\frac{x_D-x_L}{2}\,f\left(\frac{x_L+x_D}{2}+\frac{x_D-x_L}{2}\xi\right).

In the case of standard limits, at one Gauss point the weight is A0=2A_0=2 and x0=0x_0=0 is the value at which we must evaluate the function f(x0)f(x_0).

Computational derivation of the weights and the Gauss point

Let us define the symbols and set up the equation:

Loading...

Let us prepare two equations (for the first we assume a0=0,a1=1a_0=0, a_1=1, for the second we assume a0=1,a1=0a_0=1, a_1=0) and solve the system for A_0 and x_0:

Loading...

For additional explanation, I recommend this video.

Gaussian integration method with multiple nodes

We want to derive a Gaussian integration method that will take into account vv nodes on the interval [a,b][a,b] and will exactly compute the integral of polynomials up to degree n=2v−1n=2v-1. The following must hold:

∫abP2v−1(x) dx=∑i=0v−1Ai P2v−1(xi).\int_a^bP_{2v-1}(x)\,\textrm{d}x = \sum_{i=0}^{v-1} A_i\,P_{2v-1}(x_i).

In the derivation we will restrict ourselves to the standard limits xL=−1x_L=-1, xD=1x_D=1,

where the polynomial of degree n=2v−1n=2v-1 is defined as:

P2v−1(x)=∑i=02v−1ai xi.P_{2v-1}(x)=\sum_{i=0}^{2v-1} a_i\,x^i.

With two Gauss points/nodes we exactly compute the integral of a polynomial up to third order, and with three Gauss nodes we exactly compute the integral of a polynomial up to fifth order!

Computational derivation

Let us first prepare the symbolic notation of the polynomial and the corresponding variables:

Now let us find the weights AiA_i and the nodes xix_i for the case of two Gauss nodes; the polynomial is therefore of third degree.

Nodes:   (x0, x1)
Weights: (A0, A1)

The polynomial:

Loading...

Similarly to the one node above, here let us define the equations:

Loading...

We solve them for the unknown xix_i and AiA_i:

Loading...

We determined a list of two (equal) solutions.

First, the nodes are defined: x0=−3/3x_0=-\sqrt{3}/3 and x1=3/3x_1=\sqrt{3}/3, with the corresponding weights A0=A1=1A_0=A_1=1.

The code above is derived in general - you can increase the number of nodes v and compute the nodes and the corresponding weights.

Below is a table of nodes and weights for one, two, and three nodes (for the limits a=−1a=-1, b=1b=1):

Number of points 1:

iiNode xix_iWeight AiA_i
002

Number of points 2:

iiNode xix_iWeight AiA_i
0−33-\frac{\sqrt{3}}{3}1
1+33+\frac{\sqrt{3}}{3}1

Number of points 3:

iiNode xix_iWeight AiA_i
0−155-\frac{\sqrt{15}}{5}59\frac{5}{9}
1089\frac{8}{9}
2155\frac{\sqrt{15}}{5}59\frac{5}{9}

For more nodes and also the error estimate, see Mathworld Legendre-Gauss Quadrature.

For the case of three Gauss points, we compute the numerical integral (standard limits):

IGauss3=59 f(−155)+89 f(0)+59 f(155).I_{\textrm{Gauss3}}= \frac{5}{9}\,f\left(-\frac{\sqrt{15}}{5}\right) + \frac{8}{9}\,f\left(0\right)+\frac{5}{9}\,f\left(\frac{\sqrt{15}}{5}\right).

Numerical implementation

The numerical implementation (including the transformation of the limits) for one, two, or three nodes:

Let us look at an example. First, let us define the function we want to integrate:

Now we pass the function (in this concrete case f) and not the value (e.g., f(0.)) to the gaussian function. First for one node, then two and three:

Loading...
Loading...
Loading...

scipy.integrate.fixed_quad

Within scipy, the Gaussian integration method is implemented in the scipy.integrate.fixed_quad() function (documentation):

fixed_quad(func, a, b, args=(), n=5)

where the parameters are:

  • func is the name of the function we call,

  • a is the lower limit,

  • b is the upper limit,

  • args is a tuple of any additional arguments of the function func,

  • n is the number of nodes of the Gaussian integration, default n=5.

The function returns a tuple with the integration result val and the value None: (val, None)

Let us look at the example from above:

Loading...

The result is equal to the previous one:

Loading...

scipy.integrate

scipy.integrate is a powerful tool for numerical integration (see the documentation). In what follows, we will look at some of the functions.

Integration functions that require a defining function:

  • quad(func, a, b[, args, full_output, ...]) computes the definite integral of func(x) over the limits [a, b],

  • dblquad(func, a, b, gfun, hfun[, args, ...]) computes the definite integral of func(x,y),

  • tplquad(func, a, b, gfun, hfun, qfun, rfun) computes the definite integral of func(x,y,z),

  • nquad(func, ranges[, args, opts, full_output]) computes the definite integral of the nn-dimensional function func( ...),

scipy.integrate.quad

Let us look at a very useful function for integration, scipy.integrate.quad() (documentation):

quad(func, a, b, args=(), full_output=0, epsabs=1.49e-08, epsrel=1.49e-08, limit=50,
     points=None, weight=None, wvar=None, wopts=None, maxp1=50, limlst=50)

The selected parameters are:

  • func the Python function we integrate,

  • a the lower limit of integration (np.inf can be used for an infinite limit),

  • b the upper limit of integration (np.inf can be used for an infinite limit),

  • full_output to display all results, default 0,

  • epsabs the allowed absolute error,

  • epsrel the allowed relative error.

Let us look at the example from above:

Loading...

scipy.integrate.dblquad

This is a function similar to quad, but for integration over two variables (documentation). The function scipy.integrate.dblquad() computes the double integral of func(y, x) over the limits from x = [a, b] and y = [gfun(x), hfun(x)].

dblquad(func, a, b, gfun, hfun, args=(), epsabs=1.49e-08, epsrel=1.49e-08)

The selected parameters are:

  • func is the Python function we integrate,

  • a is the lower limit of integration of x (np.inf can be used for an infinite limit),

  • b is the upper limit of integration of x (np.inf can be used for an infinite limit),

  • gfun is the Python function that defines the lower limit of y as a function of x,

  • hfun is the Python function that defines the upper limit of y as a function of x.

Let us look at an example of computing the area of a half-circle with radius 1:

∫−11(∫01−x21 dy) dx=π2\int_{-1}^{1}\left(\int_0^{\sqrt{1-x^2}}1\,\textrm{d}y\right)\,\textrm{d}x=\frac{\pi}{2}

Let us define the appropriate Python functions and compute the result:

Loading...

Integration functions that require a table of values:

  • trapezoid(y[, x, dx, axis]) composite trapezoidal rule,

  • cumulative_trapezoid(y[, x, dx, axis, initial]) cumulative integral of the integrand (returns the result at each node),

  • simpson(y[, x, dx, axis]) Simpson’s method,

  • romb(y[, dx, axis, show]) Romberg method.

Here we will look at the cumulative_trapezoid function on an example. Consider the case where a mass m=1m=1 (we omit the units) acted upon by a force F=sin⁡(t)F=\sin(t). From Newton’s 2nd law it follows that: F=m x¨F=m\,\ddot x. We integrate the acceleration to compute the velocity; then we integrate once more for the displacement. Let us first define the function for the acceleration:

We are interested in what happens over a time of 3 seconds:

Let us compute the table of accelerations and then integrate for the velocity (here it is important to define the initial value):

Now let us integrate the velocity once more to compute the path:

Let us display the result:

<Figure size 640x480 with 1 Axes>