Tutorial IntegratorLearner#

Note

Because this documentation consists of static html, the live_plot and live_info widget is not live. Download the notebook in order to see the real behaviour. 1

import adaptive

adaptive.notebook_extension()

import holoviews as hv
import numpy as np

This learner learns a 1D function and calculates the integral and error of the integral with it. It is based on Pedro Gonnet’s implementation.

Let’s try the following function with cusps (that is difficult to integrate):

def f24(x):
    return np.floor(np.exp(x))


xs = np.linspace(0, 3, 200)
hv.Scatter((xs, [f24(x) for x in xs]))

Just to prove that this really is a difficult to integrate function, let’s try a familiar function integrator scipy.integrate.quad, which will give us warnings that it encounters difficulties (if we run it in a notebook.)

import scipy.integrate

scipy.integrate.quad(f24, 0, 3)
/tmp/ipykernel_2697/484480164.py:3: IntegrationWarning: The maximum number of subdivisions (50) has been achieved.
  If increasing the limit yields no improvement it is advised to analyze 
  the integrand in order to determine the difficulties.  If the position of a 
  local difficulty can be determined (singularity, discontinuity) one will 
  probably gain from splitting up the interval and calling the integrator 
  on the subranges.  Perhaps a special-purpose integrator should be used.
  scipy.integrate.quad(f24, 0, 3)
(17.65947611079367, 0.017039069845928623)

We initialize a learner again and pass the bounds and relative tolerance we want to reach. Then in the Runner we pass goal=lambda l: l.done() where learner.done() is True when the relative tolerance has been reached.

from adaptive.runner import SequentialExecutor

learner = adaptive.IntegratorLearner(f24, bounds=(0, 3), tol=1e-8)

# We use a SequentialExecutor, which runs the function to be learned in
# *this* process only. This means we don't pay
# the overhead of evaluating the function in another process.
runner = adaptive.Runner(
    learner, executor=SequentialExecutor(), goal=lambda l: l.done()
)
await runner.task  # This is not needed in a notebook environment!
runner.live_info()

Now we could do the live plotting again, but lets just wait untill the runner is done.

if not runner.task.done():
    raise RuntimeError(
        "Wait for the runner to finish before executing the cells below!"
    )
print(
    "The integral value is {} with the corresponding error of {}".format(
        learner.igral, learner.err
    )
)
learner.plot()
The integral value is 17.6643835377243 with the corresponding error of 1.764637385684444e-07

1

This notebook can be downloaded as tutorial.IntegratorLearner.ipynb and tutorial.IntegratorLearner.md.