<jupyter_start><jupyter_text>Adaptive step-size selection for ODE filtersIn ProbNum the step size adaptation scheme from [Schober et al., 2019](https://arxiv.org/pdf/1610.05261.pdf) respectively [Bosch et al., 2021](https://arxiv.org/pdf/2012.08202.pdf) is implemented.<jupyter_code># Make inline plots vector graphics instead of raster graphics
%matplotlib inline
from IPython.display import set_matplotlib_formats

set_matplotlib_formats("pdf", "svg")

# Plotting
import matplotlib.pyplot as plt

plt.style.use("../../probnum.mplstyle")
import numpy as np
from probnum import randvars
from probnum.diffeq import probsolve_ivp<jupyter_output><empty_output><jupyter_text>We begin by defining an ODE: the usual Lotka-Volterra problem.<jupyter_code>def f(t, y):
    y1, y2 = y
    return np.array([0.5 * y1 - 0.05 * y1 * y2, -0.5 * y2 + 0.05 * y1 * y2])


def df(t, y):
    y1, y2 = y
    return np.array([[0.5 - 0.05 * y2, -0.05 * y1], [0.05 * y2, -0.5 + 0.05 * y1]])


t0 = 0.0
tmax = 20.0
y0 = np.array([20, 20])<jupyter_output><empty_output><jupyter_text>IBM(1) with EK0We start by showing how solving an IVP with adaptive steps works.<jupyter_code>sol = probsolve_ivp(f, t0, tmax, y0, df=df, algo_order=4, method="EK1")

evalgrid = np.linspace(t0, tmax, 200)
means = sol(evalgrid).mean

plt.plot(evalgrid, means[:, 0], label="Prey")
plt.plot(evalgrid, means[:, 1], label="Predators")
plt.legend(loc="upper right")
plt.show()<jupyter_output><empty_output><jupyter_text>Lets visualise the individual steps.<jupyter_code>plt.plot(evalgrid, means[:, 0], label="Prey")
plt.plot(evalgrid, means[:, 1], label="Predators")
for t in sol.locations:
    plt.axvline(t, linewidth=0.5, color="gray")
plt.legend(loc="upper right")
plt.show()<jupyter_output><empty_output><jupyter_text>Note how more steps are taken near the peaks.  The same, for a few priorsLet's consider how other priors fare in this setting.<jupyter_code>algo_orders = [2, 3]
filters = ["EK0", "EK1"]


fig, ax = plt.subplots(
    nrows=len(algo_orders),
    ncols=len(filters),
    sharex=True,
    sharey=True,
    figsize=(12, 12),
)

evalgrid = np.linspace(t0, tmax, 100)

for idx in range(len(algo_orders)):  # algo_orders in rows
    for jdx in range(len(filters)):  # filters in cols
        sol = probsolve_ivp(
            f,
            t0,
            tmax,
            y0,
            df=df,
            algo_order=algo_orders[idx],
            method=filters[jdx],
        )

        solution = sol(evalgrid)
        ts, means, stds = evalgrid, solution.mean, solution.std
        ax[idx][jdx].plot(ts, means)

        for t in sol.locations:
            ax[idx][jdx].axvline(t, linewidth=0.2, color="black")
        ax[idx][jdx].set_title(f"Order {algo_orders[idx]} w/{filters[jdx]}")
        ax[idx][jdx].set_xlim((t0, tmax))
        ax[idx][jdx].set_ylim((-10, 35))

plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14712005551700208, 'fraction_numerical': 0.0395558639833449, 'mean_word_length': 3.7890365448504983, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '210396', 'license': 'MIT', 'n_tokens_mistral': 1172, 'n_tokens_neox': 1097, 'n_words': 254, 'path': 'docs/source/tutorials/odes/adaptive_steps_odefilter.ipynb', 'repo_name': 'christopheroates/probnum', 'size': '2882'}