Adaptive quadrature

Example

Compute the following function using a Recursive Trapazoid method:

$$I = \int_0^1 x\tanh\left(50\left(x-\frac{1}{2}\right)\right) + 1\,dx.$$

The function being integrated is shown in the plot below.

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
%matplotlib inline
def f(x) :
    return x * np.tanh(50.0*(x-0.5)) + 1.0

x = np.linspace(0,1,100)
plt.plot(x,f(x));
adapt
xstore = np.empty(0)

def adaptTrap(f, xa, xb, tol=1E-4):
    
    Δx = xb - xa
    Δx2 = Δx/2
    xm = 0.5*(xa+xb)
    
    global xstore
    xstore = np.append(xstore, xm)
    
    I1 = Δx*(f(xa) + f(xb))/2
    I2 = Δx2*(f(xa) + f(xm))/2 + Δx2*(f(xm) + f(xb))/2
    
    err = np.abs((I1-I2)/I2)
    if err <= tol:
        return I2
    else:
        return adaptTrap(f, xa, xm, tol) + adaptTrap(f, xm, xb, tol)
    
I = adaptTrap(f, 0, 1, 1E-2)
print(f"\nI_adapt = {I:.8f}")
print(f"I_quad  = {quad(f,0,1)[0]:.8f}")

x = np.linspace(0,1,100)
y = f(x)
plt.plot(x,y,'-')

ystore = f(xstore)
ml, sl, bl = plt.stem(xstore,ystore, bottom=-1);
plt.ylim([0,2]);
plt.setp(sl, 'color', 'gray', 'linewidth', 1);
plt.setp(ml, 'color', 'gray', 'markersize', 4);
I_adapt = 1.24953451
I_quad  = 1.24967101
adapt