From 403c7f510f43db21d395b1f3313b4c9c8432245b Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Sun, 5 Oct 2025 11:05:32 -0600 Subject: [PATCH 01/11] added trus_inputs to pytensor functions, added multiple pytensor backends, added block_until_ready to jax calls --- doc/gallery/scan/benchmark_backends.ipynb | 7151 +++++++++++++++++++++ 1 file changed, 7151 insertions(+) create mode 100644 doc/gallery/scan/benchmark_backends.ipynb diff --git a/doc/gallery/scan/benchmark_backends.ipynb b/doc/gallery/scan/benchmark_backends.ipynb new file mode 100644 index 0000000000..3bc77de8a0 --- /dev/null +++ b/doc/gallery/scan/benchmark_backends.ipynb @@ -0,0 +1,7151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9571ee33", + "metadata": {}, + "source": [ + "# Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "73cc811c", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import jax.numpy as jnp\n", + "from numba import jit\n", + "import numba\n", + "import pytensor\n", + "import pytensor.tensor as pt\n", + "import timeit\n", + "import jax\n", + "import math\n", + "from jax.scipy.special import gammaln\n", + "from functools import partial\n", + "\n", + "import plotly.graph_objects as go\n", + "from plotly.subplots import make_subplots\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "daa0969b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pytensor version: 0+untagged.31335.g4312d8c\n", + "jax version: 0.7.2\n", + "numba version: 0.62.1\n" + ] + } + ], + "source": [ + "print(\"pytensor version:\", pytensor.__version__)\n", + "print(\"jax version:\", jax.__version__)\n", + "print(\"numba version:\", numba.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "8294718d", + "metadata": {}, + "outputs": [], + "source": [ + "class Benchmarker:\n", + " \"\"\"\n", + " Benchmark a set of functions by timing execution and summarizing statistics.\n", + "\n", + " Parameters\n", + " ----------\n", + " functions : list of callables\n", + " List of callables to benchmark.\n", + " names : list of str, optional\n", + " Names corresponding to each function. Default is ['func_0', 'func_1', ...].\n", + " number : int or None, optional\n", + " Number of loops per timing. If None, auto-calibrated via Timer.autorange().\n", + " Default is None.\n", + " repeat : int, optional\n", + " Number of repeats for timing. Default is 7.\n", + " target_time : float, optional\n", + " Target duration in seconds for auto-calibration. Default is 0.2.\n", + "\n", + " Attributes\n", + " ----------\n", + " results : dict\n", + " Mapping from function names to a dict with keys:\n", + " - 'raw_us': numpy.ndarray of raw timings in microseconds\n", + " - 'loops': number of loops used per timing\n", + "\n", + " Methods\n", + " -------\n", + " run()\n", + " Auto-calibrate (if needed) and run timings for all functions.\n", + " summary(unit='us') -> pandas.DataFrame\n", + " Return a summary DataFrame with statistics converted to the given unit.\n", + " raw(name=None) -> dict or numpy.ndarray\n", + " Return raw timing data in microseconds for a specific function or all.\n", + " _convert_times(times, unit) -> numpy.ndarray\n", + " Convert an array of times from microseconds to the specified unit.\n", + " \"\"\"\n", + "\n", + " def __init__(\n", + " self, functions, names=None, number=None, min_rounds=5, max_time=1.0, target_time=0.2\n", + " ):\n", + " self.functions = functions\n", + " self.names = names or [f\"func_{i}\" for i in range(len(functions))]\n", + " self.number = number\n", + " self.min_rounds = min_rounds\n", + " self.max_time = max_time\n", + " self.target_time = target_time\n", + " self.results = {}\n", + "\n", + " def run(self, inputs: dict[str, dict]):\n", + " \"\"\"\n", + " Auto-calibrate loop count and sample rounds if needed, then time each function.\n", + " \"\"\"\n", + " for name, func in zip(self.names, self.functions):\n", + " for input_name, kwargs in inputs.items():\n", + " timer = timeit.Timer(partial(func, **kwargs))\n", + "\n", + " # Calibrate loops\n", + " if self.number is None:\n", + " loops, calib_time = timer.autorange()\n", + " else:\n", + " loops = self.number\n", + " calib_time = timer.timeit(number=loops)\n", + "\n", + " # Determine rounds based on max_time and min_rounds\n", + " if self.max_time is not None:\n", + " rounds = max(self.min_rounds, int(np.ceil(self.max_time / calib_time)))\n", + " else:\n", + " rounds = self.min_rounds\n", + "\n", + " raw_round_times = np.array(timer.repeat(repeat=rounds, number=loops))\n", + "\n", + " # Convert to microseconds per single execution\n", + " raw_us = raw_round_times / loops * 1e6\n", + "\n", + " self.results[(name, input_name)] = {\n", + " \"raw_us\": raw_us,\n", + " \"loops\": loops,\n", + " \"rounds\": rounds,\n", + " }\n", + "\n", + " def summary(self, unit=\"us\"):\n", + " \"\"\"\n", + " Summarize benchmark statistics in a DataFrame.\n", + "\n", + " Parameters\n", + " ----------\n", + " unit : {'us', 'ms', 'ns', 's'}, optional\n", + " Unit for output times. 'us' means microseconds, 'ms' milliseconds,\n", + " 'ns' nanoseconds, 's' seconds. Default is 'us'.\n", + "\n", + " Returns\n", + " -------\n", + " pandas.DataFrame\n", + " Summary with columns:\n", + " Name, Loops, Min, Max, Mean, StdDev, Median, IQR (all in given unit),\n", + " OPS (Kops/unit), Samples.\n", + " \"\"\"\n", + " records = []\n", + " indexes = []\n", + " for name, data in self.results.items():\n", + " raw_us = data[\"raw_us\"]\n", + " # Convert to target unit\n", + " times = self._convert_times(raw_us, unit)\n", + " if isinstance(name, tuple) and len(name) > 1:\n", + " indexes.append(name)\n", + " elif isinstance(name, tuple) and len(name) == 1:\n", + " indexes.append(name[0])\n", + " else:\n", + " indexes.append(name)\n", + "\n", + " stats = {\n", + " \"Loops\": data[\"loops\"],\n", + " f\"Min ({unit})\": np.min(times),\n", + " f\"Max ({unit})\": np.max(times),\n", + " f\"Mean ({unit})\": np.mean(times),\n", + " f\"StdDev ({unit})\": np.std(times),\n", + " f\"Median ({unit})\": np.median(times),\n", + " f\"IQR ({unit})\": np.percentile(times, 75) - np.percentile(times, 25),\n", + " \"OPS (Kops/s)\": 1e3 / (np.mean(raw_us)),\n", + " \"Samples\": len(raw_us),\n", + " }\n", + " records.append(stats)\n", + "\n", + " if all(isinstance(idx, tuple) for idx in indexes):\n", + " index = pd.MultiIndex.from_tuples(indexes)\n", + " else:\n", + " index = pd.Index(indexes)\n", + " return pd.DataFrame(records, index=index)\n", + "\n", + " def raw(self, name=None):\n", + " \"\"\"\n", + " Get raw timing data in microseconds.\n", + "\n", + " Parameters\n", + " ----------\n", + " name : str, optional\n", + " If given, returns the raw_us array for that function. Otherwise returns\n", + " a dict of all raw results.\n", + "\n", + " Returns\n", + " -------\n", + " numpy.ndarray or dict\n", + " \"\"\"\n", + " if name:\n", + " return self.results.get(name, {}).get(\"raw_us\")\n", + " return {n: d[\"raw_us\"] for n, d in self.results.items()}\n", + "\n", + " def _convert_times(self, times, unit):\n", + " \"\"\"\n", + " Convert an array of times from microseconds to the specified unit.\n", + "\n", + " Parameters\n", + " ----------\n", + " times : array-like\n", + " Times in microseconds.\n", + " unit : {'us', 'ms', 'ns', 's'}\n", + " Target unit: 'us' microseconds, 'ms' milliseconds,\n", + " 'ns' nanoseconds, 's' seconds.\n", + "\n", + " Returns\n", + " -------\n", + " numpy.ndarray\n", + " Converted times.\n", + "\n", + " Raises\n", + " ------\n", + " ValueError\n", + " If `unit` is not one of the supported options.\n", + " \"\"\"\n", + " unit = unit.lower()\n", + " if unit == \"us\":\n", + " factor = 1.0\n", + " elif unit == \"ms\":\n", + " factor = 1e-3\n", + " elif unit == \"ns\":\n", + " factor = 1e3\n", + " elif unit == \"s\":\n", + " factor = 1e-6\n", + " else:\n", + " raise ValueError(f\"Unsupported unit: {unit}\")\n", + " return times * factor" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "6e76a860", + "metadata": {}, + "outputs": [], + "source": [ + "# Set Pytensor to use float32\n", + "pytensor.config.floatX = \"float32\"" + ] + }, + { + "cell_type": "markdown", + "id": "1c3eb543", + "metadata": {}, + "source": [ + "# Introduction" + ] + }, + { + "cell_type": "markdown", + "id": "e066c9c4", + "metadata": {}, + "source": [ + "# Baby Steps" + ] + }, + { + "cell_type": "markdown", + "id": "962c851c", + "metadata": {}, + "source": [ + "## Fibonacci Algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ed368809", + "metadata": {}, + "outputs": [], + "source": [ + "# Pytensor creates functions itself\n", + "n_symbolic = pt.iscalar(\"n\")\n", + "\n", + "def step(a, b):\n", + " return a + b, a\n", + "\n", + "(outputs_a, outputs_b), _ = pytensor.scan(\n", + " fn=step,\n", + " outputs_info=[pt.constant(1.0), pt.constant(1.0)],\n", + " n_steps=n_symbolic\n", + ")\n", + "\n", + "# compile function returning final a\n", + "fibonacci_pytensor = pytensor.function([n_symbolic], outputs_a[-1], trust_input=True)\n", + "fibonacci_pytensor_numba = pytensor.function([n_symbolic], outputs_a[-1], mode='NUMBA', trust_input=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "bf48d6bf", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def fibonacci_numba(n):\n", + " a = np.ones(1, dtype=np.int32)\n", + " b = np.ones(1, dtype=np.int32)\n", + " for _ in range(n):\n", + " a[0], b[0] = a[0] + b[0], a[0]\n", + " return a[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "893c3124", + "metadata": {}, + "outputs": [], + "source": [ + "# This is faster than running a scan or a fori_loop\n", + "@partial(jax.jit, static_argnums=0)\n", + "def fibonacci_jax(n):\n", + " a, b = jnp.array(1, dtype=np.int32), jnp.array(1, dtype=np.int32)\n", + " for _ in range(n):\n", + " a, b = a + b, a\n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "63bfdffe", + "metadata": {}, + "outputs": [], + "source": [ + "fibonacci_bench = Benchmarker(\n", + " functions=[fibonacci_pytensor, fibonacci_numba, jax.block_until_ready(fibonacci_jax), fibonacci_pytensor_numba], \n", + " names=['fibonacci_pytensor', 'fibonacci_numba', 'fibonacci_jax', 'fibonacci_pytensor_numba'],\n", + " number=10\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "65bf994e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
fibonacci_pytensorfibonacci_inputs1064518.02500167663.20420066403.9358401071.00029466790.32500910.6417990.0150595
fibonacci_numbafibonacci_inputs1075.491700104.42910093.3517336.43002893.518754.25419910.71217412
fibonacci_jaxfibonacci_inputs102.1125007.4416013.2033202.1195602.125000.112499312.1761095
fibonacci_pytensor_numbafibonacci_inputs103325.6000003470.2958003371.58414050.8202623355.9916015.6416990.2965965
\n", + "
" + ], + "text/plain": [ + " Loops Min (us) Max (us) \\\n", + "fibonacci_pytensor fibonacci_inputs 10 64518.025001 67663.204200 \n", + "fibonacci_numba fibonacci_inputs 10 75.491700 104.429100 \n", + "fibonacci_jax fibonacci_inputs 10 2.112500 7.441601 \n", + "fibonacci_pytensor_numba fibonacci_inputs 10 3325.600000 3470.295800 \n", + "\n", + " Mean (us) StdDev (us) \\\n", + "fibonacci_pytensor fibonacci_inputs 66403.935840 1071.000294 \n", + "fibonacci_numba fibonacci_inputs 93.351733 6.430028 \n", + "fibonacci_jax fibonacci_inputs 3.203320 2.119560 \n", + "fibonacci_pytensor_numba fibonacci_inputs 3371.584140 50.820262 \n", + "\n", + " Median (us) IQR (us) \\\n", + "fibonacci_pytensor fibonacci_inputs 66790.32500 910.641799 \n", + "fibonacci_numba fibonacci_inputs 93.51875 4.254199 \n", + "fibonacci_jax fibonacci_inputs 2.12500 0.112499 \n", + "fibonacci_pytensor_numba fibonacci_inputs 3355.99160 15.641699 \n", + "\n", + " OPS (Kops/s) Samples \n", + "fibonacci_pytensor fibonacci_inputs 0.015059 5 \n", + "fibonacci_numba fibonacci_inputs 10.712174 12 \n", + "fibonacci_jax fibonacci_inputs 312.176109 5 \n", + "fibonacci_pytensor_numba fibonacci_inputs 0.296596 5 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fibonacci_bench.run(\n", + " inputs={\n", + " \"fibonacci_inputs\": {\"n\": 100_000},\n", + " }\n", + ")\n", + "fibonacci_bench.summary()" + ] + }, + { + "cell_type": "markdown", + "id": "7bbb35a2", + "metadata": {}, + "source": [ + "## Element-wise multiplication Algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "7b8bb97b", + "metadata": {}, + "outputs": [], + "source": [ + "a_symbolic = pt.vector(\"a\", dtype=\"int32\")\n", + "b_symbolic = pt.vector(\"b\", dtype=\"int32\")\n", + "\n", + "def step(a_element, b_element):\n", + " return a_element * b_element\n", + " \n", + "c, _ = pytensor.scan(\n", + " fn=step,\n", + " sequences=[a_symbolic, b_symbolic]\n", + ")\n", + "\n", + "# compile function returning final a\n", + "elementwise_multiply_pytensor = pytensor.function([a_symbolic, b_symbolic], c, trust_input=True)\n", + "\n", + "elementwise_multiply_pytensor_numba = pytensor.function([a_symbolic, b_symbolic], c, mode=\"NUMBA\", trust_input=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "14327cbf", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def elementwise_multiply_numba(a, b):\n", + " n = a.shape[0]\n", + " c = np.empty(n, dtype=a.dtype)\n", + " for i in range(n):\n", + " c[i] = a[i] * b[i]\n", + " return c" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "3943328f", + "metadata": {}, + "outputs": [], + "source": [ + "@jax.jit\n", + "def elementwise_multiply_jax(a, b):\n", + " n = a.shape[0]\n", + " c = jnp.empty(n, dtype=a.dtype)\n", + " for i in range(n):\n", + " c = c.at[i].set(a[i] * b[i])\n", + " return c" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d43c4f9c", + "metadata": {}, + "outputs": [], + "source": [ + "a = np.random.normal(0, 1, (100)).astype(np.int32)\n", + "b = np.random.normal(0, 1, (100)).astype(np.int32)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "f0f4ede5", + "metadata": {}, + "outputs": [], + "source": [ + "elem_mult_bench = Benchmarker(\n", + " functions=[elementwise_multiply_pytensor, elementwise_multiply_numba, jax.block_until_ready(elementwise_multiply_jax), elementwise_multiply_pytensor_numba], \n", + " names=['elementwise_multiply_pytensor', 'elementwise_multiply_numba', 'elementwise_multiply_jax', 'elementwise_multiply_pytensor_numba'],\n", + " number=10\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cdab8946", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
elementwise_multiply_pytensorelem_mult_inputs103.09580118.9167003.7485840.5130673.7084000.241699266.76739811841
elementwise_multiply_numbaelem_mult_inputs100.3417010.7792000.3860480.0850130.3708990.0290992590.35307523
elementwise_multiply_jaxelem_mult_inputs107.9958999.9874998.9178860.5686758.8959000.456251112.1342027
elementwise_multiply_pytensor_numbaelem_mult_inputs103.6000008.9416994.3791551.6353243.6666000.291699228.3545379
\n", + "
" + ], + "text/plain": [ + " Loops Min (us) \\\n", + "elementwise_multiply_pytensor elem_mult_inputs 10 3.095801 \n", + "elementwise_multiply_numba elem_mult_inputs 10 0.341701 \n", + "elementwise_multiply_jax elem_mult_inputs 10 7.995899 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 10 3.600000 \n", + "\n", + " Max (us) Mean (us) \\\n", + "elementwise_multiply_pytensor elem_mult_inputs 18.916700 3.748584 \n", + "elementwise_multiply_numba elem_mult_inputs 0.779200 0.386048 \n", + "elementwise_multiply_jax elem_mult_inputs 9.987499 8.917886 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 8.941699 4.379155 \n", + "\n", + " StdDev (us) \\\n", + "elementwise_multiply_pytensor elem_mult_inputs 0.513067 \n", + "elementwise_multiply_numba elem_mult_inputs 0.085013 \n", + "elementwise_multiply_jax elem_mult_inputs 0.568675 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 1.635324 \n", + "\n", + " Median (us) IQR (us) \\\n", + "elementwise_multiply_pytensor elem_mult_inputs 3.708400 0.241699 \n", + "elementwise_multiply_numba elem_mult_inputs 0.370899 0.029099 \n", + "elementwise_multiply_jax elem_mult_inputs 8.895900 0.456251 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 3.666600 0.291699 \n", + "\n", + " OPS (Kops/s) Samples \n", + "elementwise_multiply_pytensor elem_mult_inputs 266.767398 11841 \n", + "elementwise_multiply_numba elem_mult_inputs 2590.353075 23 \n", + "elementwise_multiply_jax elem_mult_inputs 112.134202 7 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 228.354537 9 " + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "elem_mult_bench.run(\n", + " inputs={\n", + " \"elem_mult_inputs\": {\"a\": a, \"b\": b},\n", + " }\n", + ")\n", + "elem_mult_bench.summary()" + ] + }, + { + "cell_type": "markdown", + "id": "25a87710", + "metadata": {}, + "source": [ + "# Changepoint Detection Algorithms" + ] + }, + { + "cell_type": "markdown", + "id": "16b2b312", + "metadata": {}, + "source": [ + "## Cumulative Sum (CUSUM) Algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "c1226cfc", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def cusum_adaptive_numba(x, alpha=0.01, k=0.5, h=5.0):\n", + " \"\"\"\n", + " Two-sided CUSUM with adaptive exponential moving average baseline.\n", + " \n", + " Parameters\n", + " ----------\n", + " x: np.ndarray\n", + " input signal\n", + " alpha: float\n", + " EMA smoothing factor (0 < alpha <= 1)\n", + " k: float\n", + " slack to avoid small changes triggering alarms\n", + " h: float\n", + " threshold for raising an alarm\n", + " \n", + " Returns\n", + " -------\n", + " s_pos: np.ndarray\n", + " upper CUSUM stats\n", + " s_neg: np.ndarray\n", + " lower CUSUM stats\n", + " mu_t: np.ndarray\n", + " evolving baseline estimate\n", + " alarms_pos: np.ndarray\n", + " alarms for upward changes\n", + " alarms_neg: np.ndarray\n", + " alarms for downward changes\n", + " \"\"\"\n", + " n = x.shape[0]\n", + "\n", + " s_pos = np.zeros(n, dtype=np.float64)\n", + " s_neg = np.zeros(n, dtype=np.float64)\n", + " mu_t = np.zeros(n, dtype=np.float64)\n", + " alarms_pos = np.zeros(n, dtype=np.bool_)\n", + " alarms_neg = np.zeros(n, dtype=np.bool_)\n", + "\n", + " # Initialization\n", + " mu_t[0] = x[0]\n", + "\n", + " for i in range(1, n):\n", + " # Update baseline (EMA)\n", + " mu_t[i] = alpha * x[i] + (1 - alpha) * mu_t[i-1]\n", + "\n", + " # Update CUSUM stats\n", + " s_pos[i] = max(0.0, s_pos[i-1] + x[i] - mu_t[i] - k)\n", + " s_neg[i] = max(0.0, s_neg[i-1] - (x[i] - mu_t[i]) - k)\n", + "\n", + " # Alarms\n", + " alarms_pos[i] = s_pos[i] > h\n", + " alarms_neg[i] = s_neg[i] > h\n", + "\n", + " return s_pos, s_neg, mu_t, alarms_pos, alarms_neg" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "14937a2a", + "metadata": {}, + "outputs": [], + "source": [ + "@jax.jit\n", + "def cusum_adaptive_jax(x, alpha=0.01, k=0.5, h=5.0):\n", + " \"\"\"\n", + " Two-sided CUSUM with adaptive exponential moving average baseline.\n", + " \n", + " Parameters\n", + " ----------\n", + " x: jnp.ndarray\n", + " input signal\n", + " alpha: float\n", + " EMA smoothing factor (0 < alpha <= 1)\n", + " k: float\n", + " slack to avoid small changes triggering alarms\n", + " h: float\n", + " threshold for raising an alarm\n", + " \n", + " Returns\n", + " -------\n", + " s_pos: jnp.ndarray\n", + " upper CUSUM stats\n", + " s_neg: jnp.ndarray\n", + " lower CUSUM stats\n", + " mu_t: jnp.ndarray\n", + " evolving baseline estimate\n", + " alarms_pos: jnp.ndarray\n", + " alarms for upward changes\n", + " alarms_neg: jnp.ndarray\n", + " alarms for downward changes\n", + " \"\"\"\n", + " def body(carry, x_t):\n", + " s_pos_prev, s_neg_prev, mu_prev = carry\n", + " \n", + " # Update EMA baseline\n", + " mu_t = alpha * x_t + (1 - alpha) * mu_prev\n", + " \n", + " # Update CUSUMs using updated baseline\n", + " s_pos = jnp.maximum(0.0, s_pos_prev + x_t - mu_t - k)\n", + " s_neg = jnp.maximum(0.0, s_neg_prev - (x_t - mu_t) - k)\n", + " \n", + " new_carry = (s_pos, s_neg, mu_t)\n", + " output = (s_pos, s_neg, mu_t)\n", + " return new_carry, output\n", + "\n", + " # Initialize: CUSUMs at 0, initial mean = first sample\n", + " s0 = (0.0, 0.0, x[0])\n", + " _, (s_pos_vals, s_neg_vals, mu_vals) = jax.lax.scan(body, s0, x)\n", + " \n", + " # Thresholding\n", + " alarms_pos = s_pos_vals > h\n", + " alarms_neg = s_neg_vals > h\n", + "\n", + " return s_pos_vals, s_neg_vals, mu_vals, alarms_pos, alarms_neg\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "815967a4", + "metadata": {}, + "outputs": [], + "source": [ + "x_symbolic = pt.vector(\"x\")\n", + "alpha_symbolic = pt.scalar(\"alpha\")\n", + "k_symbolic = pt.scalar(\"k\")\n", + "h_symbolic = pt.scalar(\"h\")\n", + "\n", + "def step(x_t, s_pos_prev, s_neg_prev, mu_prev, alpha, k):\n", + " # Update EMA baseline\n", + " mu_t = alpha * x_t + (1 - alpha) * mu_prev\n", + " \n", + " # Update CUSUMs using updated baseline\n", + " s_pos = pt.maximum(0.0, s_pos_prev + x_t - mu_t - k)\n", + " s_neg = pt.maximum(0.0, s_neg_prev - (x_t - mu_t) - k)\n", + " \n", + " return s_pos, s_neg, mu_t\n", + "\n", + "\n", + "(s_pos_vals, s_neg_vals, mu_vals), updates = pytensor.scan(\n", + " fn=step,\n", + " outputs_info=[pt.constant(0.), pt.constant(0.), x_symbolic[0]],\n", + " non_sequences=[alpha_symbolic, k_symbolic],\n", + " sequences=[x_symbolic]\n", + ")\n", + "\n", + "# Thresholding\n", + "alarms_pos = s_pos_vals > h_symbolic\n", + "alarms_neg = s_neg_vals > h_symbolic\n", + "\n", + "cusum_adaptive_pytensor = pytensor.function([x_symbolic, alpha_symbolic, k_symbolic, h_symbolic], [s_pos_vals, s_neg_vals, mu_vals, alarms_pos, alarms_neg], trust_input=True)\n", + "\n", + "cusum_adaptive_pytensor_numba = pytensor.function([x_symbolic, alpha_symbolic, k_symbolic, h_symbolic], [s_pos_vals, s_neg_vals, mu_vals, alarms_pos, alarms_neg], mode=\"NUMBA\", trust_input=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "024f421f", + "metadata": {}, + "outputs": [], + "source": [ + "cusum_adaptive_pytensor_jax = pytensor.function([x_symbolic, alpha_symbolic, k_symbolic, h_symbolic], [s_pos_vals, s_neg_vals, mu_vals, alarms_pos, alarms_neg], mode=\"JAX\", trust_input=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "6c892129", + "metadata": {}, + "outputs": [], + "source": [ + "xs1 = np.random.normal(80, 20, size=(50))\n", + "xs2 = np.random.normal(50, 20, size=(50))\n", + "xs = np.concat((xs1, xs2))\n", + "xs = xs.astype(np.float32)\n", + "xs = xs.astype(np.float32)\n", + "xs_std = (xs - xs.mean()) / xs.std()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "d21873d6", + "metadata": {}, + "outputs": [], + "source": [ + "cusum_bench = Benchmarker(\n", + " functions=[cusum_adaptive_pytensor, cusum_adaptive_numba, jax.block_until_ready(cusum_adaptive_jax), cusum_adaptive_pytensor_numba, jax.block_until_ready(cusum_adaptive_pytensor_jax)], \n", + " names=['cusum_adaptive_pytensor', 'cusum_adaptive_numba', 'cusum_adaptive_jax', 'cusum_adaptive_pytensor_numba', 'cusum_adaptive_pytensor_jax'],\n", + " number=10\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "d8eab72d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
cusum_adaptive_pytensorcusum_inputs10120.633400169.616699135.6346767.004116134.1084007.0292017.372746761
cusum_adaptive_numbacusum_inputs101.7749993.3958002.0357140.5560271.8042000.050000491.2280927
cusum_adaptive_jaxcusum_inputs1011.05840113.82500012.2241500.74757912.2646001.06252581.80527934
cusum_adaptive_pytensor_numbacusum_inputs1025.52500132.55420027.4075002.62600326.5125001.29580036.4863635
cusum_adaptive_pytensor_jaxcusum_inputs1019.27500057.13340122.2107486.48145321.1625011.73130045.02324631
\n", + "
" + ], + "text/plain": [ + " Loops Min (us) Max (us) \\\n", + "cusum_adaptive_pytensor cusum_inputs 10 120.633400 169.616699 \n", + "cusum_adaptive_numba cusum_inputs 10 1.774999 3.395800 \n", + "cusum_adaptive_jax cusum_inputs 10 11.058401 13.825000 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 10 25.525001 32.554200 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 10 19.275000 57.133401 \n", + "\n", + " Mean (us) StdDev (us) \\\n", + "cusum_adaptive_pytensor cusum_inputs 135.634676 7.004116 \n", + "cusum_adaptive_numba cusum_inputs 2.035714 0.556027 \n", + "cusum_adaptive_jax cusum_inputs 12.224150 0.747579 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 27.407500 2.626003 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 22.210748 6.481453 \n", + "\n", + " Median (us) IQR (us) \\\n", + "cusum_adaptive_pytensor cusum_inputs 134.108400 7.029201 \n", + "cusum_adaptive_numba cusum_inputs 1.804200 0.050000 \n", + "cusum_adaptive_jax cusum_inputs 12.264600 1.062525 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 26.512500 1.295800 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 21.162501 1.731300 \n", + "\n", + " OPS (Kops/s) Samples \n", + "cusum_adaptive_pytensor cusum_inputs 7.372746 761 \n", + "cusum_adaptive_numba cusum_inputs 491.228092 7 \n", + "cusum_adaptive_jax cusum_inputs 81.805279 34 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 36.486363 5 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 45.023246 31 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cusum_bench.run(\n", + " inputs={\n", + " \"cusum_inputs\": {\"x\": xs, \"alpha\": 0.1, \"k\": 0.5, \"h\": 3.5},\n", + " }\n", + ")\n", + "cusum_bench.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "3e9c3339", + "metadata": {}, + "outputs": [], + "source": [ + "outputs = cusum_adaptive_numba(xs_std, alpha=0.1, k=0.5, h=3.5)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "b85d0c0e", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "name": "series", + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "y": { + "bdata": "EwgzPqBruT9rpRy/bgTIP832Xz9EHPo+z/ieP7TnPT9FEQDADWWcPxiMoj8hRLS+xJdEvofY1r32FsY/bzAnQCSVir2Cow8/3QLnvmxiFUDoBdg+93UEvzmAFD//5YM/veX+PuEwqL3Elzk//NDfPp6tKj95FTo/IgnhPp+mIj975Ie/F1wbvJ9kbr6Hrnm8KqaJvkqAJz8htCq/KAWavg0xcr3ngBFAAYSrP/EeQD8bLyi/aPgDPrypdz8FB5k/QQt2P3nFiz/3P2I/MjA0vn6V2r4eKhfAh2/Rv3+SVr/0f72+dRmyvnGdkr+1GQq/ftDsv5A/Uj/SDQ7AI+eFvZaJhD+94oo/RzXnPx5kpD3v3hDA3ed0vzZxhL8r1hS/W8xev6VO3D4RcJS+aQZuvnmGsr9X07W//iKWv+uaLr+cjWq/NnVWv/2UbL4VXQ6/OVQXPZyMCb/dEQe/4DgPvgShgr/pwcG8zWrTv9msCj7IwC2/M2Pxvqw9EL83SKU/fOjYPp2D2L5f0+g9xAMkvw==", + "dtype": "f4" + } + }, + { + "name": "cum. positive devs.", + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "y": { + "bdata": "AAAAAAAAAAAAAABEMK/kPwAAAAAAAAAAehSuaM7u5j+0832wGSrmPzh52JvHfdE/CEuc28rE4D84k4TswfDPPwAAAAAAAAAACGuKR3Mj1z8UTJD9D8TlPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZc3sqRt+Q/8p4pTVobAUDyGLqClkrwPzC8k/yn1OA/AAAAAAAAAACS2pphBhfzP7wWzGV5vd8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMiqIWA1YPc/4ipz89cr/j/66qLpmv/6P0glbwY0m8g/AAAAAAAAAACQ61Uab8y1P3xpguzfStQ/bHOkbtby0D+Qr1wdvEbSP1gwPTcWH7E/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsMfZaE1fkPwAAAAAAAAAAAAAAAAAAAACsBouUchjrPyIThKOnp/k/rTAePZ0RB0B67b2gYHUDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOO8ujICPRPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4BqbgsostD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoKLiQUGPGPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANYqR3W1ePI/MJ5teFzN9T8CDLrBnZ7nPxT66A5/fOM/AAAAAAAAAAA=", + "dtype": "f8" + } + }, + { + "name": "cum. negative devs.", + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "y": { + "bdata": "AAAAAAAAAAAAAAAAAAAAAJqZmWUcp9Q/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJo3BIX9P/w/YHOGzILc2T8AAAAAAAAAAGBIiylmi8w/hAnv7jNkzT+wbl4kqnG7PwAAAAAAAAAAAAAAAAAAAAAgT5J54cG+PwAAAAAAAAAAeG36X3Lc2T8AAAAAAAAAAAAAAAAAAAAAzBiufmK74D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQsmKFLXuzPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPp4osp/Qu4/dH/BkUCX6T98OGqzcjjqP2pFdeLZ6+I/qGpyxk0O4j8AAAAAAAAAAEAOQ7MVwtQ/WGmYz59Rzj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQZVKPRsN8/OJM/xsR+xz8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArEzLyCOtyT8EXi0U5dLhP7+24zPfjQRAdgxAKddqDUBoJhMajz8PQMK9auhIIA1ALPkfjOWnCkBye6kIcsYNQEsK8mfO0QtAbkVzXlGMEUCR/ijm3QIGQBrN5ASeug9AlaDa7IyQCEDUvW+P4JTzPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMRFreLjDPk/WtHiCcb5+z9gNcaeqe7+P5pC+S/5Q/o/gM5ATABt+T9y/jeN4JDUPwAAAAAAAAAAAAAAAAAAAABqbc+dv7/dP/CnHsl0Z+s/dOcc12bz7T+cIOjGToHgP7ZBcd2mGNM/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0LsFbvUw4T8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "dtype": "f8" + } + }, + { + "name": "Exp. Mean", + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "y": { + "bdata": "AAAAYAJhxj8AAAB4b1fTPzQzM0uD+8o/C9ejLpok1j+KQWCwHIfZPy9uI0X0Gdo/KuOfZJlw3z86JnvgkIXgP2jeEBSx7tA/+JR1OBMP1z/g0mlMX+HcPzCkxfQuvdc/kuCxouoi1D/qFqBZjHPRP9NHQ2pXnNk/UuA3FmDi4z/kSTKf563hP7R14Ej1tOE/d236vxb83D/cSso8KYPkP8apT5Cuz+M/zBiunqMs4D/rr5wrx2ngP+03QAfAEeI/vJiGzgLb4T+FrFhZRJ3fP6JNzgHei+A/Raw5+2JK4D+ltICohMvgP/sIp+cIceE/SLt8oJYa4T/B2wlaNm3hP/XxRBXCktg/9gw+dyUO1j8RclFTGlzSP9wZFtcfbdA/85T0D0Ugyj+oH1wOdePPP34chuYaKsQ/sZkk0lSYvD/tI1Soyji4P+JUeX8RANQ/mP+5MnaT2j+i/0BnsLjcP0UZVOMKpdU/WLDLPxdO1D8dhWo5U3fYP2cRE1q+q90/CPvu3mxt4D/u4aNoa0fiP72xxid6R+M/K9MyYsfJ4D+0FfWDiHzbP97zhe0iPsM/KCTVUT0Anb+9wZzlgPu7v2KKhhpgVMG/WEmsBJMMxL/O7bObVFrQvzqJu0WKK9K/gftbWJwx3L9aYuy1Qh7Uv9zFEIXoJ+C/JmRR2MF/3b9WDRYpGuzTv2d+9Mm1+MW/6HHsUYLFmj/czBCYLiigP+jRleq+Vsm/qNEpo26G0b/kb3KsDGXWvxrLM3tM4Ne/ZdDhTvoO27+OO8sDTJnVv2aC0DleS9W/wttuQhKn1L+WkjDifIPbv8QOycVA7eC/fcABcs384r/XxjRwdUXjv8F/L9iuRuS/x78qPOHt5L/N34yAW5Pjv5/8sQPJZeO/XGNT3vBW4b85puRUNFPhv83IzULoR+G/hQGGIhgA4L+SNBKfgqrhv6FeuhlF89+/L0T60b2p478qCi5cbUPhv4xvKYZ+teG/mBfyY11y4b+ie/OZTIHhv1irHFW6Pte/aM2ZjIw10r9En71BPRjTvyTcXaInddC/IUYhkojp0r8=", + "dtype": "f8" + } + }, + { + "name": "positive alarms", + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "y": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "name": "negative alarms", + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "y": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ], + "layout": { + "legend": { + "orientation": "h", + "x": 0, + "xanchor": "left", + "y": 1.1, + "yanchor": "top" + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#f2f5fa" + }, + "error_y": { + "color": "#f2f5fa" + }, + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "baxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#506784" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "header": { + "fill": { + "color": "#2a3f5f" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#f2f5fa", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#f2f5fa" + }, + "geo": { + "bgcolor": "rgb(17,17,17)", + "lakecolor": "rgb(17,17,17)", + "landcolor": "rgb(17,17,17)", + "showlakes": true, + "showland": true, + "subunitcolor": "#506784" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "dark" + }, + "paper_bgcolor": "rgb(17,17,17)", + "plot_bgcolor": "rgb(17,17,17)", + "polar": { + "angularaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "radialaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "yaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "zaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + } + }, + "shapedefaults": { + "line": { + "color": "#f2f5fa" + } + }, + "sliderdefaults": { + "bgcolor": "#C8D4E3", + "bordercolor": "rgb(17,17,17)", + "borderwidth": 1, + "tickwidth": 0 + }, + "ternary": { + "aaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "baxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "caxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "updatemenudefaults": { + "bgcolor": "#506784", + "borderwidth": 0 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "CUSUM Change Point Detection Algorithm" + }, + "xaxis": { + "title": { + "text": "Time Index" + } + }, + "yaxis": { + "title": { + "text": "Standardized Series Scaled" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = go.Figure()\n", + "fig.add_traces(\n", + " [\n", + " go.Scatter(\n", + " x = np.arange(len(xs)),\n", + " y = xs_std,\n", + " name=\"series\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(len(xs)),\n", + " y = outputs[0],\n", + " name=\"cum. positive devs.\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(len(xs)),\n", + " y = outputs[1],\n", + " name=\"cum. negative devs.\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(len(xs)),\n", + " y = outputs[2],\n", + " name=\"Exp. Mean\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(len(xs)),\n", + " y = outputs[3].astype(np.float16),\n", + " name=\"positive alarms\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(len(xs)),\n", + " y = outputs[4].astype(np.float16),\n", + " name=\"negative alarms\"\n", + " ),\n", + " \n", + " ]\n", + ")\n", + "fig.update_layout(\n", + " title = dict(\n", + " text = \"CUSUM Change Point Detection Algorithm\"\n", + " ),\n", + " xaxis=dict(\n", + " title = \"Time Index\"\n", + " ),\n", + " yaxis=dict(\n", + " title = \"Standardized Series Scaled\"\n", + " ),\n", + " legend=dict(\n", + " yanchor=\"top\",\n", + " y=1.1,\n", + " xanchor=\"left\",\n", + " x=0,\n", + " orientation=\"h\"\n", + " ),\n", + " template=\"plotly_dark\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c2ce03ea", + "metadata": {}, + "source": [ + "## Pruned Exact Linear Time (PELT) Algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "eab4cbb9", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def segment_cost_numba(S1, S2, i, j):\n", + " \"\"\"Cost of segment x[i:j], SSE around mean\"\"\"\n", + " n = j - i\n", + " sum_x = S1[j] - S1[i]\n", + " sum_x2 = S2[j] - S2[i]\n", + " if n > 0:\n", + " return sum_x2 - (sum_x ** 2) / n\n", + " else:\n", + " return np.inf\n", + "\n", + "@jit(nopython=True)\n", + "def pelt_numba(x, beta=10.0):\n", + " \"\"\"\n", + " Pruned Exact Linear Time algorithm for change point detection\n", + "\n", + " Parameters\n", + " ----------\n", + " x: np.ndarray\n", + " The timeseries signal\n", + " beta: float\n", + " Penalty of segmenting the series\n", + "\n", + " Returns\n", + " -------\n", + " C: np.ndarray\n", + " The best costs up to segment t\n", + " last_change: np.ndarray\n", + " The last change point up to segment t\n", + " \"\"\"\n", + " n = len(x)\n", + "\n", + " # cumulative sums for cost\n", + " S1 = np.empty(n+1, dtype=np.float64)\n", + " S2 = np.empty(n+1, dtype=np.float64)\n", + " S1[0], S2[0] = 0.0, 0.0\n", + " for i in range(1, n+1):\n", + " S1[i] = S1[i-1] + x[i-1]\n", + " S2[i] = S2[i-1] + x[i-1]**2\n", + "\n", + " # DP arrays\n", + " C = np.full((n+1,), np.inf)\n", + " C[0] = -beta\n", + " last_change = np.full((n+1,), -1)\n", + " min_size = 3\n", + "\n", + " for t in range(1, n+1):\n", + " costs = np.full(n, np.inf)\n", + " for s in range(n):\n", + " if s < t and (t - s) >= min_size:\n", + " costs[s] = C[s] + segment_cost_numba(S1, S2, s, t) + beta\n", + " best_s = np.argmin(costs)\n", + " C[t] = costs[best_s]\n", + " last_change[t] = best_s\n", + "\n", + " return C, last_change" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "e6997389", + "metadata": {}, + "outputs": [], + "source": [ + "def segment_cost_jax(S1, S2, i, j):\n", + " \"\"\"Cost of segment x[i:j], SSE around mean\"\"\"\n", + " n = j - i\n", + " sum_x = S1[j] - S1[i]\n", + " sum_x2 = S2[j] - S2[i]\n", + " return jnp.where(n > 0, sum_x2 - (sum_x ** 2) / n, jnp.inf)\n", + "\n", + "\n", + "@jax.jit\n", + "def pelt_jax(x, beta=10.0):\n", + " \"\"\"\n", + " Pruned Exact Linear Time algorithm for change point detection\n", + "\n", + " Parameters\n", + " ----------\n", + " x: np.ndarray\n", + " The timeseries signal\n", + " beta: float\n", + " Penalty of segmenting the series\n", + "\n", + " Returns\n", + " -------\n", + " C: jnp.ndarray\n", + " The best costs up to segment t\n", + " last_change: jnp.ndarray\n", + " The last change point up to segment t\n", + " \"\"\"\n", + " n = len(x)\n", + "\n", + " # cumulative sums for cost\n", + " S1 = jnp.concatenate([jnp.array([0.0]), jnp.cumsum(x)])\n", + " S2 = jnp.concatenate([jnp.array([0.0]), jnp.cumsum(x**2)])\n", + "\n", + " # DP arrays\n", + " C = jnp.full((n+1,), jnp.inf)\n", + " C = C.at[0].set(-beta)\n", + " last_change = jnp.full((n+1,), -1)\n", + " min_size = 3\n", + "\n", + " s_all = jnp.arange(n) # all possible candidates\n", + "\n", + " def body(t, carry):\n", + " C, last_change = carry\n", + "\n", + " # Compute cost for all s < t, mask invalid\n", + " # valid = s_all < t & ((t - s_all) >= min_size)\n", + " \n", + " valid = (s_all < t) & ((t - s_all) >= min_size)\n", + " costs = jnp.where(\n", + " valid,\n", + " C[s_all] + segment_cost_jax(S1, S2, s_all, t) + beta,\n", + " jnp.inf\n", + " )\n", + "\n", + " best_s = jnp.argmin(costs)\n", + " C = C.at[t].set(costs[best_s])\n", + " last_change = last_change.at[t].set(best_s)\n", + " return C, last_change\n", + "\n", + " C, last_change = jax.lax.fori_loop(1, n+1, body, (C, last_change))\n", + " return C, last_change" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "094b9e8e", + "metadata": {}, + "outputs": [], + "source": [ + "def segment_cost_pytensor(S1, S2, i, j):\n", + " \"\"\"Cost of segment x[i:j], SSE around mean\"\"\"\n", + " n = j - i\n", + " sum_x = S1[j] - S1[i]\n", + " sum_x2 = S2[j] - S2[i]\n", + " return pt.switch(\n", + " pt.gt(n, 0),\n", + " sum_x2 - (sum_x ** 2) / n,\n", + " np.inf\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "03e5e927", + "metadata": {}, + "outputs": [], + "source": [ + "x_symbolic = pt.vector(\"x\")\n", + "beta_symbolic = pt.scalar(\"beta\")\n", + "n = x_symbolic.shape[0]\n", + "\n", + "# cumulative sums for cost\n", + "S1 = pt.concatenate([pt.as_tensor([0.0]), pt.cumsum(x_symbolic)])\n", + "S2 = pt.concatenate([pt.as_tensor([0.0]), pt.cumsum(x_symbolic**2)])\n", + "\n", + "# DP arrays\n", + "C_init = pt.alloc(np.inf, n+1)\n", + "C_init = pt.set_subtensor(C_init[0], -beta_symbolic)\n", + "last_change_init = pt.alloc(-1, n+1)\n", + "\n", + "s_all = pt.arange(n) # candidate change points\n", + "min_size = 3\n", + "\n", + "def step(t, C_prev, last_change_prev, S1, S2, beta_symbolic, s_all):\n", + " # valid = (s_all < t) & ((t - s_all) >= min_size)\n", + " valid = pt.and_(pt.lt(s_all, t), pt.ge(t - s_all, min_size))\n", + "\n", + " # compute costs for all candidates\n", + " costs, _ = pytensor.scan(\n", + " fn=lambda s: pt.switch(\n", + " valid[s],\n", + " C_prev[s] + segment_cost_pytensor(S1, S2, s, t) + beta_symbolic,\n", + " np.inf\n", + " ),\n", + " sequences=[pt.arange(n)]\n", + " )\n", + " costs = costs.flatten()\n", + "\n", + " best_s = pt.argmin(costs, axis=0)\n", + " C_new = pt.set_subtensor(C_prev[t], costs[best_s])\n", + " last_change_new = pt.set_subtensor(last_change_prev[t], best_s)\n", + "\n", + " return C_new, last_change_new\n", + "\n", + "(C_vals, last_change_vals), _ = pytensor.scan(\n", + " fn=step,\n", + " sequences=[pt.arange(1, n+1)],\n", + " outputs_info=[C_init, last_change_init],\n", + " non_sequences=[S1, S2, beta_symbolic, s_all]\n", + ")\n", + "\n", + "pelt_pytensor = pytensor.function([x_symbolic, beta_symbolic], [C_vals[-1], last_change_vals[-1]], trust_input=True)\n", + "pelt_pytensor_numba = pytensor.function(inputs=[x_symbolic, beta_symbolic], outputs=[C_vals[-1], last_change_vals[-1]], mode=\"NUMBA\", trust_input=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "69aea9a2", + "metadata": {}, + "outputs": [], + "source": [ + "pelt_bench = Benchmarker(\n", + " functions=[pelt_pytensor, pelt_numba, jax.block_until_ready(pelt_jax), pelt_pytensor_numba], \n", + " names=['pelt_pytensor', 'pelt_numba', 'pelt_jax', 'pelt_pytensor_numba'],\n", + " number=10\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "5aee4a18", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
pelt_pytensorpelt_inputs1011427.62910012441.870812163.819422287.09449212253.829101176.5875000.0822119
pelt_numbapelt_inputs1019.29589922.012520.3492000.99124720.3209001.31670149.1419825
pelt_jaxpelt_inputs1015.06669965.604250.39955817.81139456.8791995.26880019.84144419
pelt_pytensor_numbapelt_inputs102507.9375002881.28752627.499160130.4344742581.90409926.6666990.3805905
\n", + "
" + ], + "text/plain": [ + " Loops Min (us) Max (us) \\\n", + "pelt_pytensor pelt_inputs 10 11427.629100 12441.8708 \n", + "pelt_numba pelt_inputs 10 19.295899 22.0125 \n", + "pelt_jax pelt_inputs 10 15.066699 65.6042 \n", + "pelt_pytensor_numba pelt_inputs 10 2507.937500 2881.2875 \n", + "\n", + " Mean (us) StdDev (us) Median (us) \\\n", + "pelt_pytensor pelt_inputs 12163.819422 287.094492 12253.829101 \n", + "pelt_numba pelt_inputs 20.349200 0.991247 20.320900 \n", + "pelt_jax pelt_inputs 50.399558 17.811394 56.879199 \n", + "pelt_pytensor_numba pelt_inputs 2627.499160 130.434474 2581.904099 \n", + "\n", + " IQR (us) OPS (Kops/s) Samples \n", + "pelt_pytensor pelt_inputs 176.587500 0.082211 9 \n", + "pelt_numba pelt_inputs 1.316701 49.141982 5 \n", + "pelt_jax pelt_inputs 5.268800 19.841444 19 \n", + "pelt_pytensor_numba pelt_inputs 26.666699 0.380590 5 " + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pelt_bench.run(\n", + " inputs={\n", + " \"pelt_inputs\": {\"x\": xs_std, \"beta\": 2. * np.log(len(xs_std))},\n", + " }\n", + ")\n", + "pelt_bench.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "47cae530", + "metadata": {}, + "outputs": [], + "source": [ + "outputs = pelt_numba(xs_std, 2. * np.log(len(xs_std)))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "7b395b06", + "metadata": {}, + "outputs": [], + "source": [ + "def plot_pelt_diagnostics(x, cps, C):\n", + " \"\"\"\n", + " Diagnostic plots for PELT changepoint detection.\n", + " \n", + " Args:\n", + " x: 1D array, original time series\n", + " C: 1D array, cumulative DP cost from pelt()\n", + " cps: list of changepoint indices (sorted ascending)\n", + " \"\"\"\n", + " n = len(x)\n", + " cps_full = [0] + cps + [n]\n", + "\n", + " # Segment means, std, SSE\n", + " segment_means = []\n", + " segment_stds = []\n", + " segment_costs = []\n", + " for start, end in zip(cps_full[:-1], cps_full[1:]):\n", + " seg = x[start:end]\n", + " mean = np.mean(seg)\n", + " std = np.std(seg)\n", + " cost = np.sum((seg - mean)**2)\n", + " segment_means.append(mean)\n", + " segment_stds.append(std)\n", + " segment_costs.append(cost)\n", + "\n", + " # Step function for segment mean\n", + " mean_step = np.zeros(n)\n", + " for i, (start, end) in enumerate(zip(cps_full[:-1], cps_full[1:])):\n", + " mean_step[start:end] = segment_means[i]\n", + "\n", + " # Step function for segment std\n", + " std_step = np.zeros(n)\n", + " for i, (start, end) in enumerate(zip(cps_full[:-1], cps_full[1:])):\n", + " std_step[start:end] = segment_stds[i]\n", + "\n", + " if len(x) < 20:\n", + " title1 = \"Warning: Sample size is small - Detected Changepoints\"\n", + " else:\n", + " title1 = \"Detected Changepoints\"\n", + "\n", + " fig = make_subplots(\n", + " rows=4, \n", + " cols=1,\n", + " subplot_titles=(title1, \"Average Shifts\", \"Variability Shifts\", \"Cumulative Cost\")\n", + " )\n", + "\n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x = np.arange(len(x)),\n", + " y = x,\n", + " line_color=\"royalblue\",\n", + " name = \"Actuals\",\n", + " mode=\"lines\",\n", + " showlegend=False,\n", + " hovertemplate=\"Time Point: %{x}
Actual: %{y}\"\n", + " ),\n", + " row=1, col=1\n", + " )\n", + "\n", + " for cp in cps:\n", + " fig.add_vline(x=cp, line_dash='dash', line_color=\"red\", row=1, col=1)\n", + "\n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x = np.arange(len(x)),\n", + " y = x,\n", + " name = \"Actuals\",\n", + " mode=\"lines\",\n", + " line_color=\"rgba(105, 105, 105, 0.25)\",\n", + " showlegend=False,\n", + " hoverinfo=\"skip\"\n", + " ),\n", + " row=2, col=1\n", + " )\n", + "\n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x = np.arange(len(x)),\n", + " y = mean_step,\n", + " name = \"Average\",\n", + " line_color=\"royalblue\",\n", + " showlegend=False,\n", + " hovertemplate=\"Time Point: %{x}
Average: %{y}\"\n", + " ),\n", + " row=2, col=1\n", + " )\n", + "\n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x = np.arange(len(x)),\n", + " y = std_step,\n", + " name = \"Standard Deviation\",\n", + " line_color=\"royalblue\",\n", + " showlegend=False,\n", + " hovertemplate=\"Time Point: %{x}
Standard Deviation: %{y}\"\n", + " ),\n", + " row=3, col=1\n", + " )\n", + "\n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x = np.arange(len(x)),\n", + " y = C,\n", + " name = \"Cumulative Cost\",\n", + " line_color=\"royalblue\",\n", + " showlegend=False,\n", + " hovertemplate=\"Time Point: %{x}
Cost: %{y}\"\n", + " ),\n", + " row=4, col=1\n", + " )\n", + "\n", + " for cp in cps:\n", + " fig.add_vline(x=cp, line_dash='dash', line_color=\"red\", row=4, col=1)\n", + "\n", + " return fig.update_layout(height=1000, width=1200, template=\"plotly_dark\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "e1de7df5", + "metadata": {}, + "outputs": [], + "source": [ + "def get_changepoints(last_change, n):\n", + " \"\"\"\n", + " Backtrack changepoints from last_change array.\n", + " \n", + " Args:\n", + " last_change: array from pelt()\n", + " n: length of input series\n", + "\n", + " Returns:\n", + " list of changepoint indices (sorted ascending)\n", + " \"\"\"\n", + " cps = []\n", + " t = n\n", + " while t > 0:\n", + " s = int(last_change[t])\n", + " if s <= 0:\n", + " break\n", + " cps.append(s)\n", + " t = s\n", + " return list(reversed(cps))" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "b73d80ac", + "metadata": {}, + "outputs": [], + "source": [ + "cps = get_changepoints(outputs[1], n=len(xs_std))" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "e2e376de", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "Time Point: %{x}
Actual: %{y}", + "line": { + "color": "royalblue" + }, + "mode": "lines", + "name": "Actuals", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "xaxis": "x", + "y": { + "bdata": "crKPQg66zEImAVRC0TDSQsA8sUK7uZ5CmtPCQuLcqkJSxp1BpNzBQjYqxELV5mxCPz58QjlLgkIaeNFCDT4CQ/kThEIfNKJCfGdjQson90IeiZtCvA5dQhUdo0JCsbhCaSyfQqVig0JFDqpC0UOcQqpDp0LMJapCB2GcQg3DpULb5yhCp92GQtxUeEIKl4ZCvuB0QnGrpkIUvk5CW9BxQrR8hEIAQPRCnoXHQgxHq0KGr09CvH6NQj2stUL3mcBCql61QrGju0JFqrFCPsd9Qum6ZULcNzFBVbLjQVNSPkJrLGtCpU5tQt7gIEJQ8lpC8bO6QZarrkJDyGdBADCEQn7uuELSTrtCtd3dQoUqi0Js6VZBl/cyQht9K0KC7VZCDz47QsDvm0LT23JCrV14QjP9CEKyhAZC7j0eQjZITUKi1zZCSV0+Qj+AeELKWVlCIBeJQiEnW0K6FFxCaZ6AQp/YLELaL4ZCy7rgQQzPjULdmU1CU3ZhQuWlWEJIMMVCUp6bQhUeZkJixIxCDT9RQg==", + "dtype": "f4" + }, + "yaxis": "y" + }, + { + "hoverinfo": "skip", + "line": { + "color": "rgba(105, 105, 105, 0.25)" + }, + "mode": "lines", + "name": "Actuals", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "xaxis": "x2", + "y": { + "bdata": "crKPQg66zEImAVRC0TDSQsA8sUK7uZ5CmtPCQuLcqkJSxp1BpNzBQjYqxELV5mxCPz58QjlLgkIaeNFCDT4CQ/kThEIfNKJCfGdjQson90IeiZtCvA5dQhUdo0JCsbhCaSyfQqVig0JFDqpC0UOcQqpDp0LMJapCB2GcQg3DpULb5yhCp92GQtxUeEIKl4ZCvuB0QnGrpkIUvk5CW9BxQrR8hEIAQPRCnoXHQgxHq0KGr09CvH6NQj2stUL3mcBCql61QrGju0JFqrFCPsd9Qum6ZULcNzFBVbLjQVNSPkJrLGtCpU5tQt7gIEJQ8lpC8bO6QZarrkJDyGdBADCEQn7uuELSTrtCtd3dQoUqi0Js6VZBl/cyQht9K0KC7VZCDz47QsDvm0LT23JCrV14QjP9CEKyhAZC7j0eQjZITUKi1zZCSV0+Qj+AeELKWVlCIBeJQiEnW0K6FFxCaZ6AQp/YLELaL4ZCy7rgQQzPjULdmU1CU3ZhQuWlWEJIMMVCUp6bQhUeZkJixIxCDT9RQg==", + "dtype": "f4" + }, + "yaxis": "y2" + }, + { + "hovertemplate": "Time Point: %{x}
Average: %{y}", + "line": { + "color": "royalblue" + }, + "name": "Average", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "xaxis": "x2", + "y": { + "bdata": "AAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0A=", + "dtype": "f8" + }, + "yaxis": "y2" + }, + { + "hovertemplate": "Time Point: %{x}
Standard Deviation: %{y}", + "line": { + "color": "royalblue" + }, + "name": "Standard Deviation", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "xaxis": "x3", + "y": { + "bdata": "AAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEA=", + "dtype": "f8" + }, + "yaxis": "y3" + }, + { + "hovertemplate": "Time Point: %{x}
Cost: %{y}", + "line": { + "color": "royalblue" + }, + "name": "Cumulative Cost", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", + "dtype": "i1" + }, + "xaxis": "x4", + "y": { + "bdata": "FlW1u7FrIsAAAAAAAADwfwAAAAAAAPB/GLavc4BMAUDuWfXxLk8KQCihxbvZpgpA+GWcdwPsCkAc0IByO0YNQCpTshE9Rg1ACQ/rumOtJEDKfEI+QMolQJRGWswO1CZA++q+NFpuKEDgzqs38FMpQFxR+34P5ylAjOVj3qtPLECXctoKi2MyQMS0kJ6K1TJA+Lg/G6DVMkCbvJuG3NYzQOTWCiFN8zZAxe4lGWP8NkCb99NJqzA4QPzb/J3TMDhASqHwYRhoOECOPIK0lGk4QBBppccP0zhAU6p3v9faOEBEWqcbNd44QDKb+CyX4ThAaDjGNQLpOED253yFk+w4QASfic8m7jhAhGEqbHt5O0DxpQbZSrw7QOvsDC2XPzxAqggFie56PECUEx+FD/88QFces4iHCj1AYkXWGxw/PkDaKxqMsb8+QNGtqNEb9D5AbVgiVFw2QUBw4eUdRZ1BQNO+V4lHqEFANNX8MpREQkCqLNUvXlBCQAFdO2CudEJAOWepMyG8QkBN2Bx4F9xCQM1Vd9MoDUNAYehSqbchQ0DgNxL541hDQL5D69DfvkNAAuuk+VelR0BiARhbcOhIQKptWI2C7khApsCfqvRqSUCsBbj9p6tJQJQWctwTrklAdukieLzHSUCeMGIGPCJKQISYkf/OuEtAdIi7oOmMTECCy0EctfFMQGClt0VApU5AOaGK/t4VUECCNZmlJN5QQJ5tpd+aJlFAwg0F7VpQUkBP9IMtw1tSQJv4N4FMalJADsyvdk5qUkAakzMXym9SQJ7Q4pDPrlJALpTYUaeyUkC79Er/FbhSQGnTtfJl51JAUsKbIe0VU0D18sucWCtTQDaZaOa2K1NAa7C7T5wxU0De9LMymzRTQAoF7lI5PlNAEY25AGw+U0CPjy+sfVhTQO9sKPusWFNAhutuf+tYU0CTsVpedGVTQM/B7z6/cVNA4fFzHJ2FU0DQqSGWI85TQKpRKwn271NA0eX6xInwU0ARAhG3V/FTQCijb2Nd8VNAoDnTeevMVEC5+1vEFQdVQBqbQ7iqB1VAC0COGpwgVUB9TompxyFVQA==", + "dtype": "f8" + }, + "yaxis": "y4" + } + ], + "layout": { + "annotations": [ + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Detected Changepoints", + "x": 0.5, + "xanchor": "center", + "xref": "paper", + "y": 1, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Average Shifts", + "x": 0.5, + "xanchor": "center", + "xref": "paper", + "y": 0.71875, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Variability Shifts", + "x": 0.5, + "xanchor": "center", + "xref": "paper", + "y": 0.4375, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Cumulative Cost", + "x": 0.5, + "xanchor": "center", + "xref": "paper", + "y": 0.15625, + "yanchor": "bottom", + "yref": "paper" + } + ], + "height": 1000, + "shapes": [ + { + "line": { + "color": "red", + "dash": "dash" + }, + "type": "line", + "x0": 51, + "x1": 51, + "xref": "x", + "y0": 0, + "y1": 1, + "yref": "y domain" + }, + { + "line": { + "color": "red", + "dash": "dash" + }, + "type": "line", + "x0": 51, + "x1": 51, + "xref": "x4", + "y0": 0, + "y1": 1, + "yref": "y4 domain" + } + ], + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#f2f5fa" + }, + "error_y": { + "color": "#f2f5fa" + }, + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "baxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#506784" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "header": { + "fill": { + "color": "#2a3f5f" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#f2f5fa", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#f2f5fa" + }, + "geo": { + "bgcolor": "rgb(17,17,17)", + "lakecolor": "rgb(17,17,17)", + "landcolor": "rgb(17,17,17)", + "showlakes": true, + "showland": true, + "subunitcolor": "#506784" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "dark" + }, + "paper_bgcolor": "rgb(17,17,17)", + "plot_bgcolor": "rgb(17,17,17)", + "polar": { + "angularaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "radialaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "yaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "zaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + } + }, + "shapedefaults": { + "line": { + "color": "#f2f5fa" + } + }, + "sliderdefaults": { + "bgcolor": "#C8D4E3", + "bordercolor": "rgb(17,17,17)", + "borderwidth": 1, + "tickwidth": 0 + }, + "ternary": { + "aaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "baxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "caxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "updatemenudefaults": { + "bgcolor": "#506784", + "borderwidth": 0 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + } + } + }, + "width": 1200, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 1 + ] + }, + "xaxis2": { + "anchor": "y2", + "domain": [ + 0, + 1 + ] + }, + "xaxis3": { + "anchor": "y3", + "domain": [ + 0, + 1 + ] + }, + "xaxis4": { + "anchor": "y4", + "domain": [ + 0, + 1 + ] + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0.84375, + 1 + ] + }, + "yaxis2": { + "anchor": "x2", + "domain": [ + 0.5625, + 0.71875 + ] + }, + "yaxis3": { + "anchor": "x3", + "domain": [ + 0.28125, + 0.4375 + ] + }, + "yaxis4": { + "anchor": "x4", + "domain": [ + 0, + 0.15625 + ] + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_pelt_diagnostics(xs, cps, outputs[0])" + ] + }, + { + "cell_type": "markdown", + "id": "09f2e235", + "metadata": {}, + "source": [ + "# Kalman Filter Algorithms" + ] + }, + { + "cell_type": "markdown", + "id": "1c42336f", + "metadata": {}, + "source": [ + "## Linear Gaussian Kalman Filter" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "5004eeab", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def atrocious_kalman_filter_numba(z, F, H, Q, R, x0, P0):\n", + " \"\"\"\n", + " This implementation of the Kalman filter is Atrocious and in standard Python would be a \n", + " BIG NO-NO. That being said this version SIGNIFICANTLY reduces Numba Compilation time. \n", + " \n", + " Linear Gaussian Kalman filter algorithm\n", + "\n", + " Parameters\n", + " ----------\n", + " z: np.ndarray\n", + " shape (T, m) - observations\n", + " F: np.ndarray\n", + " state transition matrix - shape (n, n)\n", + " H: np.ndarray\n", + " observation/design matrix - shape (m, n)\n", + " Q: np.ndarray\n", + " process noise covariance - shape (n, n)\n", + " R: np.ndarray\n", + " observation noise covariance - shape (m, m)\n", + " x0: np.ndarray\n", + " initial state mean - shape (n,)\n", + " P0: np.ndarray\n", + " initial state covariance - shape (n, n)\n", + "\n", + " Returns\n", + " -------\n", + " xs: np.ndarray\n", + " shape (T, n) - filtered state means\n", + " Ps: np.ndarray\n", + " shape (T, n, n) - filtered state covariances\n", + " \"\"\"\n", + " T = z.shape[0]\n", + " m = z.shape[1]\n", + " n = x0.shape[0]\n", + "\n", + " xs = np.empty((T, n), dtype=np.float32)\n", + " Ps = np.empty((T, n, n), dtype=np.float32)\n", + "\n", + " # local working arrays\n", + " x = np.empty(n, dtype=np.float32)\n", + " for i in range(n):\n", + " x[i] = x0[i]\n", + " P = np.empty((n, n), dtype=np.float32)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " P[i, j] = P0[i, j]\n", + "\n", + " # temporary matrices/vectors\n", + " x_pred = np.empty((T, n), dtype=np.float32)\n", + " P_pred = np.empty((T, n, n), dtype=np.float32)\n", + " y = np.empty(m, dtype=np.float32)\n", + " S = np.empty((m, m), dtype=np.float32)\n", + " K = np.empty((n, m), dtype=np.float32)\n", + " I_n = np.eye(n, dtype=np.float32)\n", + "\n", + " for t in range(T):\n", + " # === Predict ===\n", + " # x_pred = F @ x\n", + " for i in range(n):\n", + " s = 0.0\n", + " for j in range(n):\n", + " s += F[i, j] * x[j]\n", + " x_pred[t, i] = s\n", + "\n", + " # P_pred = F @ P @ F.T + Q\n", + " # temp = F @ P\n", + " temp = np.empty((n, n), dtype=np.float32)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " s = 0.0\n", + " for k in range(n):\n", + " s += F[i, k] * P[k, j]\n", + " temp[i, j] = s\n", + " # P_pred = temp @ F.T\n", + " for i in range(n):\n", + " for j in range(n):\n", + " s = 0.0\n", + " for k in range(n):\n", + " s += temp[i, k] * F[j, k] # F.T[k, j] = F[j, k]\n", + " P_pred[t, i, j] = s + Q[i, j]\n", + "\n", + " # === Update ===\n", + " # y = z[t] - H @ x_pred\n", + " for i in range(m):\n", + " s = 0.0\n", + " for j in range(n):\n", + " s += H[i, j] * x_pred[t, j]\n", + " y[i] = z[t, i] - s\n", + "\n", + " # S = H @ P_pred @ H.T + R\n", + " # temp2 = H @ P_pred\n", + " temp2 = np.empty((m, n), dtype=np.float32)\n", + " for i in range(m):\n", + " for j in range(n):\n", + " s = 0.0\n", + " for k in range(n):\n", + " s += H[i, k] * P_pred[t, k, j]\n", + " temp2[i, j] = s\n", + " # S = temp2 @ H.T\n", + " for i in range(m):\n", + " for j in range(m):\n", + " s = 0.0\n", + " for k in range(n):\n", + " s += temp2[i, k] * H[j, k] # H.T[k,j] = H[j,k]\n", + " S[i, j] = s + R[i, j]\n", + "\n", + " # K = P_pred @ H.T @ inv(S)\n", + " # first compute P_pred @ H.T -> (n, m)\n", + " P_Ht = np.empty((n, m), dtype=np.float32)\n", + " for i in range(n):\n", + " for j in range(m):\n", + " s = 0.0\n", + " for k in range(n):\n", + " s += P_pred[t, i, k] * H[j, k] # H.T[k,j] = H[j,k]\n", + " P_Ht[i, j] = s\n", + "\n", + " # invert S\n", + " S_inv = np.linalg.inv(S)\n", + "\n", + " # K = P_Ht @ S_inv (n,m) @ (m,m) -> (n,m)\n", + " for i in range(n):\n", + " for j in range(m):\n", + " s = 0.0\n", + " for k in range(m):\n", + " s += P_Ht[i, k] * S_inv[k, j]\n", + " K[i, j] = s\n", + "\n", + " # x = x_pred + K @ y\n", + " for i in range(n):\n", + " s = 0.0\n", + " for j in range(m):\n", + " s += K[i, j] * y[j]\n", + " x[i] = x_pred[t, i] + s\n", + "\n", + " # P = (I - K H) P_pred\n", + " # compute (I - K H)\n", + " KH = np.empty((n, n), dtype=np.float32)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " s = 0.0\n", + " for k in range(m):\n", + " s += K[i, k] * H[k, j]\n", + " KH[i, j] = s\n", + "\n", + " I_minus_KH = np.empty((n, n), dtype=np.float32)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " I_minus_KH[i, j] = I_n[i, j] - KH[i, j]\n", + "\n", + " # P = I_minus_KH @ P_pred\n", + " for i in range(n):\n", + " for j in range(n):\n", + " s = 0.0\n", + " for k in range(n):\n", + " s += I_minus_KH[i, k] * P_pred[t, k, j]\n", + " P[i, j] = s\n", + "\n", + " # store results\n", + " for i in range(n):\n", + " xs[t, i] = x[i]\n", + " for i in range(n):\n", + " for j in range(n):\n", + " Ps[t, i, j] = P[i, j]\n", + "\n", + " return xs, Ps, x_pred, P_pred\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "25bcb14e", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def kalman_filter_numba(z, F, H, Q, R, x0, P0):\n", + " \"\"\"\n", + " Linear Gaussian Kalman filter algorithm\n", + "\n", + " Parameters\n", + " ----------\n", + " z: np.ndarray\n", + " shape (T, m) - observations\n", + " F: np.ndarray\n", + " state transition matrix - shape (n, n)\n", + " H: np.ndarray\n", + " observation/design matrix - shape (m, n)\n", + " Q: np.ndarray\n", + " process noise covariance - shape (n, n)\n", + " R: np.ndarray\n", + " observation noise covariance - shape (m, m)\n", + " x0: np.ndarray\n", + " initial state mean - shape (n,)\n", + " P0: np.ndarray\n", + " initial state covariance - shape (n, n)\n", + "\n", + " Returns\n", + " -------\n", + " xs: np.ndarray\n", + " shape (T, n) - filtered state means\n", + " Ps: np.ndarray\n", + " shape (T, n, n) - filtered state covariances\n", + " \"\"\"\n", + " T, m = z.shape\n", + " n = x0.shape[0]\n", + "\n", + " xs = np.zeros((T, n), dtype=np.float32)\n", + " Ps = np.zeros((T, n, n), dtype=np.float32)\n", + "\n", + " x_pred = np.zeros((T, n), dtype=np.float32)\n", + " P_pred = np.zeros((T, n, n), dtype=np.float32)\n", + "\n", + " x = x0.copy()\n", + " P = P0.copy()\n", + "\n", + " I = np.eye(n, dtype=np.float32)\n", + "\n", + " for t in range(T):\n", + " # --- Predict ---\n", + " x_pred[t] = F @ x\n", + " P_pred[t] = F @ P @ F.T + Q\n", + "\n", + " # --- Update ---\n", + " y = z[t] - H @ x_pred[t]\n", + " S = H @ P_pred[t] @ H.T + R\n", + " K = P_pred[t] @ H.T @ np.linalg.inv(S)\n", + "\n", + " x = x_pred[t] + K @ y\n", + " P = (I - K @ H) @ P_pred[t]\n", + "\n", + " xs[t] = x\n", + " Ps[t] = P\n", + "\n", + " return xs, Ps, x_pred, P_pred" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "cd715dfb", + "metadata": {}, + "outputs": [], + "source": [ + "@jax.jit\n", + "def kalman_filter_jax(z, F, H, Q, R, x0, P0):\n", + " \"\"\"\n", + " Linear Gaussian Kalman filter algorithm\n", + "\n", + " Parameters\n", + " ----------\n", + " z: np.ndarray\n", + " shape (T, m) - observations\n", + " F: np.ndarray\n", + " state transition matrix - shape (n, n)\n", + " H: np.ndarray\n", + " observation/design matrix - shape (m, n)\n", + " Q: np.ndarray\n", + " process noise covariance - shape (n, n)\n", + " R: np.ndarray\n", + " observation noise covariance - shape (m, m)\n", + " x0: np.ndarray\n", + " initial state mean - shape (n,)\n", + " P0: np.ndarray\n", + " initial state covariance - shape (n, n)\n", + "\n", + " Returns\n", + " -------\n", + " xs: jnp.ndarray\n", + " shape (T, n) - filtered state means\n", + " Ps: jnp.ndarray\n", + " shape (T, n, n) - filtered state covariances\n", + " \"\"\"\n", + "\n", + " n = x0.shape[0]\n", + " I = jnp.eye(n)\n", + " X_pred_init = jnp.zeros((1,))\n", + " P_pred_init = jnp.zeros((1, 1,))\n", + "\n", + " def step(carry, z_t):\n", + " x, P, _, _ = carry\n", + "\n", + " # --- Predict ---\n", + " x_pred = F @ x\n", + " P_pred = F @ P @ F.T + Q\n", + "\n", + " # --- Update ---\n", + " y = z_t - H @ x_pred\n", + " S = H @ P_pred @ H.T + R\n", + " K = P_pred @ H.T @ jnp.linalg.inv(S)\n", + "\n", + " x_new = x_pred + K @ y\n", + " P_new = (I - K @ H) @ P_pred\n", + "\n", + " return (x_new, P_new, x_pred, P_pred), (x_new, P_new, x_pred, P_pred)\n", + "\n", + " # run scan\n", + " (_, _, _, _), (xs, Ps, x_pred, P_pred) = jax.lax.scan(step, (x0, P0, X_pred_init, P_pred_init), z)\n", + "\n", + " return xs, Ps, x_pred, P_pred" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "5af37c40", + "metadata": {}, + "outputs": [], + "source": [ + "z_symbolic = pt.matrix(\"z\")\n", + "F_symbolic = pt.matrix(\"F\")\n", + "H_symbolic = pt.matrix(\"H\")\n", + "Q_symbolic = pt.matrix(\"Q\")\n", + "R_symbolic = pt.matrix(\"R\")\n", + "x0_symbolic = pt.vector(\"x0\")\n", + "P0_symbolic = pt.matrix(\"P0\")\n", + "\n", + "n = x0_symbolic.shape[0]\n", + "I = pt.eye(n)\n", + "X_pred_init = pt.zeros_like(x0_symbolic)\n", + "P_pred_init = pt.zeros_like(P0_symbolic)\n", + "\n", + "def step(z_t, x, P, x_pred, P_pred, F_symbolic, H_symbolic, Q_symbolic, R_symbolic, I):\n", + "\n", + " # --- Predict ---\n", + " x_pred = F_symbolic @ x\n", + " P_pred = F_symbolic @ P @ F_symbolic.T + Q_symbolic\n", + "\n", + " # --- Update ---\n", + " y = z_t - H_symbolic @ x_pred\n", + " S = H_symbolic @ P_pred @ H_symbolic.T + R_symbolic\n", + " K = P_pred @ H_symbolic.T @ pt.linalg.inv(S)\n", + "\n", + " x_new = x_pred + K @ y\n", + " P_new = (I - K @ H_symbolic) @ P_pred\n", + "\n", + " return x_new, P_new, x_pred, P_pred\n", + "\n", + "# run scan\n", + "(xs, Ps, x_pred, P_pred), _ = pytensor.scan(\n", + " fn=step,\n", + " outputs_info=[x0_symbolic, P0_symbolic, X_pred_init, P_pred_init],\n", + " sequences=[z_symbolic],\n", + " non_sequences=[F_symbolic, H_symbolic, Q_symbolic, R_symbolic, I]\n", + ")\n", + "\n", + "kalman_filter_pytensor = pytensor.function([z_symbolic, F_symbolic, H_symbolic, Q_symbolic, R_symbolic, x0_symbolic, P0_symbolic], [xs, Ps, x_pred, P_pred], trust_input=True)\n", + "\n", + "kalman_filter_pytensor_numba = pytensor.function([z_symbolic, F_symbolic, H_symbolic, Q_symbolic, R_symbolic, x0_symbolic, P0_symbolic], [xs, Ps, x_pred, P_pred], mode=\"NUMBA\", trust_input=True)\n", + "kalman_filter_pytensor_jax = pytensor.function([z_symbolic, F_symbolic, H_symbolic, Q_symbolic, R_symbolic, x0_symbolic, P0_symbolic], [xs, Ps, x_pred, P_pred], mode=\"JAX\", trust_input=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "3c9e7254", + "metadata": {}, + "outputs": [], + "source": [ + "T = 500\n", + "F = np.array([[1.0]]).astype(np.float32)\n", + "H = np.array([[1.0]]).astype(np.float32)\n", + "Q = np.array([[0.01]]).astype(np.float32)\n", + "R = np.array([[0.1]]).astype(np.float32)\n", + "x0 = np.array([0.0]).astype(np.float32)\n", + "P0 = np.array([[1.0]]).astype(np.float32)\n", + "\n", + "true = 1.0\n", + "z = (true + 0.4*np.random.randn(T)).reshape(T, 1).astype(np.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "00472afd", + "metadata": {}, + "outputs": [], + "source": [ + "kalman_filter_bench = Benchmarker(\n", + " functions=[kalman_filter_pytensor, atrocious_kalman_filter_numba, kalman_filter_numba, jax.block_until_ready(kalman_filter_jax), kalman_filter_pytensor_numba, jax.block_until_ready(kalman_filter_pytensor_jax)], \n", + " names=['kalman_filter_pytensor', 'atrocious_kalman_filter_numba', 'kalman_filter_numba', 'kalman_filter_jax', 'kalman_filter_pytensor_numba', 'kalman_filter_pytensor_jax'],\n", + " number=10\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "68ec703d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/qv/63yqp4p50630y7pqfgcbgtq80000gn/T/tmpvmdj39to:35: NumbaWarning:\n", + "\n", + "\u001b[1m\u001b[1mCannot cache compiled function \"scan\" as it uses dynamic globals (such as ctypes pointers and large global arrays)\u001b[0m\u001b[0m\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
kalman_filter_pytensorkalman_filter_inputs106024.8665996579.8458006250.349981153.0711066202.177100232.7593750.15999116
atrocious_kalman_filter_numbakalman_filter_inputs10321.066599339.383300326.6883006.500478324.7874991.7459013.0610225
kalman_filter_numbakalman_filter_inputs10661.045800699.420800679.64500015.146345678.95839928.6166001.4713565
kalman_filter_jaxkalman_filter_inputs10311.850000404.729199349.46667630.904895345.98330153.4541022.86150317
kalman_filter_pytensor_numbakalman_filter_inputs10849.591600914.716700886.17166022.541980890.61670026.8916991.1284505
kalman_filter_pytensor_jaxkalman_filter_inputs10338.316600393.687500360.70655815.525106359.57499925.8312502.77233719
\n", + "
" + ], + "text/plain": [ + " Loops Min (us) \\\n", + "kalman_filter_pytensor kalman_filter_inputs 10 6024.866599 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 10 321.066599 \n", + "kalman_filter_numba kalman_filter_inputs 10 661.045800 \n", + "kalman_filter_jax kalman_filter_inputs 10 311.850000 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 10 849.591600 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 10 338.316600 \n", + "\n", + " Max (us) Mean (us) \\\n", + "kalman_filter_pytensor kalman_filter_inputs 6579.845800 6250.349981 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 339.383300 326.688300 \n", + "kalman_filter_numba kalman_filter_inputs 699.420800 679.645000 \n", + "kalman_filter_jax kalman_filter_inputs 404.729199 349.466676 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 914.716700 886.171660 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 393.687500 360.706558 \n", + "\n", + " StdDev (us) Median (us) \\\n", + "kalman_filter_pytensor kalman_filter_inputs 153.071106 6202.177100 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 6.500478 324.787499 \n", + "kalman_filter_numba kalman_filter_inputs 15.146345 678.958399 \n", + "kalman_filter_jax kalman_filter_inputs 30.904895 345.983301 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 22.541980 890.616700 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 15.525106 359.574999 \n", + "\n", + " IQR (us) OPS (Kops/s) \\\n", + "kalman_filter_pytensor kalman_filter_inputs 232.759375 0.159991 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 1.745901 3.061022 \n", + "kalman_filter_numba kalman_filter_inputs 28.616600 1.471356 \n", + "kalman_filter_jax kalman_filter_inputs 53.454102 2.861503 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 26.891699 1.128450 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 25.831250 2.772337 \n", + "\n", + " Samples \n", + "kalman_filter_pytensor kalman_filter_inputs 16 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 5 \n", + "kalman_filter_numba kalman_filter_inputs 5 \n", + "kalman_filter_jax kalman_filter_inputs 17 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 5 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 19 " + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kalman_filter_bench.run(\n", + " inputs={\n", + " \"kalman_filter_inputs\": {\"z\": z, \"F\": F, \"H\": H, \"Q\": Q, \"R\": R, \"x0\": x0, \"P0\": P0},\n", + " }\n", + ")\n", + "kalman_filter_bench.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "37526f86", + "metadata": {}, + "outputs": [], + "source": [ + "xs, Ps, x_pred, P_pred = kalman_filter_jax(z, F, H, Q, R, x0, P0)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "231140ba", + "metadata": {}, + "outputs": [], + "source": [ + "def compute_pred_intervals(z, x_pred, P_pred, H, R, zscore=1.96):\n", + " T = z.shape[0]\n", + " m = H.shape[0]\n", + " mean = np.zeros((T, m))\n", + " lower = np.zeros((T, m))\n", + " upper = np.zeros((T, m))\n", + " outside = np.zeros(T, dtype=np.bool_)\n", + "\n", + " for t in range(T):\n", + " mean[t] = H @ x_pred[t]\n", + " S = H @ P_pred[t] @ H.T + R\n", + " std = np.sqrt(np.diag(S))\n", + " lower[t] = mean[t] - zscore * std\n", + " upper[t] = mean[t] + zscore * std\n", + "\n", + " # check coverage of actual obs\n", + " outside[t] = np.any((z[t] < lower[t]) | (z[t] > upper[t]))\n", + "\n", + " coverage = 1 - outside.mean()\n", + " return mean, lower, upper, coverage\n" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "ff739003", + "metadata": {}, + "outputs": [], + "source": [ + "mean, lower, upper, coverage = compute_pred_intervals(z, x_pred, P_pred, H, R)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "7546c95c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "np.float64(0.916)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "coverage" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "6b765a37", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "marker": { + "color": "royalblue" + }, + "mode": "markers", + "name": "actuals", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", + "dtype": "i2" + }, + "y": { + "bdata": "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", + "dtype": "f4" + } + }, + { + "marker": { + "color": "orange" + }, + "mode": "lines", + "name": "filtered mean", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", + "dtype": "i2" + }, + "y": { + "bdata": "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", + "dtype": "f4" + } + }, + { + "legendgroup": "95% CI", + "line": { + "width": 0 + }, + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", + "dtype": "i2" + }, + "y": { + "bdata": "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", + "dtype": "f8" + } + }, + { + "fill": "tonexty", + "fillcolor": "rgba(235, 140, 52, 0.2)", + "legendgroup": "95% CI", + "line": { + "width": 0 + }, + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "95% CI", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", + "dtype": "i2" + }, + "y": { + "bdata": "AAAAgBiFAMAAAABA3+zhPwAAAODOkuQ/AAAAgOPw3z8AAACASPfXPwAAAAAPcdo/AAAAwLlE2z8AAACApgHVPwAAAAD7vNY/AAAAAD5U1T8AAABA6QnVPwAAAIC53dw/AAAAwIOU2T8AAACAXM3YPwAAAID+Idg/AAAAgM0p0j8AAACA8FLEPwAAAIDBMsU/AAAAgGjyyT8AAABAY4DcPwAAAIBrQNo/AAAAQIQQ2z8AAADAb/zRPwAAAABqqKE/AAAAANVGwD8AAAAAIKCgPwAAAAAWmcE/AAAAgDjizT8AAABAWX7TPwAAAABJRM8/AAAAQMpQ1z8AAADAD6XSPwAAAMDlcNg/AAAAgCYLzz8AAADA02bUPwAAAEBCddk/AAAAQI7/2D8AAACA9A/QPwAAAEDU1tQ/AAAAwNg60D8AAAAASejLPwAAAACDM84/AAAAQJvv3D8AAAAgUJrhPwAAAMAwLds/AAAAoP8M4D8AAADgdQPgPwAAAMBIEtM/AAAAgHUEyT8AAADAAa3TPwAAAEC7/do/AAAAQCkR3z8AAADA/+vdPwAAAMCkQNI/AAAAAE0/xz8AAADAlGLXPwAAAIC5Nck/AAAAAKbzxz8AAAAAX+bEPwAAAAB9h84/AAAAQEKl1T8AAADAIB3ZPwAAAEAMqtM/AAAAAFPyzD8AAADAW1XTPwAAAECEu9U/AAAAwJKM1D8AAADARljUPwAAAMApf9I/AAAAAFu4zj8AAABA2nTQPwAAAACGk84/AAAAgNzAyj8AAADAUSzTPwAAAABLcc4/AAAAAN2yuD8AAAAAdR+4PwAAAECWbdU/AAAAwKZD2z8AAABAL7fUPwAAAAC/zcY/AAAAADznuz8AAACAHrvBPwAAAACYSJc/AAAAAFQ+oD8AAAAA6ZS7PwAAAIDY2sk/AAAAAH5hoj8AAAAAb+3BPwAAAAC4jqw/AAAAwCeY0j8AAABA8BzfPwAAAMCuAN8/AAAAwCc61j8AAAAA5xzQPwAAAACbfMc/AAAAACfAuz8AAACALYXMPwAAAIBY9sI/AAAAAJNVxj8AAAAAcY/HPwAAAIAycNE/AAAAQCAz1D8AAADAVmHSPwAAAMCbX9g/AAAAwNmt3T8AAADA9O3WPwAAAMCqrdg/AAAAwMV30j8AAACATS3IPwAAAIDkXdE/AAAAgD3Bxz8AAAAA4g23vwAAAABEX8E/AAAAAOhvwT8AAADAvbPSPwAAAABC97M/AAAAAEKOqb8AAAAAIMFpvwAAAAAcPso/AAAAAEQavD8AAAAAws2yPwAAAABCEqw/AAAAAO/Atb8AAAAAdLikPwAAAIDshMU/AAAAAMdVwT8AAACAh4/EPwAAAEAmPNM/AAAAAPW4zT8AAAAAz3TKPwAAAABbEc8/AAAAwF5/0j8AAAAAaqnNPwAAAMC7MtQ/AAAAQIoB2D8AAADAW4jVPwAAAIAxCcM/AAAAAIB9R78AAACAfTfGPwAAAEAuLNE/AAAAgG49xD8AAAAA5/69PwAAAMA4h9Q/AAAAQBMY1D8AAACA5PXLPwAAAACAbsc/AAAAAA8zzD8AAABAofzWPwAAAMBJE9w/AAAAQKeF2j8AAABApKHePwAAACBDEOA/AAAAwPQZ0z8AAABAYE7dPwAAAEATTd8/AAAAQLYi3T8AAADAm8zdPwAAAEA8Y90/AAAAwHrx3T8AAABghRjiPwAAAEDwWN4/AAAAwCjz2T8AAABA+DbYPwAAAMBRrtk/AAAAACSMuT8AAADAAcTSPwAAAABobsU/AAAAQO0j0z8AAADA8KrSPwAAAEDSLdg/AAAAwMkF3D8AAAAgmgHhPwAAACA9IuA/AAAAgJG70D8AAADATdrbPwAAAMBTqtU/AAAAgK070D8AAABAo2LWPwAAAMATwtU/AAAAwLDo0T8AAAAAkFjIPwAAAEDfPtE/AAAAwPtD0j8AAACAedvJPwAAAMA7FNw/AAAAQGri0z8AAAAACiTPPwAAAMDBi9c/AAAAQFKZ2j8AAADAsYrePwAAAOC4lOA/AAAAYHIT5T8AAACg9p7jPwAAAOAWCuE/AAAAQICm2D8AAADAQy7VPwAAAMD5tNU/AAAAALSDqz8AAAAAasCwPwAAAABxzcA/AAAAAGAbzz8AAACAbu3QPwAAAMBwWdY/AAAAAIcVxD8AAAAATXK3PwAAAMAgJdc/AAAAAAM+yj8AAABApQfVPwAAAMDgLN4/AAAAwF2a0D8AAADAK7vSPwAAAEB2L9c/AAAAAOAIxj8AAAAAAAGrPwAAAABFoMA/AAAAQPwg0D8AAABAYvPRPwAAAECF/NM/AAAAQIhn2T8AAAAghybhPwAAAEBkyN0/AAAAQBdz2T8AAAAA+HnNPwAAAABHpb0/AAAAAGgKwr8AAAAA5d69PwAAAABefLE/AAAAAD8syT8AAAAAGhuvPwAAAMADptM/AAAAwNvG1j8AAABAW5HRPwAAAAB80cU/AAAAAJnwxT8AAADAwfDXPwAAAEDRm9Y/AAAAQGrV1D8AAADAST/aPwAAAMDnTN0/AAAAwCIy1z8AAADAQyvdPwAAAADUT7I/AAAAgBlHxj8AAABAcOTSPwAAAIC7jME/AAAAgG/rwz8AAABAegDWPwAAAIAMOMU/AAAAAGgJgL8AAACAkWHGPwAAAAAod8Q/AAAAgMxowz8AAABAym3WPwAAAKC0t+A/AAAAwOy43T8AAAAgxXzgPwAAAEBhbt0/AAAAQGp22D8AAADA1qLdPwAAACABl+A/AAAAQG3T0j8AAABACaHSPwAAAECTMt8/AAAAwIqa2z8AAABgZnTiPwAAAMD1hN0/AAAAQMei1j8AAABAAuvQPwAAAEBaYdA/AAAAAD4zzz8AAAAA7HzLPwAAAIBTHsw/AAAAwLPg1T8AAADAwebRPwAAAEDQqd8/AAAAQJbA2j8AAABgi3DhPwAAACClJ+M/AAAAwCtW1D8AAADATencPwAAAEAD/dU/AAAAwMIY1z8AAACAJefBPwAAAABeFMU/AAAAACp7xT8AAABA6sLTPwAAAEAZYto/AAAAwOQV3T8AAADA6RHbPwAAAMDthtM/AAAAQMGk1D8AAADAZOvUPwAAAMDVb9g/AAAAAJ55yz8AAADAC9LRPwAAAIA6Lsg/AAAAQJTi0T8AAABAodLbPwAAAIBzsc8/AAAAgFLixT8AAABAfSLXPwAAAED7fdY/AAAAQBhg1z8AAAAAF/O8PwAAAAA4Toa/AAAAAFRKuT8AAACAJQrGPwAAAAC4AZi/AAAAgN8FwT8AAABAJfPQPwAAAMCiQ9I/AAAAgAnowz8AAAAAWOW5PwAAAIBCn80/AAAAQM+D0z8AAACAscLMPwAAAECExdg/AAAAQApi1j8AAAAADQbKPwAAAIDSIMw/AAAAgCm9wj8AAACAyH3MPwAAAABMOcY/AAAAQOQY0z8AAACAKRrNPwAAAMDlltE/AAAAALIqzz8AAABAftXdPwAAAEAcAto/AAAAQFDC2z8AAABg/U7gPwAAAMBMp98/AAAAwDtp1T8AAADAtiXaPwAAAIC7U9E/AAAAwDWy0z8AAABAL8/QPwAAAEDsStM/AAAAQMOu2j8AAABA5tLWPwAAAEAVpto/AAAAwBFG2T8AAACAnjbRPwAAAEDJutM/AAAAgFbrzT8AAAAAlsO9PwAAAABWlL4/AAAAAPVbvD8AAAAAJZLDPwAAAACoz7s/AAAAQEzg0D8AAAAAxP+3PwAAAADgR50/AAAAAMA9nr8AAAAACGSlvwAAAADU/6Y/AAAAABASeL8AAAAA/iuqPwAAAICFP8I/AAAAAOp9oT8AAAAAMie+PwAAAIBba8g/AAAAAM9ttj8AAABAnY3RPwAAAMA7adI/AAAAQJn80T8AAACAwojMPwAAAIBDT9A/AAAAgJ1Dzz8AAAAAoAHLPwAAAAAstL4/AAAAACSLtj8AAACAfubDPwAAAMAnIdU/AAAAwDJq1j8AAABAYgbVPwAAAEClCNY/AAAAQOOv0T8AAAAAUlzLPwAAAIDI0s8/AAAAAMZtxT8AAAAAQnLJPwAAAIAuxs0/AAAAADGkzT8AAABAdaDQPwAAAMDjJts/AAAAQMvc2D8AAADgGFbgPwAAAEAQAt4/AAAAoCr35D8AAACgEPLjPwAAAGBAxeY/AAAA4GTN5T8AAAAggxnpPwAAAMBNe98/AAAAwBTZ3T8AAADAzqPSPwAAAMBmRtU/AAAAwCAH0D8AAACAmsHLPwAAAIBRNsw/AAAAAIR9qj8AAAAALmq9PwAAAMCMsNc/AAAAQJIR2T8AAABApondPwAAAMAv99M/AAAAwDVn1z8AAAAAphTOPwAAAMAyvNI/AAAAwGHY3D8AAADARxLcPwAAAMBRKN0/AAAAAKE10T8AAADAeE/QPwAAAMC2o9Q/AAAAQOJU1j8AAADAEhPfPwAAAED4kds/AAAAwMtB1D8AAADAAMHXPwAAAADImM8/AAAAAL+qyz8AAAAAOOaVPwAAAABJIcA/AAAAQHG41D8AAADAMMbUPwAAAMBebtY/AAAAwAFB1T8AAABAgNnaPwAAAMCpn9Y/AAAAwEUN1z8AAABAmtrUPwAAAECke9M/AAAAwD7w1j8AAABAxOjaPwAAAEAK3NY/AAAAwNQF3T8AAADAejrcPwAAAEAgzNs/AAAAwP4w3D8AAACA/ILLPwAAAADx384/AAAAQHiC0z8AAABAZazTPwAAAMC3Y9M/AAAAgCIVyz8AAAAAAv7FPwAAAAAi5cQ/AAAAADcQyj8AAAAAVQjIPwAAAID0ysw/AAAAwFU01D8AAABAyu3bPwAAAIAE0cw/AAAAAHwRnD8AAAAAjpajvwAAAACACkc/AAAAACZIzD8AAACAXUHRPwAAAEAB99k/AAAAQMIX1z8AAADAD1raPwAAAKDwleE/AAAAQCUx1z8AAADAIj/RPwAAAED8UdQ/AAAAQKS/2j8AAADAZJrRPwAAAEBBPtY/AAAAwLb53D8AAADAbUraPwAAAIC1AtE/AAAAgJcwzT8AAADglzDgPwAAAKC0pOE/AAAAwITK0j8AAADA0XLZPwAAAMD84d0/AAAAwNEW3T8AAABAMc/WPwAAAID02sU/AAAAAK7txz8AAADA6ILaPwAAAMB33d0/AAAAwECP2z8AAABAVAbbPwAAAEDy1dY/AAAAwAzB2D8AAADAyvPcPwAAAMBsSdw/AAAAwLQW1j8AAAAASwjQPwAAAEBv3tE/AAAAgN/SzD8AAAAA9ICdPwAAAADEr7w/AAAAgK46xz8AAAAAT8q5Pw==", + "dtype": "f8" + } + } + ], + "layout": { + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#f2f5fa" + }, + "error_y": { + "color": "#f2f5fa" + }, + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "baxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#506784" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "header": { + "fill": { + "color": "#2a3f5f" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#f2f5fa", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#f2f5fa" + }, + "geo": { + "bgcolor": "rgb(17,17,17)", + "lakecolor": "rgb(17,17,17)", + "landcolor": "rgb(17,17,17)", + "showlakes": true, + "showland": true, + "subunitcolor": "#506784" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "dark" + }, + "paper_bgcolor": "rgb(17,17,17)", + "plot_bgcolor": "rgb(17,17,17)", + "polar": { + "angularaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "radialaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "yaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "zaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + } + }, + "shapedefaults": { + "line": { + "color": "#f2f5fa" + } + }, + "sliderdefaults": { + "bgcolor": "#C8D4E3", + "bordercolor": "rgb(17,17,17)", + "borderwidth": 1, + "tickwidth": 0 + }, + "ternary": { + "aaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "baxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "caxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "updatemenudefaults": { + "bgcolor": "#506784", + "borderwidth": 0 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + } + } + }, + "xaxis": { + "title": { + "text": "Time Index" + } + }, + "yaxis": { + "title": { + "text": "y" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig= go.Figure()\n", + "fig.add_traces(\n", + " [\n", + " go.Scatter(\n", + " x = np.arange(T),\n", + " y = z.ravel(),\n", + " mode=\"markers\",\n", + " marker_color = \"royalblue\",\n", + " name = \"actuals\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(T),\n", + " y = xs.ravel(),\n", + " mode = \"lines\",\n", + " marker_color = \"orange\",\n", + " name = \"filtered mean\"\n", + " ),\n", + " go.Scatter(\n", + " name=\"\", \n", + " x=np.arange(T), \n", + " y=upper.ravel(), \n", + " mode=\"lines\", \n", + " marker=dict(color=\"#eb8c34\"), \n", + " line=dict(width=0), \n", + " legendgroup=\"95% CI\",\n", + " showlegend=False\n", + " ),\n", + " go.Scatter(\n", + " name=\"95% CI\", \n", + " x=np.arange(T), \n", + " y=lower.ravel(), \n", + " mode=\"lines\", marker=dict(color=\"#eb8c34\"), \n", + " line=dict(width=0), \n", + " legendgroup=\"95% CI\", \n", + " fill='tonexty', \n", + " fillcolor='rgba(235, 140, 52, 0.2)'\n", + " ),\n", + "\n", + " ]\n", + ")\n", + "fig.update_layout(\n", + " xaxis=dict(\n", + " title = \"Time Index\",\n", + " ),\n", + " yaxis=dict(\n", + " title = \"y\"\n", + " ),\n", + " template = \"plotly_dark\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "052b0194", + "metadata": {}, + "source": [ + "## Non-linear Kalman Filter" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "6b088d6b", + "metadata": {}, + "outputs": [], + "source": [ + "@jit(nopython=True)\n", + "def loglik_poisson_numba(s, y):\n", + " \"\"\"Poisson Log Likelihood\"\"\"\n", + " mu = np.exp(s)\n", + " return y * np.log(mu + 1e-30) - mu - math.lgamma(y + 1.0) # numba does not support scipy.special gammaln\n", + "\n", + "@jit(nopython=True)\n", + "def particle_filter_1d_predict_numba(A, Q, x0_mean, x0_std, ys, N=1000, seed=2):\n", + " \"\"\"\n", + " 1D particle filter.\n", + " \n", + " Parameters\n", + " ----------\n", + " A: float\n", + " State transition\n", + " Q: float\n", + " Process covariance\n", + " x0_mean: float\n", + " Prior mean for the latent state\n", + " x0_std: float\n", + " Prior standard deviation \n", + " ys: np.ndarray\n", + " observations\n", + " N: int\n", + " number of particles\n", + " seed: int\n", + " rng seed for reproducibility\n", + "\n", + " Returns\n", + " -------\n", + " filtered_means: np.ndarray\n", + " The filtered mean for the latent state \n", + " filtered_vars: np.ndarray\n", + " The filtered variance for the latent state\n", + " pred_means: np.ndarray\n", + " observation predicted mean \n", + " \"\"\"\n", + " np.random.seed(seed)\n", + " T = ys.shape[0]\n", + " particles = np.random.normal(x0_mean, x0_std, size=N)\n", + " weights = np.ones(N) / N\n", + "\n", + " filtered_means = np.zeros(T)\n", + " filtered_vars = np.zeros(T)\n", + " pred_means = np.zeros(T)\n", + "\n", + " for t in range(T):\n", + " y = ys[t]\n", + "\n", + " # propagate (vectorized)\n", + " particles = A * particles + np.random.normal(0, np.sqrt(Q), size=N)\n", + "\n", + " # update weights\n", + " logw = np.zeros(N)\n", + " for i in range(N):\n", + " logw[i] = loglik_poisson_numba(particles[i], y)\n", + " logw = logw - np.max(logw)\n", + " weights *= np.exp(logw)\n", + " weights /= np.sum(weights) + 1e-12\n", + "\n", + " # filtered moments\n", + " mean_t = np.sum(weights * particles)\n", + " var_t = np.sum(weights * (particles - mean_t) ** 2)\n", + "\n", + " # predictive mean\n", + " pred_mean = np.sum(weights * np.exp(particles))\n", + "\n", + " filtered_means[t] = mean_t\n", + " filtered_vars[t] = var_t\n", + " pred_means[t] = pred_mean\n", + "\n", + " # resample (multinomial resampling) because numba doesn't support np.random.choice\n", + " cumulative_sum = np.cumsum(weights)\n", + " cumulative_sum[-1] = 1.0 # guard against rounding error\n", + " indices = np.searchsorted(cumulative_sum, np.random.rand(N))\n", + "\n", + " particles = particles[indices]\n", + " weights = np.ones(N) / N\n", + "\n", + " return filtered_means, filtered_vars, pred_means" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "a468c403", + "metadata": {}, + "outputs": [], + "source": [ + "# Had to fix the loglikelihood and key to use benchmarker as is\n", + "def loglik_poisson_jax(s, y):\n", + " \"\"\"Poisson Log Likelihood\"\"\"\n", + " mu = jnp.exp(s)\n", + " return y * jnp.log(mu + 1e-30) - mu - gammaln(y + 1.0)\n", + "\n", + "\n", + "@partial(jax.jit, static_argnums=5)\n", + "def particle_filter_1d_predict_jax(\n", + " A, Q, x0_mean, x0_std, ys, N=1000,\n", + "):\n", + " \"\"\"\n", + " 1D particle filter.\n", + " \n", + " Parameters\n", + " ----------\n", + " A: float\n", + " State transition\n", + " Q: float\n", + " Process covariance\n", + " x0_mean: float\n", + " Prior mean for the latent state\n", + " x0_std: float\n", + " Prior standard deviation \n", + " ys: np.ndarray\n", + " observations\n", + " loglik_fn: function\n", + " The log likelihood function\n", + " key: \n", + " JAX prng key\n", + " N: int\n", + " number of particles\n", + "\n", + " Returns\n", + " -------\n", + " filtered_means: jnp.ndarray\n", + " The filtered mean for the latent state \n", + " filtered_vars: jnp.ndarray\n", + " The filtered variance for the latent state\n", + " pred_means: jnp.ndarray\n", + " observation predicted mean \n", + " \"\"\"\n", + " key = jax.random.PRNGKey(0)\n", + " T = ys.shape[0]\n", + " particles = jax.random.normal(key, (N,)) * x0_std + x0_mean # init particles from gaussian priors\n", + " weights = jnp.ones(N) / N # particle weights, all particles equally likely prior\n", + "\n", + " def body_fun(carry, t):\n", + " particles, weights, key = carry\n", + " y = ys[t]\n", + "\n", + " # propagate\n", + " key, subkey = jax.random.split(key)\n", + " particles = A * particles + jax.random.normal(subkey, (N,)) * jnp.sqrt(Q) # state transition model\n", + "\n", + " # update weights\n", + " logw = jax.vmap(lambda x: loglik_poisson_jax(x, y))(particles) # update particles in parallel\n", + " logw = logw - jnp.max(logw) # avoid overflow\n", + " weights = weights * jnp.exp(logw) # old weights times the likelihood\n", + " weights /= jnp.sum(weights) + 1e-12 # normalize so that weights sum to 1\n", + "\n", + " # filtered moments\n", + " mean_t = jnp.sum(weights * particles) # posterior mean of latent state\n", + " var_t = jnp.sum(weights * (particles - mean_t)**2) # posterior variance of latent state\n", + "\n", + " # predictive mean\n", + " pred_mean = jnp.sum(weights * jnp.exp(particles))\n", + "\n", + " # resample to prevent dominant particles\n", + " key, subkey = jax.random.split(key)\n", + " indices = jax.random.choice(subkey, N, p=weights, shape=(N,))\n", + " particles = particles[indices]\n", + " weights = jnp.ones(N) / N\n", + "\n", + " carry = (particles, weights, key)\n", + " out = (mean_t, var_t, pred_mean)\n", + " return carry, out\n", + "\n", + " _, outputs = jax.lax.scan(body_fun, (particles, weights, key), jnp.arange(T))\n", + " return outputs\n" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "15fd4a0c", + "metadata": {}, + "outputs": [], + "source": [ + "from pytensor.tensor.random.utils import RandomStream\n", + "\n", + "# Random stream for PyTensor\n", + "srng = RandomStream(seed=42)\n", + "\n", + "# Poisson log-likelihood\n", + "def loglik_poisson_pytensor(s, y):\n", + " mu = pt.exp(s)\n", + " return y.flatten() * pt.log(mu + 1e-30) - mu - pt.gammaln(y.flatten() + 1.0)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "59525da5", + "metadata": {}, + "outputs": [], + "source": [ + "ys_symbolic = pt.vector(\"ys\")\n", + "x0_mean_symbolic = pt.scalar(\"x0_mean\")\n", + "x0_std_symbolic = pt.scalar(\"x0_std\")\n", + "A_symbolic = pt.scalar(\"A\")\n", + "Q_symbolic = pt.scalar(\"Q\")\n", + "N_symbolic = pt.scalar(\"N\", dtype='int64')\n", + "\n", + "# Initialize particles and weights\n", + "particles_init = srng.normal(size=(N_symbolic,)) * x0_std_symbolic + x0_mean_symbolic\n", + "weights_init = pt.ones((N_symbolic,)) / N_symbolic \n", + "\n", + "# Step function for scan\n", + "def step(y_t, particles_prev, weights_prev, A_symbolic, Q_symbolic):\n", + " # Propagate particles\n", + " particles_prop = A_symbolic * particles_prev + srng.normal(size=(N_symbolic,)) * pt.sqrt(Q_symbolic)\n", + "\n", + " # Update weights\n", + " # logw = pt.stack([loglik_poisson_pytensor(p, y_t) for p in particles_prop])\n", + " logw = loglik_poisson_pytensor(particles_prop, y_t)\n", + " logw_stable = logw - pt.max(logw)\n", + " w_unnorm = weights_prev * pt.exp(logw_stable)\n", + " w = w_unnorm / (pt.sum(w_unnorm) + 1e-12) \n", + "\n", + " # Filtered moments\n", + " mean_t = pt.sum(w * particles_prop)\n", + " var_t = pt.sum(w * (particles_prop - mean_t) ** 2)\n", + " pred_mean = pt.sum(w * pt.exp(particles_prop))\n", + "\n", + " # Resample particles\n", + " idx = srng.choice(size=(N_symbolic,), a=N_symbolic, p=w) \n", + " particles_resampled = particles_prop[idx]\n", + " weights_resampled = pt.ones((N_symbolic,)) / N_symbolic\n", + "\n", + " # Return flat tuple\n", + " return particles_resampled, weights_resampled, mean_t, var_t, pred_mean\n", + "\n", + "# first two are recurrent, rest are collected\n", + "outputs_info = [\n", + " particles_init,\n", + " weights_init,\n", + " None,\n", + " None,\n", + " None\n", + "]\n", + "\n", + "(particles_seq, weights_seq, means_seq, vars_seq, preds_seq), updates = pytensor.scan(\n", + " fn=step,\n", + " sequences=[ys_symbolic],\n", + " outputs_info=outputs_info,\n", + " non_sequences=[A_symbolic, Q_symbolic]\n", + ")\n", + "\n", + "particle_filter_1d_predict_pytensor = pytensor.function(\n", + " [A_symbolic, Q_symbolic, x0_mean_symbolic, x0_std_symbolic, ys_symbolic, N_symbolic],\n", + " [means_seq, vars_seq, preds_seq],\n", + " updates=updates,\n", + " no_default_updates=True,\n", + " trust_input=True\n", + ")\n", + "\n", + "particle_filter_1d_predict_pytensor_numba = pytensor.function(\n", + " [A_symbolic, Q_symbolic, x0_mean_symbolic, x0_std_symbolic, ys_symbolic, N_symbolic],\n", + " [means_seq, vars_seq, preds_seq],\n", + " updates=updates,\n", + " no_default_updates=True,\n", + " mode=\"NUMBA\", \n", + " trust_input=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "c033a1d0", + "metadata": {}, + "outputs": [], + "source": [ + "key = jax.random.PRNGKey(0)\n", + "T = 300\n", + "A = 0.95\n", + "Q = 0.05\n", + "rng = np.random.RandomState(1)\n", + "\n", + "target_mean = 10.0\n", + "latent_var = Q / (1 - A**2)\n", + "x0_mean = np.log(target_mean) - 0.5 * latent_var\n", + "x0_std = 1.0\n", + "\n", + "# Simulate latent\n", + "x = np.zeros(T)\n", + "x[0] = rng.normal() * np.sqrt(latent_var) + x0_mean\n", + "for t in range(1, T):\n", + " x[t] = A * x[t-1] + rng.normal() * np.sqrt(Q)\n", + "\n", + "ys = np.array(rng.poisson(np.exp(x)), dtype=np.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "2a9cbfa5", + "metadata": {}, + "outputs": [], + "source": [ + "nonlinear_kalman_filter_bench = Benchmarker(\n", + " functions=[particle_filter_1d_predict_pytensor, particle_filter_1d_predict_numba, jax.block_until_ready(particle_filter_1d_predict_jax), particle_filter_1d_predict_pytensor_numba,], \n", + " names=['particle_filter_1d_predict_pytensor', 'particle_filter_1d_predict_numba', 'particle_filter_1d_predict_jax', 'particle_filter_1d_predict_pytensor_numba',],\n", + " number=5 # This takes a while to run reducing number of loops\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "c782c42b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
particle_filter_1d_predict_pytensorkalman_filter_inputs5776326.149999792344.283199782741.5382796040.856511779343.4081988662.6000000.0012785
particle_filter_1d_predict_numbakalman_filter_inputs551164.90839951900.63320051432.376601264.82944351439.416601276.4916020.0194435
particle_filter_1d_predict_jaxkalman_filter_inputs517.35840133723.7500007730.25357212709.92769619.72499910139.6457990.1293627
particle_filter_1d_predict_pytensor_numbakalman_filter_inputs5724575.624999739611.624999731249.6600005239.730301731423.7000016487.6667980.0013685
\n", + "
" + ], + "text/plain": [ + " Loops \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 5 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 5 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 5 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 5 \n", + "\n", + " Min (us) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 776326.149999 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 51164.908399 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 17.358401 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 724575.624999 \n", + "\n", + " Max (us) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 792344.283199 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 51900.633200 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 33723.750000 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 739611.624999 \n", + "\n", + " Mean (us) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 782741.538279 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 51432.376601 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 7730.253572 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 731249.660000 \n", + "\n", + " StdDev (us) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 6040.856511 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 264.829443 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 12709.927696 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 5239.730301 \n", + "\n", + " Median (us) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 779343.408198 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 51439.416601 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 19.724999 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 731423.700001 \n", + "\n", + " IQR (us) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 8662.600000 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 276.491602 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 10139.645799 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 6487.666798 \n", + "\n", + " OPS (Kops/s) \\\n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 0.001278 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 0.019443 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 0.129362 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 0.001368 \n", + "\n", + " Samples \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 5 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 5 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 7 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 5 " + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nonlinear_kalman_filter_bench.run(\n", + " inputs={\n", + " \"kalman_filter_inputs\": {\"A\": A, \"Q\": Q, \"x0_mean\": x0_mean, \"x0_std\": x0_std, \"ys\": ys, \"N\": 2000},\n", + " }\n", + ")\n", + "nonlinear_kalman_filter_bench.summary()" + ] + }, + { + "cell_type": "markdown", + "id": "29fe0cc4", + "metadata": {}, + "source": [ + "Slightly different estimates because I couldn't reproduce 1:1 " + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "2bd23897", + "metadata": {}, + "outputs": [], + "source": [ + "filtered_means, filtered_vars, pred_means = particle_filter_1d_predict_numba(\n", + " A, Q, x0_mean, x0_std, ys, N=2000, seed=2\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "7caac5a5", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "legend": "legend", + "marker": { + "color": "cornflowerblue" + }, + "mode": "markers", + "name": "actuals", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AADAQQAAcEEAAIhBAACgQAAAMEEAAMBAAADgQAAAEEEAAIA/AAAAQAAAoEAAAKBAAABAQAAAgD8AAKBAAACAQAAAQEAAAIA/AACAPwAAAEAAAABAAAAAQAAAQEAAAABAAACAQAAAAEAAAAAAAACAPwAAAEAAAIA/AACAQAAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAQEAAAEBAAAAAAAAAAAAAAIA/AACAPwAAoEAAAAAAAACAPwAAAEAAAAAAAAAAAAAAgD8AAIA/AAAAQAAAgD8AAABAAACAPwAAAAAAAABAAACgQAAAoEAAAABAAAAAQAAAoEAAAMBAAAAAQAAAAAAAAAAAAAAAQAAAgD8AAKBAAABAQAAAgD8AAIA/AACAPwAAAEAAAABAAABAQAAAgEAAAABAAACAPwAAQEAAAAAAAACAPwAAgD8AAIA/AABAQAAAgD8AAABAAACAPwAAgD8AAABAAACAPwAAQEAAAABAAAAAAAAAgEAAAIBAAAAAQAAAQEAAAIA/AAAAQAAAAAAAAIA/AACAPwAAAEAAAAAAAACAPwAAgD8AAABAAAAAQAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAQAAAAAAAAIA/AACAQAAAAAAAAIA/AAAAQAAAQEAAAABAAACAQAAAAEAAAAAAAACAPwAAAAAAAAAAAAAAAAAAQEAAAEBAAACAPwAAgD8AAIA/AAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAABAQAAAgEAAAABAAAAAAAAAAEAAAIA/AACAPwAAQEAAAABAAAAAQAAAgEAAAAAAAAAAQAAAgD8AAIA/AAAAAAAAAAAAAABAAACAPwAAgD8AAEBAAACAQAAAAEAAAIA/AACAQAAAgD8AAIA/AAAAAAAAgD8AAIA/AABAQAAAgEAAAAAAAAAAQAAAgD8AAEBAAABAQAAAgD8AAIBAAACAPwAAgD8AAMBAAACAPwAAgD8AAKBAAACAPwAAAEAAAMBAAACAPwAAgEAAAAAAAABAQAAAgD8AAEBAAADAQAAAwEAAAKBAAAAAQAAAAEAAAABAAABAQAAAgD8AAABAAACAPwAAgD8AAEBAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAgD8AAAAAAACgQAAAAAAAAIBAAACAPwAAAEAAAIA/AAAAQAAAgD8AAMBAAABAQAAAgEAAAABAAABAQAAAgD8AAABAAACAPwAAAEAAAIA/AAAAQAAAAEAAAAAAAACAPwAAAAAAAAAAAABAQAAAgD8AAIA/AAAAQAAAAAAAAIA/AAAAAAAAAEAAAABAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAAAAQAAAAEAAAIA/AACAPwAAAAAAAABAAACAQAAAAEAAAIBAAABAQAAAgD8AAIA/AABAQAAAAAAAAAAAAACAPwAAQEAAAAAAAAAAAAAAgD8AAAAAAAAAQAAAgEAAAIA/AACAPwAAAEAAAABAAACAPwAAAEAAAAAAAABAQAAAAEAAAIA/AABAQAAAAAAAAAAA", + "dtype": "f4" + }, + "yaxis": "y" + }, + { + "legend": "legend", + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "predicted mean", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "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", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "legend": "legend", + "legendgroup": "predicted mean 95% CI", + "line": { + "width": 0 + }, + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AzL/QW7XxUEGcL1BqF1+Qds7gEFCIlJB4HBDQSyrTUE0/A5B3V7qQORg+0BWIgNBjo/sQF+svkC/rN1Au4ngQBZ41EAQ0rFApVmcQLdJmUAcWZdAkBqWQFz1oUDwbZ1AS5+1QEA5q0Am14pAYpuBQLTWhUBQW3lAxDqcQLSHgECGvF1AyOlDQEC4LkBN4jBA1A41QHs0OUBpETtA6P8qQECRHUClvCRAAOUrQO49XECKIIRAtCVgQExJRUCUeEZAakBHQML1kEBAX3VANWNqQOBteEAcqVZAgvE8QH8wP0BiMEBAzPdWQGOOUUC5SGRAXPtcQNhSP0DuPlVAS4CdQBoEyECnDbVAXompQB3pzED16fJA+gTRQGcUpEAES4hAEx2LQKgqgkCiGq1AomyzQP68m0C6SItA16GAQHBhhEB8aodAj0mVQEjcrUAzi6VABcCUQHhCoUB+/oNAb3t4QMTGakCmV2JAaXiEQHvteEBqBYFAIbx0QKAeaUDzaHlA1C1sQCHPiECcvotAUixsQD0ml0AP2rFASBqnQO63rUC6pJlAmuCWQBB9ekBEV2xARB9lQNzUdUCKuFFAkLRPQDeHTEDS7GBARsRyQLJXUUDOcUxAphFKQOl5SUDXP0lAmmRdQDwfQUCslEJAtU2BQK3XXUAu91hA2FlrQOBfiUBu8olAJuemQC6In0ADDINA4sB1QOaPVEDBmj1ARpcsQMW8WkC0MIRAGld6QI5Hb0CojWRAeOFzQJaegUCJ4YZAzTKLQIlVjUCSWI5A1uOdQOIat0CCaa1A9EOLQCB+jUD77oJA8n92QKGSjEDC2I1AnHSPQI6xq0DxNIpATLWLQFf3gUAm5HVAdjBUQAyYOkCtPVFAmG9PQM4+S0CTGnhA7OCbQFewl0AQB4hAqDykQP6fkUBR44VASA5iQIYcW0D+kVZAUxOBQGJ1n0Dkx4JAFdiGQBKae0C4ipBAf/CeQEBwj0AAJatADDCVQKGRh0DoP79AuuaiQIx3kUAJtrdA5hieQJb6mkCa+s9APKOtQK7XwUB4uZdAmGGiQI7CkEAShp5AwG7UQChL/kA4GgRBoNfdQMvpxUDs1bRA7nS3QPT3oEDigJxAkmSMQPSJgUArKJJA4VF2QIGBVEDmCDxAiOMpQBalQUA2z1pAlu0/QFa5QEDUDSxAApGGQLpvZkDSTpJAbnuFQHNViEAUxHtAY7CDQEK1d0AqybVAhI22QGN6x0DoobVAvVu5QPpfn0Ba0ptAZM2MQK5YjkCFWINARW+GQN3NiUB+EmhA3MtdQHjgQ0DwODBAKs5gQFAJWUDq8VNAZhhpQMLxS0BH5EpA3Bc1QPQtTEBYpGBAoBhFQBRjMEALoTRArF8kQHJ3KkAE3xpAE8YhQL94EkCMhwhAslklQFwLQkByf0BAVlZCQKOeLUBSjEZABAmIQEfCikBzwapApj6yQNaNmkAbcIxAKsGcQABafkAb1FpAIsJVQDpTgEB0VFpAedY+QEtEP0AN4CxAec9FQNHnhEBl+HdAXNpsQEynfEBpaoNAq3x2QFlOgUAeY1xAjd6CQLOehkAef3lAXmaQQP7ncEAECVFA", + "dtype": "f4" + }, + "yaxis": "y" + }, + { + "fill": "tonexty", + "fillcolor": "rgba(235, 140, 52, 0.2)", + "legend": "legend", + "legendgroup": "predicted mean 95% CI", + "line": { + "width": 0 + }, + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "predicted mean 95% CI", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "pkxPQSALB0EL3flAsh9dQNJyYUCYHgZAPEfWP7Cd+z+QwKc+gLVdvgCXQ72AKYc9gBtIvvDTF7+QdKu+IBievign1b6wiC+/aIVRv7C9Vb/MU1i/SPNZv7heSb+c/k+/uMQov3zCOr+MTme/AFlwv5RtbL8SanS/xLBRv2RIcb+ou3y/zvB/v9/Kfr+BFH+/pYV/vzXRf79w53+/6jN+v0IHe79M7ny/Elt+v5ILfb9WD26/wDJ8v1bkf7+m1n+/Jsx/v3xaYL+Q5nW/PIJ5v8DEdL8KFH6/mvZ/v1j/f7/2/3+/4gZ+v+zVfr88MXu/euR8v4r/f79uTn6/eORPv+QrBb9Yyym/zIU9v8Dk9b4AVwi+aETkvvglRr/Y+mm/KgNnvwDab7+0oDe/qLQsv6xgUr/o02a/+DFxv3jSbb+E3mq/7v9avzxaNr+o4UO/+q5bvzRqSr8gL26/nL90v75keb+mrXu/2rxtvyyUdL8M3HC/NCF2v7bgeb/UZHS/avh4v/Zyab+KU2a/3vh4v6KWWL+wei+/6G1Bv7CXNr90QlW/0vFYv7b5c7+263i/ovl6v+a7db9m0H6/oBB/v8Rmf7+CBHy/cNJ2vwLdfr/IaH+/jpx/v9Snf7/0q3+/Ws58v8D+f79g+X+/IJ1wv9S1fL9grX2/wDh5v37caL9qQmi/5L5Bv3j2TL+yDm+/KsN1v2Bpfr88+n+/Snh+vyxYfb80AG6/iAh0v/L9d79+H3u/2G52vy5WcL9eZ2u/qOtmvw6QZL/4aWO/RFZPv5QSJr8AHDe/FNlmv1JiZL8gKW+/Rn11v+ppZb+6+2O/lCFiv2z7Ob/w+2e/tl1mv7AHcL9WtnW/uHd+v3bif79c4H6/phh/vz6Ef79E5HS/iC5Sv8DgV78sQGq/FOhFv8yNX79OYWy/eL97v35Ffb/eF36/9s9wv+QRTb+cTG+/vnBrv1aJc78a2mC/KNNNv6wmYr/o4zq/giBbvx63ar/stRa/gPJHv56+X78o9iS/MApPv3BuU78Yxei+pLo2vwChEb+y1Fe/3LtIv6aXYL8YbU6/cFDVvoAukbzAfrE9wK2qvmh4Cb+ELyq/rG0lvwDZSr88TlG/+Jxlv1RocL966F6/NI51v4xrfr8o8H+/xQB+v079f7+YVH2///9/v3r/f7/dYX6/HrdrvyCger9OuV6/6sVsvyjwab+eeHO/sHduv14Kdb/8eCi/iBQnv9BGBr/8vyi/WOohvxwxTb/gQlK/jihlv9hpY7+yyG6/YNhrvwZpaL/OLHq/Xrh8vxbxf78X/36/sAt8vxKqfb/6gH6/fuJ5v5B0f7/Ui3+/cIZ/vxhvf792FXy/SOZ/v4IEf7/Ae3+/mth8v7gbfr9jL3q/GDR8v2sXd79SeHK/PBJ9v9b7f7/A/3+/kPp/v3ehfr+o1X+/MD5qv/pkZ7/Yhzu/KMouvzQEVL8ykGW/mPNQvw5scr+kU32/rjl+vzR1cb9AbH2/pf5/v3f/f7/og36/nN5/v1JTbb8k8XS/QMN4v4gdc79AuG6/fH51v5CccL/6A32/EDhvv5ipa79KXHS/OgVhv5B0d78S536/", + "dtype": "f4" + }, + "yaxis": "y" + }, + { + "legend": "legend2", + "marker": { + "color": "cornflowerblue" + }, + "mode": "lines", + "name": "true latent state", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x2", + "y": { + "bdata": "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", + "dtype": "f8" + }, + "yaxis": "y2" + }, + { + "legend": "legend2", + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "filtered state mean", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x2", + "y": { + "bdata": "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", + "dtype": "f8" + }, + "yaxis": "y2" + }, + { + "legend": "legend2", + "legendgroup": "filtered state mean 95% CI", + "line": { + "width": 0 + }, + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "", + "showlegend": false, + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x2", + "y": { + "bdata": "W3JhQB28SkCnNUdAp4kqQMuqLEAQbx5Ak3YZQKmoHUC5PgNAKAjpP+aV8j+U8Pk/fAzqPy0oyj87b+E/4l7iPyCl2T8Jr70/KlirPy6XqD9K5aQ/ulKjP/l6sD8qqqs/DZHDPzZmuT90xZs/Ay2SP2/WlD9mnIc//pStP5baij+uoWc/PKJCP/uyHD9JtyA/diklP3+ELD9GPy8/uiwPP8g72j5g6wM/ItoVP1z/az+UIZU/y2JsPyioPj/BID8/O6dBP6Jlnz/KpYU/6+p8P9j4hj8iS2Q/Lzs6P1uJOj+9yTs/w9ZgPzHwXz9Y+Hc/upVrPyjYOz9+5V4/9LO1P8gz1j9hmMM/9pO4P6Ku1D+F7e4/E0/WP6qErT9Lyo4/CACXP1Fbjj9JUrw/Nu3BP3CsrT9JfJs/DaCMP/a1kT/hcJU/lJ6kPxilvD8nzrI/Hs+hP0rvrz+mGI8/XI+IP1Scej8sP24/k1WPPzaXhT8aMY0/8YaHP6Xnez+pDog/FFCBP4vMlz8DqJo/yreBP7xvpz9jR8A/yfi0PxITuz8mDqg/Xe6kP/gtiD8oSXk/9rpyP9Knhj8Qs1o/xKtWP0xNTj9HhHA/PKSGPxtUVD+9T0w/XcJJPz4qSj9rN0s/D81rP3XROj8NZjs/J++LP0Sfaj/dPGQ/fJuAP3/zmD83aJg/tES2Pyb4rT9Uf48/FB6CP6TsVz8SDTI/pqAVP3bYZj+/mJM/0/qJPyuugz9tB3c/c2GGPzGKkT8vDJc/y2mbP2ETnz/4pJ8/oriwP+RTxz+T7bw/qDOZP+ZcnD/wRI8/aYGFP99DnD+89Jw/HYyeP0ISvD9C2ZU/L7GYP+d9jD80E4Q/IKRXP6KaMD83llY/ytxPP2jGSD+nKYo/r2WvP8TeqT9mMZY/0AO1P3SioD9kypM/UGZrP7aqZD8T22E/GKiOP8MPrz9rkJE/qDaUP2lXiz8qaKE/FGuvP4jGnz/CTrs/HjOkP8RrlD8Dg80/cXiyP4CWnj9GDcY/fC2tP3Rtqj9Undc/eYS5P9pizj/sd6Y/3m2xP/itnj8joK4/zEbdP5DZ9z+AlP0/wtzfP+H0zD/++78/+0nCP6LTsD+nKaw/oi+ZPz6NjT9kaaI/NmuHP3xSZD9pYDo/LlYSP1JDQD/nRms/0DM8P7HyQD/LHhw/inuUPySYeT/E+qE/IeiRP7LIlT/c6Ik/5q2SP6S9hz9uuMU/lfLEPwqk0j80VsM/+ejGP5rMrT+e26k/VuOZP3Q0nD/0gJA/roWTPxqulj/wFHU/2ixoP+paQz8d2CA/LldyP7LIaD8bZF0/8o5/P9dCTD9sxks/meYgPwM4Tj9T8HE/7k1GP2k7IT+bBSk/tDENP4brFz/VDfA+FLgJP25Pzj7G+5U+mhsQPwnASz8fGkE/BstBPwQNGD86b0Y/LdOdP9wtoD9s2L8/glvEP84lrD8+Wp0/KuetPzjEjj9J0GY/U/djP+yDjz9LCmk/pEA8P4iyPT8i1hg/jdpHP5rBlD+2Uoo/bdeAP9WejD9pLJI/76OGP+E9jj8MqWc/IL6QPx8XlD+kcoc/2OKiP0CFgj/2OVs/", + "dtype": "f4" + }, + "yaxis": "y2" + }, + { + "fill": "tonexty", + "fillcolor": "rgba(235, 140, 52, 0.2)", + "legend": "legend2", + "legendgroup": "filtered state mean 95% CI", + "line": { + "width": 0 + }, + "marker": { + "color": "#eb8c34" + }, + "mode": "lines", + "name": "filtered state mean 95% CI", + "type": "scatter", + "x": { + "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", + "dtype": "i2" + }, + "xaxis": "x2", + "y": { + "bdata": "CagpQLmBGkAfYxdAgm3qP04g6D8gvcM/n5K1P1zGvT/fZXA/B5YgP3uTPz9xdk0/uIUlP4SWlT62KQg/fK0PP7JI9D5AMEk+cFYLvag5k72oPZq9SECwvcC25jyAmoC8QKpQPpCJ8D34X4m+v/TNvoE1pL46Vti++CSIvW6XtL6ySB6/INhbv4ukiL/s74W/9uF7vx8Ecb+GXWy/zHqJv90ZmL9+CJO/NseLv7iKK7/6N76+56MbvzCRUL93QUu/Jc9Kv4hnJb4Iy+q+xY4Kv5Ex3L5+Oje//ztyv9uwZ7/thmS/O5cxv5USSL8odBu/Cpgnv9plab9IFja/EK8Dvo6uoz7w7EQ+UO+/PXoP1D62qi0/NHbrPvidzj1iw0e+bHNYvlGFsb5AU/w9QE45Pshqlr1f7oO+yBa+vqd6pr4ENpO+8KbzvWyKCD5wRJs9gJnOvaDpnzzGJ52+ldvkvraxBb92NhW/XB2XvloV0L4+Krq+CDH5vpnMDb+97tq+GUgLv7lBjr4uJ3C+NHoMv5A92r2gnyw+EEiqPey+FT5ANnC9cAmvvbbT075ETvu+JIAQv4tA7b7k8T+/8sFCvxw4Rb8fSx6/xb8Bv3OXOL8D+kK/AxBKvzLZTL+TpU+/declvxHjXr8hWFi/Ry+vvjhrIr/JLi6/6t8Mv+mqjb4ZfIO+uMiJPYCHkzvqrKu+rlDTvoxkL7/WXWO/AqSJv+xiKb8D4rK+XA/evlRNBr9t8xi/WFb5vksyy74Eo6O+IwSEvrAGfL4wPGm+YGl4vdxuQT7QuPo9QKptvowsWb6Plqy+3ATivu4qcL6Ibla+WCZCvvikxz0GbWO+3sJdvivbqb5Fo96+MMgwvygTcL8nhTu/fpM6vyaSQ78xafK+ICzDvfhl/r0SxI++4EbRPAgHJL5pHp6+nvQSv/bfJb8NWjW/mYnBvgBWBrw0vLq+rm2Tvlir3L6Mi0a+oF3OvBRqTr6Yz8E9OC/xvZZoi75kyYc+gODMPMhJEr40Kls+wN6ZvPAFX72uYNw+MDgmPj5dmT6Ykqu9IC/RPCymIr4AQcW8kHTgPtXEOj8HyUk/x6QMP5Tnwz5wSmg+oLF/PgDxbjvAxSq9SG5Svoestr6kKyq+2ajsvhoOQb9tkXe/QoCPv6CtZL/dkTC/ZJdmv91Rab9cIJC/cj6Xvm4NFb+EcyG+E9KYvvJAib7m0NO+lMm0vltU5b6wOTs+qEpRPrYisj7MvlI+SK5wPgAA/zpAAvi85AhQvuATQb4RJa2+IoOUvtZqdr4qoQi/Anofv0o7Xb/ZuYe/roAgvwySM7+FZzm/hnwTv5G+RL9EO0m/dVN2v61jRr9lNyG/9KFbv3e7h7+0BoK/iRGbvyV0kb8hXai/32Cgv0zJt7+81MW/f6mavzugc78rIGu/boRiv4G9iL98q1W/7dW+vno5pr7QTh09XOAHPrgaqb36xH2+UEtavfyK3b5LAyq/DSo7v6v00L7nxS6/2k9sv9xea78IQIu/neRav0nQr75GffK+Tt8Hvw9H3r6Iwba+CD7oviTvvL5aIiS/jqy2vrV0lr46Ede+bPZbvkPd+b6e7EK/", + "dtype": "f4" + }, + "yaxis": "y2" + } + ], + "layout": { + "annotations": [ + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Observation Predictions", + "x": 0.5, + "xanchor": "center", + "xref": "paper", + "y": 0.9999999999999999, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Latent State Estimation", + "x": 0.5, + "xanchor": "center", + "xref": "paper", + "y": 0.46499999999999997, + "yanchor": "bottom", + "yref": "paper" + } + ], + "height": 1000, + "legend": { + "orientation": "h", + "x": 0, + "xanchor": "left", + "y": 1, + "yanchor": "top" + }, + "legend2": { + "orientation": "h", + "x": 0, + "xanchor": "left", + "y": 0.465, + "yanchor": "top" + }, + "showlegend": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#f2f5fa" + }, + "error_y": { + "color": "#f2f5fa" + }, + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "baxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#506784" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "header": { + "fill": { + "color": "#2a3f5f" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#f2f5fa", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#f2f5fa" + }, + "geo": { + "bgcolor": "rgb(17,17,17)", + "lakecolor": "rgb(17,17,17)", + "landcolor": "rgb(17,17,17)", + "showlakes": true, + "showland": true, + "subunitcolor": "#506784" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "dark" + }, + "paper_bgcolor": "rgb(17,17,17)", + "plot_bgcolor": "rgb(17,17,17)", + "polar": { + "angularaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "radialaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "yaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + }, + "zaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "gridwidth": 2, + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3" + } + }, + "shapedefaults": { + "line": { + "color": "#f2f5fa" + } + }, + "sliderdefaults": { + "bgcolor": "#C8D4E3", + "bordercolor": "rgb(17,17,17)", + "borderwidth": 1, + "tickwidth": 0 + }, + "ternary": { + "aaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "baxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "bgcolor": "rgb(17,17,17)", + "caxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "updatemenudefaults": { + "bgcolor": "#506784", + "borderwidth": 0 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "zerolinewidth": 2 + } + } + }, + "width": 1200, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 1 + ], + "matches": "x2", + "showticklabels": false + }, + "xaxis2": { + "anchor": "y2", + "domain": [ + 0, + 1 + ] + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0.5349999999999999, + 0.9999999999999999 + ] + }, + "yaxis2": { + "anchor": "x2", + "domain": [ + 0, + 0.46499999999999997 + ] + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = make_subplots(\n", + " rows=2, cols=1,\n", + " subplot_titles=(\"Observation Predictions\", \"Latent State Estimation\"),\n", + " vertical_spacing=0.07,\n", + " shared_xaxes=True\n", + ")\n", + "\n", + "fig.add_traces(\n", + " [\n", + " go.Scatter(\n", + " x = np.arange(T),\n", + " y = ys,\n", + " mode = \"markers\",\n", + " marker_color = \"cornflowerblue\",\n", + " name = \"actuals\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(T),\n", + " y = pred_means,\n", + " mode = \"lines\",\n", + " marker_color = \"#eb8c34\",\n", + " name = \"predicted mean\"\n", + " ),\n", + " go.Scatter(\n", + " name=\"\", \n", + " x=np.arange(T), \n", + " y=pred_means + 2*jnp.sqrt(pred_means), \n", + " mode=\"lines\", \n", + " marker=dict(color=\"#eb8c34\"), \n", + " line=dict(width=0), \n", + " legendgroup=\"predicted mean 95% CI\",\n", + " showlegend=False\n", + " ),\n", + " go.Scatter(\n", + " name=\"predicted mean 95% CI\", \n", + " x=np.arange(T), \n", + " y=pred_means - 2*jnp.sqrt(pred_means), \n", + " mode=\"lines\", marker=dict(color=\"#eb8c34\"), \n", + " line=dict(width=0), \n", + " legendgroup=\"predicted mean 95% CI\", \n", + " fill='tonexty', \n", + " fillcolor='rgba(235, 140, 52, 0.2)'\n", + " ),\n", + " ],\n", + " rows=1, cols=1\n", + ")\n", + "\n", + "fig.add_traces(\n", + " [\n", + " go.Scatter(\n", + " x = np.arange(T),\n", + " y = x,\n", + " mode = \"lines\",\n", + " marker_color = \"cornflowerblue\",\n", + " name = \"true latent state\"\n", + " ),\n", + " go.Scatter(\n", + " x = np.arange(T),\n", + " y = filtered_means,\n", + " mode = \"lines\",\n", + " marker_color = \"#eb8c34\",\n", + " name = \"filtered state mean\"\n", + " ),\n", + " go.Scatter(\n", + " name=\"\", \n", + " x=np.arange(T), \n", + " y=filtered_means + 2*jnp.sqrt(filtered_vars), \n", + " mode=\"lines\", \n", + " marker=dict(color=\"#eb8c34\"), \n", + " line=dict(width=0), \n", + " legendgroup=\"filtered state mean 95% CI\",\n", + " showlegend=False\n", + " ),\n", + " go.Scatter(\n", + " name=\"filtered state mean 95% CI\", \n", + " x=np.arange(T), \n", + " y=filtered_means - 2*jnp.sqrt(filtered_vars), \n", + " mode=\"lines\", marker=dict(color=\"#eb8c34\"), \n", + " line=dict(width=0), \n", + " legendgroup=\"filtered state mean 95% CI\", \n", + " fill='tonexty', \n", + " fillcolor='rgba(235, 140, 52, 0.2)'\n", + " ),\n", + " ],\n", + " rows=2, cols=1\n", + ")\n", + "\n", + "for i, yaxis in enumerate(fig.select_yaxes(), 1):\n", + " legend_name = f\"legend{i}\"\n", + " fig.update_layout({legend_name: dict(y=yaxis.domain[1], yanchor=\"top\")}, showlegend=True)\n", + " fig.update_traces(row=i, legend=legend_name)\n", + "\n", + "fig.update_layout(height=1000, width=1200, template=\"plotly_dark\")\n", + "\n", + "fig.update_layout(\n", + " legend1=dict(\n", + " yanchor=\"top\",\n", + " y=1.0,\n", + " xanchor=\"left\",\n", + " x=0,\n", + " orientation=\"h\"\n", + " ),\n", + " legend2=dict(\n", + " yanchor=\"top\",\n", + " y=.465,\n", + " xanchor=\"left\",\n", + " x=0,\n", + " orientation=\"h\"\n", + " ),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48ccc984", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pytensor-dev", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 1580b09a113511bec1e6aa4f27b1f4f48c47c231 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Sun, 5 Oct 2025 11:26:30 -0600 Subject: [PATCH 02/11] updated renderer for reviewnb --- doc/gallery/scan/benchmark_backends.ipynb | 8993 ++++++++++----------- 1 file changed, 4486 insertions(+), 4507 deletions(-) diff --git a/doc/gallery/scan/benchmark_backends.ipynb b/doc/gallery/scan/benchmark_backends.ipynb index 3bc77de8a0..ee078e8a49 100644 --- a/doc/gallery/scan/benchmark_backends.ipynb +++ b/doc/gallery/scan/benchmark_backends.ipynb @@ -35,6 +35,17 @@ { "cell_type": "code", "execution_count": 2, + "id": "d5fc1350", + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.io as pio\n", + "pio.renderers.default = \"notebook\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, "id": "daa0969b", "metadata": {}, "outputs": [ @@ -42,7 +53,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "pytensor version: 0+untagged.31335.g4312d8c\n", + "pytensor version: 0+untagged.31336.g403c7f5.dirty\n", "jax version: 0.7.2\n", "numba version: 0.62.1\n" ] @@ -56,7 +67,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "8294718d", "metadata": {}, "outputs": [], @@ -246,7 +257,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "6e76a860", "metadata": {}, "outputs": [], @@ -281,7 +292,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "ed368809", "metadata": {}, "outputs": [], @@ -305,7 +316,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "bf48d6bf", "metadata": {}, "outputs": [], @@ -321,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "893c3124", "metadata": {}, "outputs": [], @@ -337,7 +348,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "63bfdffe", "metadata": {}, "outputs": [], @@ -351,7 +362,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "65bf994e", "metadata": {}, "outputs": [ @@ -393,52 +404,52 @@ " fibonacci_pytensor\n", " fibonacci_inputs\n", " 10\n", - " 64518.025001\n", - " 67663.204200\n", - " 66403.935840\n", - " 1071.000294\n", - " 66790.32500\n", - " 910.641799\n", - " 0.015059\n", + " 68155.341699\n", + " 69006.229100\n", + " 68637.53498\n", + " 277.683947\n", + " 68645.579100\n", + " 151.466600\n", + " 0.014569\n", " 5\n", " \n", " \n", " fibonacci_numba\n", " fibonacci_inputs\n", " 10\n", - " 75.491700\n", - " 104.429100\n", - " 93.351733\n", - " 6.430028\n", - " 93.51875\n", - " 4.254199\n", - " 10.712174\n", - " 12\n", + " 86.483300\n", + " 108.250001\n", + " 95.49680\n", + " 6.168624\n", + " 95.529199\n", + " 5.229100\n", + " 10.471555\n", + " 13\n", " \n", " \n", " fibonacci_jax\n", " fibonacci_inputs\n", " 10\n", - " 2.112500\n", - " 7.441601\n", - " 3.203320\n", - " 2.119560\n", - " 2.12500\n", - " 0.112499\n", - " 312.176109\n", + " 2.400001\n", + " 9.104201\n", + " 3.79250\n", + " 2.656539\n", + " 2.462500\n", + " 0.154199\n", + " 263.678308\n", " 5\n", " \n", " \n", " fibonacci_pytensor_numba\n", " fibonacci_inputs\n", " 10\n", - " 3325.600000\n", - " 3470.295800\n", - " 3371.584140\n", - " 50.820262\n", - " 3355.99160\n", - " 15.641699\n", - " 0.296596\n", + " 3398.070800\n", + " 3432.645799\n", + " 3416.00250\n", + " 11.031143\n", + " 3417.499999\n", + " 3.904101\n", + " 0.292740\n", " 5\n", " \n", " \n", @@ -447,31 +458,31 @@ ], "text/plain": [ " Loops Min (us) Max (us) \\\n", - "fibonacci_pytensor fibonacci_inputs 10 64518.025001 67663.204200 \n", - "fibonacci_numba fibonacci_inputs 10 75.491700 104.429100 \n", - "fibonacci_jax fibonacci_inputs 10 2.112500 7.441601 \n", - "fibonacci_pytensor_numba fibonacci_inputs 10 3325.600000 3470.295800 \n", - "\n", - " Mean (us) StdDev (us) \\\n", - "fibonacci_pytensor fibonacci_inputs 66403.935840 1071.000294 \n", - "fibonacci_numba fibonacci_inputs 93.351733 6.430028 \n", - "fibonacci_jax fibonacci_inputs 3.203320 2.119560 \n", - "fibonacci_pytensor_numba fibonacci_inputs 3371.584140 50.820262 \n", - "\n", - " Median (us) IQR (us) \\\n", - "fibonacci_pytensor fibonacci_inputs 66790.32500 910.641799 \n", - "fibonacci_numba fibonacci_inputs 93.51875 4.254199 \n", - "fibonacci_jax fibonacci_inputs 2.12500 0.112499 \n", - "fibonacci_pytensor_numba fibonacci_inputs 3355.99160 15.641699 \n", + "fibonacci_pytensor fibonacci_inputs 10 68155.341699 69006.229100 \n", + "fibonacci_numba fibonacci_inputs 10 86.483300 108.250001 \n", + "fibonacci_jax fibonacci_inputs 10 2.400001 9.104201 \n", + "fibonacci_pytensor_numba fibonacci_inputs 10 3398.070800 3432.645799 \n", + "\n", + " Mean (us) StdDev (us) \\\n", + "fibonacci_pytensor fibonacci_inputs 68637.53498 277.683947 \n", + "fibonacci_numba fibonacci_inputs 95.49680 6.168624 \n", + "fibonacci_jax fibonacci_inputs 3.79250 2.656539 \n", + "fibonacci_pytensor_numba fibonacci_inputs 3416.00250 11.031143 \n", + "\n", + " Median (us) IQR (us) \\\n", + "fibonacci_pytensor fibonacci_inputs 68645.579100 151.466600 \n", + "fibonacci_numba fibonacci_inputs 95.529199 5.229100 \n", + "fibonacci_jax fibonacci_inputs 2.462500 0.154199 \n", + "fibonacci_pytensor_numba fibonacci_inputs 3417.499999 3.904101 \n", "\n", " OPS (Kops/s) Samples \n", - "fibonacci_pytensor fibonacci_inputs 0.015059 5 \n", - "fibonacci_numba fibonacci_inputs 10.712174 12 \n", - "fibonacci_jax fibonacci_inputs 312.176109 5 \n", - "fibonacci_pytensor_numba fibonacci_inputs 0.296596 5 " + "fibonacci_pytensor fibonacci_inputs 0.014569 5 \n", + "fibonacci_numba fibonacci_inputs 10.471555 13 \n", + "fibonacci_jax fibonacci_inputs 263.678308 5 \n", + "fibonacci_pytensor_numba fibonacci_inputs 0.292740 5 " ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -495,7 +506,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "7b8bb97b", "metadata": {}, "outputs": [], @@ -519,7 +530,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "14327cbf", "metadata": {}, "outputs": [], @@ -535,7 +546,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "3943328f", "metadata": {}, "outputs": [], @@ -551,7 +562,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "d43c4f9c", "metadata": {}, "outputs": [], @@ -562,7 +573,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "f0f4ede5", "metadata": {}, "outputs": [], @@ -576,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "id": "cdab8946", "metadata": {}, "outputs": [ @@ -618,52 +629,52 @@ " elementwise_multiply_pytensor\n", " elem_mult_inputs\n", " 10\n", - " 3.095801\n", - " 18.916700\n", - " 3.748584\n", - " 0.513067\n", - " 3.708400\n", - " 0.241699\n", - " 266.767398\n", - " 11841\n", + " 3.120801\n", + " 24.929100\n", + " 3.680448\n", + " 0.486678\n", + " 3.595800\n", + " 0.133300\n", + " 271.706047\n", + " 13825\n", " \n", " \n", " elementwise_multiply_numba\n", " elem_mult_inputs\n", " 10\n", - " 0.341701\n", - " 0.779200\n", - " 0.386048\n", - " 0.085013\n", - " 0.370899\n", - " 0.029099\n", - " 2590.353075\n", - " 23\n", + " 0.383401\n", + " 0.695800\n", + " 0.413064\n", + " 0.062775\n", + " 0.397950\n", + " 0.011476\n", + " 2420.933988\n", + " 22\n", " \n", " \n", " elementwise_multiply_jax\n", " elem_mult_inputs\n", " 10\n", - " 7.995899\n", - " 9.987499\n", - " 8.917886\n", - " 0.568675\n", - " 8.895900\n", - " 0.456251\n", - " 112.134202\n", + " 7.612501\n", + " 8.129200\n", + " 7.791072\n", + " 0.151626\n", + " 7.762501\n", + " 0.087450\n", + " 128.352043\n", " 7\n", " \n", " \n", " elementwise_multiply_pytensor_numba\n", " elem_mult_inputs\n", " 10\n", - " 3.600000\n", - " 8.941699\n", - " 4.379155\n", - " 1.635324\n", - " 3.666600\n", - " 0.291699\n", - " 228.354537\n", + " 3.875000\n", + " 5.870899\n", + " 4.145834\n", + " 0.611565\n", + " 3.925001\n", + " 0.083400\n", + " 241.206018\n", " 9\n", " \n", " \n", @@ -672,37 +683,37 @@ ], "text/plain": [ " Loops Min (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 10 3.095801 \n", - "elementwise_multiply_numba elem_mult_inputs 10 0.341701 \n", - "elementwise_multiply_jax elem_mult_inputs 10 7.995899 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 10 3.600000 \n", + "elementwise_multiply_pytensor elem_mult_inputs 10 3.120801 \n", + "elementwise_multiply_numba elem_mult_inputs 10 0.383401 \n", + "elementwise_multiply_jax elem_mult_inputs 10 7.612501 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 10 3.875000 \n", "\n", " Max (us) Mean (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 18.916700 3.748584 \n", - "elementwise_multiply_numba elem_mult_inputs 0.779200 0.386048 \n", - "elementwise_multiply_jax elem_mult_inputs 9.987499 8.917886 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 8.941699 4.379155 \n", + "elementwise_multiply_pytensor elem_mult_inputs 24.929100 3.680448 \n", + "elementwise_multiply_numba elem_mult_inputs 0.695800 0.413064 \n", + "elementwise_multiply_jax elem_mult_inputs 8.129200 7.791072 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 5.870899 4.145834 \n", "\n", " StdDev (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 0.513067 \n", - "elementwise_multiply_numba elem_mult_inputs 0.085013 \n", - "elementwise_multiply_jax elem_mult_inputs 0.568675 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 1.635324 \n", + "elementwise_multiply_pytensor elem_mult_inputs 0.486678 \n", + "elementwise_multiply_numba elem_mult_inputs 0.062775 \n", + "elementwise_multiply_jax elem_mult_inputs 0.151626 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 0.611565 \n", "\n", " Median (us) IQR (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 3.708400 0.241699 \n", - "elementwise_multiply_numba elem_mult_inputs 0.370899 0.029099 \n", - "elementwise_multiply_jax elem_mult_inputs 8.895900 0.456251 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 3.666600 0.291699 \n", + "elementwise_multiply_pytensor elem_mult_inputs 3.595800 0.133300 \n", + "elementwise_multiply_numba elem_mult_inputs 0.397950 0.011476 \n", + "elementwise_multiply_jax elem_mult_inputs 7.762501 0.087450 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 3.925001 0.083400 \n", "\n", " OPS (Kops/s) Samples \n", - "elementwise_multiply_pytensor elem_mult_inputs 266.767398 11841 \n", - "elementwise_multiply_numba elem_mult_inputs 2590.353075 23 \n", - "elementwise_multiply_jax elem_mult_inputs 112.134202 7 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 228.354537 9 " + "elementwise_multiply_pytensor elem_mult_inputs 271.706047 13825 \n", + "elementwise_multiply_numba elem_mult_inputs 2420.933988 22 \n", + "elementwise_multiply_jax elem_mult_inputs 128.352043 7 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 241.206018 9 " ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -734,7 +745,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "id": "c1226cfc", "metadata": {}, "outputs": [], @@ -796,7 +807,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "id": "14937a2a", "metadata": {}, "outputs": [], @@ -857,7 +868,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "id": "815967a4", "metadata": {}, "outputs": [], @@ -896,7 +907,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "id": "024f421f", "metadata": {}, "outputs": [], @@ -906,7 +917,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "id": "6c892129", "metadata": {}, "outputs": [], @@ -921,7 +932,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "id": "d21873d6", "metadata": {}, "outputs": [], @@ -935,7 +946,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "id": "d8eab72d", "metadata": {}, "outputs": [ @@ -948,1244 +959,4084 @@ " vertical-align: middle;\n", " }\n", "\n", - " .dataframe tbody tr th {\n", - " vertical-align: top;\n", - " }\n", + " .dataframe tbody tr th {\n", + " vertical-align: top;\n", + " }\n", + "\n", + " .dataframe thead th {\n", + " text-align: right;\n", + " }\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
LoopsMin (us)Max (us)Mean (us)StdDev (us)Median (us)IQR (us)OPS (Kops/s)Samples
cusum_adaptive_pytensorcusum_inputs10128.400000299.025000143.1535899.045458141.3979514.8145506.985504700
cusum_adaptive_numbacusum_inputs101.9125002.7541002.0541710.2861521.9375000.024949486.8142877
cusum_adaptive_jaxcusum_inputs1013.29999915.16670013.6954740.48420213.4937510.29590173.01682634
cusum_adaptive_pytensor_numbacusum_inputs1025.82090133.77080027.5583203.10808026.0708000.15410036.2866825
cusum_adaptive_pytensor_jaxcusum_inputs1019.60420033.14580122.0097762.32712921.4833010.61249945.43435629
\n", + "" + ], + "text/plain": [ + " Loops Min (us) Max (us) \\\n", + "cusum_adaptive_pytensor cusum_inputs 10 128.400000 299.025000 \n", + "cusum_adaptive_numba cusum_inputs 10 1.912500 2.754100 \n", + "cusum_adaptive_jax cusum_inputs 10 13.299999 15.166700 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 10 25.820901 33.770800 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 10 19.604200 33.145801 \n", + "\n", + " Mean (us) StdDev (us) \\\n", + "cusum_adaptive_pytensor cusum_inputs 143.153589 9.045458 \n", + "cusum_adaptive_numba cusum_inputs 2.054171 0.286152 \n", + "cusum_adaptive_jax cusum_inputs 13.695474 0.484202 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 27.558320 3.108080 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 22.009776 2.327129 \n", + "\n", + " Median (us) IQR (us) \\\n", + "cusum_adaptive_pytensor cusum_inputs 141.397951 4.814550 \n", + "cusum_adaptive_numba cusum_inputs 1.937500 0.024949 \n", + "cusum_adaptive_jax cusum_inputs 13.493751 0.295901 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 26.070800 0.154100 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 21.483301 0.612499 \n", + "\n", + " OPS (Kops/s) Samples \n", + "cusum_adaptive_pytensor cusum_inputs 6.985504 700 \n", + "cusum_adaptive_numba cusum_inputs 486.814287 7 \n", + "cusum_adaptive_jax cusum_inputs 73.016826 34 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 36.286682 5 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 45.434356 29 " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cusum_bench.run(\n", + " inputs={\n", + " \"cusum_inputs\": {\"x\": xs, \"alpha\": 0.1, \"k\": 0.5, \"h\": 3.5},\n", + " }\n", + ")\n", + "cusum_bench.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "3e9c3339", + "metadata": {}, + "outputs": [], + "source": [ + "outputs = cusum_adaptive_numba(xs_std, alpha=0.1, k=0.5, h=3.5)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "b85d0c0e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " \n", + " " ] }, - "execution_count": 22, "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cusum_bench.run(\n", - " inputs={\n", - " \"cusum_inputs\": {\"x\": xs, \"alpha\": 0.1, \"k\": 0.5, \"h\": 3.5},\n", - " }\n", - ")\n", - "cusum_bench.summary()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "3e9c3339", - "metadata": {}, - "outputs": [], - "source": [ - "outputs = cusum_adaptive_numba(xs_std, alpha=0.1, k=0.5, h=3.5)" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "b85d0c0e", - "metadata": {}, - "outputs": [ + "output_type": "display_data" + }, { "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "name": "series", - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "y": { - "bdata": "EwgzPqBruT9rpRy/bgTIP832Xz9EHPo+z/ieP7TnPT9FEQDADWWcPxiMoj8hRLS+xJdEvofY1r32FsY/bzAnQCSVir2Cow8/3QLnvmxiFUDoBdg+93UEvzmAFD//5YM/veX+PuEwqL3Elzk//NDfPp6tKj95FTo/IgnhPp+mIj975Ie/F1wbvJ9kbr6Hrnm8KqaJvkqAJz8htCq/KAWavg0xcr3ngBFAAYSrP/EeQD8bLyi/aPgDPrypdz8FB5k/QQt2P3nFiz/3P2I/MjA0vn6V2r4eKhfAh2/Rv3+SVr/0f72+dRmyvnGdkr+1GQq/ftDsv5A/Uj/SDQ7AI+eFvZaJhD+94oo/RzXnPx5kpD3v3hDA3ed0vzZxhL8r1hS/W8xev6VO3D4RcJS+aQZuvnmGsr9X07W//iKWv+uaLr+cjWq/NnVWv/2UbL4VXQ6/OVQXPZyMCb/dEQe/4DgPvgShgr/pwcG8zWrTv9msCj7IwC2/M2Pxvqw9EL83SKU/fOjYPp2D2L5f0+g9xAMkvw==", - "dtype": "f4" - } - }, - { - "name": "cum. positive devs.", - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "y": { - "bdata": "AAAAAAAAAAAAAABEMK/kPwAAAAAAAAAAehSuaM7u5j+0832wGSrmPzh52JvHfdE/CEuc28rE4D84k4TswfDPPwAAAAAAAAAACGuKR3Mj1z8UTJD9D8TlPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZc3sqRt+Q/8p4pTVobAUDyGLqClkrwPzC8k/yn1OA/AAAAAAAAAACS2pphBhfzP7wWzGV5vd8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMiqIWA1YPc/4ipz89cr/j/66qLpmv/6P0glbwY0m8g/AAAAAAAAAACQ61Uab8y1P3xpguzfStQ/bHOkbtby0D+Qr1wdvEbSP1gwPTcWH7E/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsMfZaE1fkPwAAAAAAAAAAAAAAAAAAAACsBouUchjrPyIThKOnp/k/rTAePZ0RB0B67b2gYHUDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOO8ujICPRPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4BqbgsostD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoKLiQUGPGPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANYqR3W1ePI/MJ5teFzN9T8CDLrBnZ7nPxT66A5/fOM/AAAAAAAAAAA=", - "dtype": "f8" - } - }, - { - "name": "cum. negative devs.", - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "y": { - "bdata": "AAAAAAAAAAAAAAAAAAAAAJqZmWUcp9Q/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJo3BIX9P/w/YHOGzILc2T8AAAAAAAAAAGBIiylmi8w/hAnv7jNkzT+wbl4kqnG7PwAAAAAAAAAAAAAAAAAAAAAgT5J54cG+PwAAAAAAAAAAeG36X3Lc2T8AAAAAAAAAAAAAAAAAAAAAzBiufmK74D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQsmKFLXuzPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPp4osp/Qu4/dH/BkUCX6T98OGqzcjjqP2pFdeLZ6+I/qGpyxk0O4j8AAAAAAAAAAEAOQ7MVwtQ/WGmYz59Rzj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQZVKPRsN8/OJM/xsR+xz8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArEzLyCOtyT8EXi0U5dLhP7+24zPfjQRAdgxAKddqDUBoJhMajz8PQMK9auhIIA1ALPkfjOWnCkBye6kIcsYNQEsK8mfO0QtAbkVzXlGMEUCR/ijm3QIGQBrN5ASeug9AlaDa7IyQCEDUvW+P4JTzPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMRFreLjDPk/WtHiCcb5+z9gNcaeqe7+P5pC+S/5Q/o/gM5ATABt+T9y/jeN4JDUPwAAAAAAAAAAAAAAAAAAAABqbc+dv7/dP/CnHsl0Z+s/dOcc12bz7T+cIOjGToHgP7ZBcd2mGNM/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0LsFbvUw4T8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "dtype": "f8" - } - }, - { - "name": "Exp. Mean", - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "y": { - "bdata": "AAAAYAJhxj8AAAB4b1fTPzQzM0uD+8o/C9ejLpok1j+KQWCwHIfZPy9uI0X0Gdo/KuOfZJlw3z86JnvgkIXgP2jeEBSx7tA/+JR1OBMP1z/g0mlMX+HcPzCkxfQuvdc/kuCxouoi1D/qFqBZjHPRP9NHQ2pXnNk/UuA3FmDi4z/kSTKf563hP7R14Ej1tOE/d236vxb83D/cSso8KYPkP8apT5Cuz+M/zBiunqMs4D/rr5wrx2ngP+03QAfAEeI/vJiGzgLb4T+FrFhZRJ3fP6JNzgHei+A/Raw5+2JK4D+ltICohMvgP/sIp+cIceE/SLt8oJYa4T/B2wlaNm3hP/XxRBXCktg/9gw+dyUO1j8RclFTGlzSP9wZFtcfbdA/85T0D0Ugyj+oH1wOdePPP34chuYaKsQ/sZkk0lSYvD/tI1Soyji4P+JUeX8RANQ/mP+5MnaT2j+i/0BnsLjcP0UZVOMKpdU/WLDLPxdO1D8dhWo5U3fYP2cRE1q+q90/CPvu3mxt4D/u4aNoa0fiP72xxid6R+M/K9MyYsfJ4D+0FfWDiHzbP97zhe0iPsM/KCTVUT0Anb+9wZzlgPu7v2KKhhpgVMG/WEmsBJMMxL/O7bObVFrQvzqJu0WKK9K/gftbWJwx3L9aYuy1Qh7Uv9zFEIXoJ+C/JmRR2MF/3b9WDRYpGuzTv2d+9Mm1+MW/6HHsUYLFmj/czBCYLiigP+jRleq+Vsm/qNEpo26G0b/kb3KsDGXWvxrLM3tM4Ne/ZdDhTvoO27+OO8sDTJnVv2aC0DleS9W/wttuQhKn1L+WkjDifIPbv8QOycVA7eC/fcABcs384r/XxjRwdUXjv8F/L9iuRuS/x78qPOHt5L/N34yAW5Pjv5/8sQPJZeO/XGNT3vBW4b85puRUNFPhv83IzULoR+G/hQGGIhgA4L+SNBKfgqrhv6FeuhlF89+/L0T60b2p478qCi5cbUPhv4xvKYZ+teG/mBfyY11y4b+ie/OZTIHhv1irHFW6Pte/aM2ZjIw10r9En71BPRjTvyTcXaInddC/IUYhkojp0r8=", - "dtype": "f8" - } - }, - { - "name": "positive alarms", - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "y": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] - }, - { - "name": "negative alarms", - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "y": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 1, - 0, - 1, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] - } - ], - "layout": { - "legend": { - "orientation": "h", - "x": 0, - "xanchor": "left", - "y": 1.1, - "yanchor": "top" - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#f2f5fa" - }, - "error_y": { - "color": "#f2f5fa" - }, - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "baxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#506784" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "header": { - "fill": { - "color": "#2a3f5f" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#f2f5fa", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#f2f5fa" - }, - "geo": { - "bgcolor": "rgb(17,17,17)", - "lakecolor": "rgb(17,17,17)", - "landcolor": "rgb(17,17,17)", - "showlakes": true, - "showland": true, - "subunitcolor": "#506784" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "dark" - }, - "paper_bgcolor": "rgb(17,17,17)", - "plot_bgcolor": "rgb(17,17,17)", - "polar": { - "angularaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "radialaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "yaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "zaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - } - }, - "shapedefaults": { - "line": { - "color": "#f2f5fa" - } - }, - "sliderdefaults": { - "bgcolor": "#C8D4E3", - "bordercolor": "rgb(17,17,17)", - "borderwidth": 1, - "tickwidth": 0 - }, - "ternary": { - "aaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "baxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "caxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "updatemenudefaults": { - "bgcolor": "#506784", - "borderwidth": 0 - }, - "xaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - } - } - }, - "title": { - "text": "CUSUM Change Point Detection Algorithm" - }, - "xaxis": { - "title": { - "text": "Time Index" - } - }, - "yaxis": { - "title": { - "text": "Standardized Series Scaled" - } - } - } - } + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" @@ -2259,7 +5110,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "id": "eab4cbb9", "metadata": {}, "outputs": [], @@ -2324,7 +5175,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "id": "e6997389", "metadata": {}, "outputs": [], @@ -2394,7 +5245,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "id": "094b9e8e", "metadata": {}, "outputs": [], @@ -2413,7 +5264,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 29, "id": "03e5e927", "metadata": {}, "outputs": [], @@ -2468,7 +5319,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 30, "id": "69aea9a2", "metadata": {}, "outputs": [], @@ -2482,7 +5333,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 31, "id": "5aee4a18", "metadata": {}, "outputs": [ @@ -2524,52 +5375,52 @@ " pelt_pytensor\n", " pelt_inputs\n", " 10\n", - " 11427.629100\n", - " 12441.8708\n", - " 12163.819422\n", - " 287.094492\n", - " 12253.829101\n", - " 176.587500\n", - " 0.082211\n", - " 9\n", + " 11940.970800\n", + " 12649.075000\n", + " 12293.823425\n", + " 235.799063\n", + " 12403.643750\n", + " 306.109426\n", + " 0.081342\n", + " 8\n", " \n", " \n", " pelt_numba\n", " pelt_inputs\n", " 10\n", - " 19.295899\n", - " 22.0125\n", - " 20.349200\n", - " 0.991247\n", - " 20.320900\n", - " 1.316701\n", - " 49.141982\n", + " 20.704200\n", + " 23.512500\n", + " 22.246680\n", + " 1.177433\n", + " 22.637501\n", + " 2.362601\n", + " 44.950527\n", " 5\n", " \n", " \n", " pelt_jax\n", " pelt_inputs\n", " 10\n", - " 15.066699\n", - " 65.6042\n", - " 50.399558\n", - " 17.811394\n", - " 56.879199\n", - " 5.268800\n", - " 19.841444\n", - " 19\n", + " 11.879099\n", + " 63.266601\n", + " 48.327435\n", + " 19.312952\n", + " 57.262501\n", + " 6.708401\n", + " 20.692180\n", + " 17\n", " \n", " \n", " pelt_pytensor_numba\n", " pelt_inputs\n", " 10\n", - " 2507.937500\n", - " 2881.2875\n", - " 2627.499160\n", - " 130.434474\n", - " 2581.904099\n", - " 26.666699\n", - " 0.380590\n", + " 2516.558301\n", + " 2667.204200\n", + " 2577.808340\n", + " 49.749941\n", + " 2572.466699\n", + " 26.212500\n", + " 0.387926\n", " 5\n", " \n", " \n", @@ -2577,26 +5428,26 @@ "" ], "text/plain": [ - " Loops Min (us) Max (us) \\\n", - "pelt_pytensor pelt_inputs 10 11427.629100 12441.8708 \n", - "pelt_numba pelt_inputs 10 19.295899 22.0125 \n", - "pelt_jax pelt_inputs 10 15.066699 65.6042 \n", - "pelt_pytensor_numba pelt_inputs 10 2507.937500 2881.2875 \n", + " Loops Min (us) Max (us) \\\n", + "pelt_pytensor pelt_inputs 10 11940.970800 12649.075000 \n", + "pelt_numba pelt_inputs 10 20.704200 23.512500 \n", + "pelt_jax pelt_inputs 10 11.879099 63.266601 \n", + "pelt_pytensor_numba pelt_inputs 10 2516.558301 2667.204200 \n", "\n", " Mean (us) StdDev (us) Median (us) \\\n", - "pelt_pytensor pelt_inputs 12163.819422 287.094492 12253.829101 \n", - "pelt_numba pelt_inputs 20.349200 0.991247 20.320900 \n", - "pelt_jax pelt_inputs 50.399558 17.811394 56.879199 \n", - "pelt_pytensor_numba pelt_inputs 2627.499160 130.434474 2581.904099 \n", + "pelt_pytensor pelt_inputs 12293.823425 235.799063 12403.643750 \n", + "pelt_numba pelt_inputs 22.246680 1.177433 22.637501 \n", + "pelt_jax pelt_inputs 48.327435 19.312952 57.262501 \n", + "pelt_pytensor_numba pelt_inputs 2577.808340 49.749941 2572.466699 \n", "\n", " IQR (us) OPS (Kops/s) Samples \n", - "pelt_pytensor pelt_inputs 176.587500 0.082211 9 \n", - "pelt_numba pelt_inputs 1.316701 49.141982 5 \n", - "pelt_jax pelt_inputs 5.268800 19.841444 19 \n", - "pelt_pytensor_numba pelt_inputs 26.666699 0.380590 5 " + "pelt_pytensor pelt_inputs 306.109426 0.081342 8 \n", + "pelt_numba pelt_inputs 2.362601 44.950527 5 \n", + "pelt_jax pelt_inputs 6.708401 20.692180 17 \n", + "pelt_pytensor_numba pelt_inputs 26.212500 0.387926 5 " ] }, - "execution_count": 30, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -2612,7 +5463,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 32, "id": "47cae530", "metadata": {}, "outputs": [], @@ -2622,7 +5473,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 33, "id": "7b395b06", "metadata": {}, "outputs": [], @@ -2746,7 +5597,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "id": "e1de7df5", "metadata": {}, "outputs": [], @@ -2775,7 +5626,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "id": "b73d80ac", "metadata": {}, "outputs": [], @@ -2785,1043 +5636,39 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "id": "e2e376de", "metadata": {}, "outputs": [ { "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "hovertemplate": "Time Point: %{x}
Actual: %{y}", - "line": { - "color": "royalblue" - }, - "mode": "lines", - "name": "Actuals", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "xaxis": "x", - "y": { - "bdata": "crKPQg66zEImAVRC0TDSQsA8sUK7uZ5CmtPCQuLcqkJSxp1BpNzBQjYqxELV5mxCPz58QjlLgkIaeNFCDT4CQ/kThEIfNKJCfGdjQson90IeiZtCvA5dQhUdo0JCsbhCaSyfQqVig0JFDqpC0UOcQqpDp0LMJapCB2GcQg3DpULb5yhCp92GQtxUeEIKl4ZCvuB0QnGrpkIUvk5CW9BxQrR8hEIAQPRCnoXHQgxHq0KGr09CvH6NQj2stUL3mcBCql61QrGju0JFqrFCPsd9Qum6ZULcNzFBVbLjQVNSPkJrLGtCpU5tQt7gIEJQ8lpC8bO6QZarrkJDyGdBADCEQn7uuELSTrtCtd3dQoUqi0Js6VZBl/cyQht9K0KC7VZCDz47QsDvm0LT23JCrV14QjP9CEKyhAZC7j0eQjZITUKi1zZCSV0+Qj+AeELKWVlCIBeJQiEnW0K6FFxCaZ6AQp/YLELaL4ZCy7rgQQzPjULdmU1CU3ZhQuWlWEJIMMVCUp6bQhUeZkJixIxCDT9RQg==", - "dtype": "f4" - }, - "yaxis": "y" - }, - { - "hoverinfo": "skip", - "line": { - "color": "rgba(105, 105, 105, 0.25)" - }, - "mode": "lines", - "name": "Actuals", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "xaxis": "x2", - "y": { - "bdata": "crKPQg66zEImAVRC0TDSQsA8sUK7uZ5CmtPCQuLcqkJSxp1BpNzBQjYqxELV5mxCPz58QjlLgkIaeNFCDT4CQ/kThEIfNKJCfGdjQson90IeiZtCvA5dQhUdo0JCsbhCaSyfQqVig0JFDqpC0UOcQqpDp0LMJapCB2GcQg3DpULb5yhCp92GQtxUeEIKl4ZCvuB0QnGrpkIUvk5CW9BxQrR8hEIAQPRCnoXHQgxHq0KGr09CvH6NQj2stUL3mcBCql61QrGju0JFqrFCPsd9Qum6ZULcNzFBVbLjQVNSPkJrLGtCpU5tQt7gIEJQ8lpC8bO6QZarrkJDyGdBADCEQn7uuELSTrtCtd3dQoUqi0Js6VZBl/cyQht9K0KC7VZCDz47QsDvm0LT23JCrV14QjP9CEKyhAZC7j0eQjZITUKi1zZCSV0+Qj+AeELKWVlCIBeJQiEnW0K6FFxCaZ6AQp/YLELaL4ZCy7rgQQzPjULdmU1CU3ZhQuWlWEJIMMVCUp6bQhUeZkJixIxCDT9RQg==", - "dtype": "f4" - }, - "yaxis": "y2" - }, - { - "hovertemplate": "Time Point: %{x}
Average: %{y}", - "line": { - "color": "royalblue" - }, - "name": "Average", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "xaxis": "x2", - "y": { - "bdata": "AAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAoOLUU0AAAACg4tRTQAAAAKDi1FNAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0AAAAAgQ8JLQAAAACBDwktAAAAAIEPCS0A=", - "dtype": "f8" - }, - "yaxis": "y2" - }, - { - "hovertemplate": "Time Point: %{x}
Standard Deviation: %{y}", - "line": { - "color": "royalblue" - }, - "name": "Standard Deviation", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "xaxis": "x3", - "y": { - "bdata": "AAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAoCXANEAAAACgJcA0QAAAAKAlwDRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEAAAABAJNU0QAAAAEAk1TRAAAAAQCTVNEA=", - "dtype": "f8" - }, - "yaxis": "y3" - }, - { - "hovertemplate": "Time Point: %{x}
Cost: %{y}", - "line": { - "color": "royalblue" - }, - "name": "Cumulative Cost", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==", - "dtype": "i1" - }, - "xaxis": "x4", - "y": { - "bdata": "FlW1u7FrIsAAAAAAAADwfwAAAAAAAPB/GLavc4BMAUDuWfXxLk8KQCihxbvZpgpA+GWcdwPsCkAc0IByO0YNQCpTshE9Rg1ACQ/rumOtJEDKfEI+QMolQJRGWswO1CZA++q+NFpuKEDgzqs38FMpQFxR+34P5ylAjOVj3qtPLECXctoKi2MyQMS0kJ6K1TJA+Lg/G6DVMkCbvJuG3NYzQOTWCiFN8zZAxe4lGWP8NkCb99NJqzA4QPzb/J3TMDhASqHwYRhoOECOPIK0lGk4QBBppccP0zhAU6p3v9faOEBEWqcbNd44QDKb+CyX4ThAaDjGNQLpOED253yFk+w4QASfic8m7jhAhGEqbHt5O0DxpQbZSrw7QOvsDC2XPzxAqggFie56PECUEx+FD/88QFces4iHCj1AYkXWGxw/PkDaKxqMsb8+QNGtqNEb9D5AbVgiVFw2QUBw4eUdRZ1BQNO+V4lHqEFANNX8MpREQkCqLNUvXlBCQAFdO2CudEJAOWepMyG8QkBN2Bx4F9xCQM1Vd9MoDUNAYehSqbchQ0DgNxL541hDQL5D69DfvkNAAuuk+VelR0BiARhbcOhIQKptWI2C7khApsCfqvRqSUCsBbj9p6tJQJQWctwTrklAdukieLzHSUCeMGIGPCJKQISYkf/OuEtAdIi7oOmMTECCy0EctfFMQGClt0VApU5AOaGK/t4VUECCNZmlJN5QQJ5tpd+aJlFAwg0F7VpQUkBP9IMtw1tSQJv4N4FMalJADsyvdk5qUkAakzMXym9SQJ7Q4pDPrlJALpTYUaeyUkC79Er/FbhSQGnTtfJl51JAUsKbIe0VU0D18sucWCtTQDaZaOa2K1NAa7C7T5wxU0De9LMymzRTQAoF7lI5PlNAEY25AGw+U0CPjy+sfVhTQO9sKPusWFNAhutuf+tYU0CTsVpedGVTQM/B7z6/cVNA4fFzHJ2FU0DQqSGWI85TQKpRKwn271NA0eX6xInwU0ARAhG3V/FTQCijb2Nd8VNAoDnTeevMVEC5+1vEFQdVQBqbQ7iqB1VAC0COGpwgVUB9TompxyFVQA==", - "dtype": "f8" - }, - "yaxis": "y4" - } - ], - "layout": { - "annotations": [ - { - "font": { - "size": 16 - }, - "showarrow": false, - "text": "Detected Changepoints", - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 1, - "yanchor": "bottom", - "yref": "paper" - }, - { - "font": { - "size": 16 - }, - "showarrow": false, - "text": "Average Shifts", - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 0.71875, - "yanchor": "bottom", - "yref": "paper" - }, - { - "font": { - "size": 16 - }, - "showarrow": false, - "text": "Variability Shifts", - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 0.4375, - "yanchor": "bottom", - "yref": "paper" - }, - { - "font": { - "size": 16 - }, - "showarrow": false, - "text": "Cumulative Cost", - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 0.15625, - "yanchor": "bottom", - "yref": "paper" - } - ], - "height": 1000, - "shapes": [ - { - "line": { - "color": "red", - "dash": "dash" - }, - "type": "line", - "x0": 51, - "x1": 51, - "xref": "x", - "y0": 0, - "y1": 1, - "yref": "y domain" - }, - { - "line": { - "color": "red", - "dash": "dash" - }, - "type": "line", - "x0": 51, - "x1": 51, - "xref": "x4", - "y0": 0, - "y1": 1, - "yref": "y4 domain" - } - ], - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#f2f5fa" - }, - "error_y": { - "color": "#f2f5fa" - }, - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "baxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#506784" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "header": { - "fill": { - "color": "#2a3f5f" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#f2f5fa", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#f2f5fa" - }, - "geo": { - "bgcolor": "rgb(17,17,17)", - "lakecolor": "rgb(17,17,17)", - "landcolor": "rgb(17,17,17)", - "showlakes": true, - "showland": true, - "subunitcolor": "#506784" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "dark" - }, - "paper_bgcolor": "rgb(17,17,17)", - "plot_bgcolor": "rgb(17,17,17)", - "polar": { - "angularaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "radialaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "yaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "zaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - } - }, - "shapedefaults": { - "line": { - "color": "#f2f5fa" - } - }, - "sliderdefaults": { - "bgcolor": "#C8D4E3", - "bordercolor": "rgb(17,17,17)", - "borderwidth": 1, - "tickwidth": 0 - }, - "ternary": { - "aaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "baxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "caxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "updatemenudefaults": { - "bgcolor": "#506784", - "borderwidth": 0 - }, - "xaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - } - } - }, - "width": 1200, - "xaxis": { - "anchor": "y", - "domain": [ - 0, - 1 - ] - }, - "xaxis2": { - "anchor": "y2", - "domain": [ - 0, - 1 - ] - }, - "xaxis3": { - "anchor": "y3", - "domain": [ - 0, - 1 - ] - }, - "xaxis4": { - "anchor": "y4", - "domain": [ - 0, - 1 - ] - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.84375, - 1 - ] - }, - "yaxis2": { - "anchor": "x2", - "domain": [ - 0.5625, - 0.71875 - ] - }, - "yaxis3": { - "anchor": "x3", - "domain": [ - 0.28125, - 0.4375 - ] - }, - "yaxis4": { - "anchor": "x4", - "domain": [ - 0, - 0.15625 - ] - } - } - } + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" @@ -3849,7 +5696,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "id": "5004eeab", "metadata": {}, "outputs": [], @@ -4024,7 +5871,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 38, "id": "25bcb14e", "metadata": {}, "outputs": [], @@ -4093,7 +5940,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 39, "id": "cd715dfb", "metadata": {}, "outputs": [], @@ -4158,7 +6005,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 40, "id": "5af37c40", "metadata": {}, "outputs": [], @@ -4208,7 +6055,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 41, "id": "3c9e7254", "metadata": {}, "outputs": [], @@ -4227,7 +6074,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 42, "id": "00472afd", "metadata": {}, "outputs": [], @@ -4241,7 +6088,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 43, "id": "68ec703d", "metadata": {}, "outputs": [ @@ -4249,7 +6096,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/qv/63yqp4p50630y7pqfgcbgtq80000gn/T/tmpvmdj39to:35: NumbaWarning:\n", + "/var/folders/qv/63yqp4p50630y7pqfgcbgtq80000gn/T/tmpqfkmwgyd:35: NumbaWarning:\n", "\n", "\u001b[1m\u001b[1mCannot cache compiled function \"scan\" as it uses dynamic globals (such as ctypes pointers and large global arrays)\u001b[0m\u001b[0m\n", "\n" @@ -4293,78 +6140,78 @@ " kalman_filter_pytensor\n", " kalman_filter_inputs\n", " 10\n", - " 6024.866599\n", - " 6579.845800\n", - " 6250.349981\n", - " 153.071106\n", - " 6202.177100\n", - " 232.759375\n", - " 0.159991\n", + " 6104.970801\n", + " 7071.941700\n", + " 6387.756000\n", + " 279.653919\n", + " 6270.281300\n", + " 186.478025\n", + " 0.156549\n", " 16\n", " \n", " \n", " atrocious_kalman_filter_numba\n", " kalman_filter_inputs\n", " 10\n", - " 321.066599\n", - " 339.383300\n", - " 326.688300\n", - " 6.500478\n", - " 324.787499\n", - " 1.745901\n", - " 3.061022\n", + " 302.166599\n", + " 340.183299\n", + " 319.794140\n", + " 14.582074\n", + " 319.112500\n", + " 25.849900\n", + " 3.127012\n", " 5\n", " \n", " \n", " kalman_filter_numba\n", " kalman_filter_inputs\n", " 10\n", - " 661.045800\n", - " 699.420800\n", - " 679.645000\n", - " 15.146345\n", - " 678.958399\n", - " 28.616600\n", - " 1.471356\n", + " 691.604200\n", + " 745.750000\n", + " 728.874160\n", + " 19.424866\n", + " 734.995800\n", + " 12.120800\n", + " 1.371979\n", " 5\n", " \n", " \n", " kalman_filter_jax\n", " kalman_filter_inputs\n", " 10\n", - " 311.850000\n", - " 404.729199\n", - " 349.466676\n", - " 30.904895\n", - " 345.983301\n", - " 53.454102\n", - " 2.861503\n", + " 316.787499\n", + " 382.941699\n", + " 347.827706\n", + " 18.909034\n", + " 346.441701\n", + " 24.083399\n", + " 2.874987\n", " 17\n", " \n", " \n", " kalman_filter_pytensor_numba\n", " kalman_filter_inputs\n", " 10\n", - " 849.591600\n", - " 914.716700\n", - " 886.171660\n", - " 22.541980\n", - " 890.616700\n", - " 26.891699\n", - " 1.128450\n", + " 923.187500\n", + " 961.175001\n", + " 948.837500\n", + " 13.490555\n", + " 950.737500\n", + " 7.887499\n", + " 1.053921\n", " 5\n", " \n", " \n", " kalman_filter_pytensor_jax\n", " kalman_filter_inputs\n", " 10\n", - " 338.316600\n", - " 393.687500\n", - " 360.706558\n", - " 15.525106\n", - " 359.574999\n", - " 25.831250\n", - " 2.772337\n", + " 328.675000\n", + " 399.116700\n", + " 371.450205\n", + " 18.218075\n", + " 374.479100\n", + " 19.102100\n", + " 2.692151\n", " 19\n", " \n", " \n", @@ -4373,36 +6220,36 @@ ], "text/plain": [ " Loops Min (us) \\\n", - "kalman_filter_pytensor kalman_filter_inputs 10 6024.866599 \n", - "atrocious_kalman_filter_numba kalman_filter_inputs 10 321.066599 \n", - "kalman_filter_numba kalman_filter_inputs 10 661.045800 \n", - "kalman_filter_jax kalman_filter_inputs 10 311.850000 \n", - "kalman_filter_pytensor_numba kalman_filter_inputs 10 849.591600 \n", - "kalman_filter_pytensor_jax kalman_filter_inputs 10 338.316600 \n", + "kalman_filter_pytensor kalman_filter_inputs 10 6104.970801 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 10 302.166599 \n", + "kalman_filter_numba kalman_filter_inputs 10 691.604200 \n", + "kalman_filter_jax kalman_filter_inputs 10 316.787499 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 10 923.187500 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 10 328.675000 \n", "\n", " Max (us) Mean (us) \\\n", - "kalman_filter_pytensor kalman_filter_inputs 6579.845800 6250.349981 \n", - "atrocious_kalman_filter_numba kalman_filter_inputs 339.383300 326.688300 \n", - "kalman_filter_numba kalman_filter_inputs 699.420800 679.645000 \n", - "kalman_filter_jax kalman_filter_inputs 404.729199 349.466676 \n", - "kalman_filter_pytensor_numba kalman_filter_inputs 914.716700 886.171660 \n", - "kalman_filter_pytensor_jax kalman_filter_inputs 393.687500 360.706558 \n", + "kalman_filter_pytensor kalman_filter_inputs 7071.941700 6387.756000 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 340.183299 319.794140 \n", + "kalman_filter_numba kalman_filter_inputs 745.750000 728.874160 \n", + "kalman_filter_jax kalman_filter_inputs 382.941699 347.827706 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 961.175001 948.837500 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 399.116700 371.450205 \n", "\n", " StdDev (us) Median (us) \\\n", - "kalman_filter_pytensor kalman_filter_inputs 153.071106 6202.177100 \n", - "atrocious_kalman_filter_numba kalman_filter_inputs 6.500478 324.787499 \n", - "kalman_filter_numba kalman_filter_inputs 15.146345 678.958399 \n", - "kalman_filter_jax kalman_filter_inputs 30.904895 345.983301 \n", - "kalman_filter_pytensor_numba kalman_filter_inputs 22.541980 890.616700 \n", - "kalman_filter_pytensor_jax kalman_filter_inputs 15.525106 359.574999 \n", + "kalman_filter_pytensor kalman_filter_inputs 279.653919 6270.281300 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 14.582074 319.112500 \n", + "kalman_filter_numba kalman_filter_inputs 19.424866 734.995800 \n", + "kalman_filter_jax kalman_filter_inputs 18.909034 346.441701 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 13.490555 950.737500 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 18.218075 374.479100 \n", "\n", " IQR (us) OPS (Kops/s) \\\n", - "kalman_filter_pytensor kalman_filter_inputs 232.759375 0.159991 \n", - "atrocious_kalman_filter_numba kalman_filter_inputs 1.745901 3.061022 \n", - "kalman_filter_numba kalman_filter_inputs 28.616600 1.471356 \n", - "kalman_filter_jax kalman_filter_inputs 53.454102 2.861503 \n", - "kalman_filter_pytensor_numba kalman_filter_inputs 26.891699 1.128450 \n", - "kalman_filter_pytensor_jax kalman_filter_inputs 25.831250 2.772337 \n", + "kalman_filter_pytensor kalman_filter_inputs 186.478025 0.156549 \n", + "atrocious_kalman_filter_numba kalman_filter_inputs 25.849900 3.127012 \n", + "kalman_filter_numba kalman_filter_inputs 12.120800 1.371979 \n", + "kalman_filter_jax kalman_filter_inputs 24.083399 2.874987 \n", + "kalman_filter_pytensor_numba kalman_filter_inputs 7.887499 1.053921 \n", + "kalman_filter_pytensor_jax kalman_filter_inputs 19.102100 2.692151 \n", "\n", " Samples \n", "kalman_filter_pytensor kalman_filter_inputs 16 \n", @@ -4413,7 +6260,7 @@ "kalman_filter_pytensor_jax kalman_filter_inputs 19 " ] }, - "execution_count": 42, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -4429,7 +6276,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 44, "id": "37526f86", "metadata": {}, "outputs": [], @@ -4439,7 +6286,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 45, "id": "231140ba", "metadata": {}, "outputs": [], @@ -4468,7 +6315,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 46, "id": "ff739003", "metadata": {}, "outputs": [], @@ -4478,17 +6325,17 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 47, "id": "7546c95c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "np.float64(0.916)" + "np.float64(0.906)" ] }, - "execution_count": 46, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -4499,891 +6346,39 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 48, "id": "6b765a37", "metadata": {}, "outputs": [ { "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "marker": { - "color": "royalblue" - }, - "mode": "markers", - "name": "actuals", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", - "dtype": "i2" - }, - "y": { - "bdata": "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", - "dtype": "f4" - } - }, - { - "marker": { - "color": "orange" - }, - "mode": "lines", - "name": "filtered mean", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", - "dtype": "i2" - }, - "y": { - "bdata": "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", - "dtype": "f4" - } - }, - { - "legendgroup": "95% CI", - "line": { - "width": 0 - }, - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", - "dtype": "i2" - }, - "y": { - "bdata": "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", - "dtype": "f8" - } - }, - { - "fill": "tonexty", - "fillcolor": "rgba(235, 140, 52, 0.2)", - "legendgroup": "95% CI", - "line": { - "width": 0 - }, - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "95% CI", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAQ==", - "dtype": "i2" - }, - "y": { - "bdata": "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", - "dtype": "f8" - } - } - ], - "layout": { - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#f2f5fa" - }, - "error_y": { - "color": "#f2f5fa" - }, - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "baxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#506784" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "header": { - "fill": { - "color": "#2a3f5f" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#f2f5fa", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#f2f5fa" - }, - "geo": { - "bgcolor": "rgb(17,17,17)", - "lakecolor": "rgb(17,17,17)", - "landcolor": "rgb(17,17,17)", - "showlakes": true, - "showland": true, - "subunitcolor": "#506784" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "dark" - }, - "paper_bgcolor": "rgb(17,17,17)", - "plot_bgcolor": "rgb(17,17,17)", - "polar": { - "angularaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "radialaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "yaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "zaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - } - }, - "shapedefaults": { - "line": { - "color": "#f2f5fa" - } - }, - "sliderdefaults": { - "bgcolor": "#C8D4E3", - "bordercolor": "rgb(17,17,17)", - "borderwidth": 1, - "tickwidth": 0 - }, - "ternary": { - "aaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "baxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "caxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "updatemenudefaults": { - "bgcolor": "#506784", - "borderwidth": 0 - }, - "xaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - } - } - }, - "xaxis": { - "title": { - "text": "Time Index" - } - }, - "yaxis": { - "title": { - "text": "y" - } - } - } - } + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" @@ -5451,7 +6446,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 49, "id": "6b088d6b", "metadata": {}, "outputs": [], @@ -5540,7 +6535,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 50, "id": "a468c403", "metadata": {}, "outputs": [], @@ -5629,7 +6624,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 51, "id": "15fd4a0c", "metadata": {}, "outputs": [], @@ -5647,7 +6642,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 52, "id": "59525da5", "metadata": {}, "outputs": [], @@ -5724,7 +6719,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 53, "id": "c033a1d0", "metadata": {}, "outputs": [], @@ -5751,7 +6746,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 54, "id": "2a9cbfa5", "metadata": {}, "outputs": [], @@ -5765,7 +6760,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 55, "id": "c782c42b", "metadata": {}, "outputs": [ @@ -5807,52 +6802,52 @@ " particle_filter_1d_predict_pytensor\n", " kalman_filter_inputs\n", " 5\n", - " 776326.149999\n", - " 792344.283199\n", - " 782741.538279\n", - " 6040.856511\n", - " 779343.408198\n", - " 8662.600000\n", - " 0.001278\n", + " 780078.116598\n", + " 786185.175000\n", + " 783728.621639\n", + " 2360.191223\n", + " 784531.191600\n", + " 3942.325001\n", + " 0.001276\n", " 5\n", " \n", " \n", " particle_filter_1d_predict_numba\n", " kalman_filter_inputs\n", " 5\n", - " 51164.908399\n", - " 51900.633200\n", - " 51432.376601\n", - " 264.829443\n", - " 51439.416601\n", - " 276.491602\n", - " 0.019443\n", + " 51350.575002\n", + " 52499.300000\n", + " 52027.498361\n", + " 379.059845\n", + " 52042.658400\n", + " 196.658398\n", + " 0.019221\n", " 5\n", " \n", " \n", " particle_filter_1d_predict_jax\n", " kalman_filter_inputs\n", " 5\n", - " 17.358401\n", - " 33723.750000\n", - " 7730.253572\n", - " 12709.927696\n", - " 19.724999\n", - " 10139.645799\n", - " 0.129362\n", + " 14.141598\n", + " 33671.425001\n", + " 7729.845257\n", + " 12705.393838\n", + " 15.683199\n", + " 10173.683301\n", + " 0.129369\n", " 7\n", " \n", " \n", " particle_filter_1d_predict_pytensor_numba\n", " kalman_filter_inputs\n", " 5\n", - " 724575.624999\n", - " 739611.624999\n", - " 731249.660000\n", - " 5239.730301\n", - " 731423.700001\n", - " 6487.666798\n", - " 0.001368\n", + " 726314.616800\n", + " 737619.216798\n", + " 733283.193361\n", + " 3765.904024\n", + " 734320.525001\n", + " 1548.925001\n", + " 0.001364\n", " 5\n", " \n", " \n", @@ -5867,46 +6862,46 @@ "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 5 \n", "\n", " Min (us) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 776326.149999 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 51164.908399 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 17.358401 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 724575.624999 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 780078.116598 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 51350.575002 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 14.141598 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 726314.616800 \n", "\n", " Max (us) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 792344.283199 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 51900.633200 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 33723.750000 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 739611.624999 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 786185.175000 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 52499.300000 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 33671.425001 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 737619.216798 \n", "\n", " Mean (us) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 782741.538279 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 51432.376601 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 7730.253572 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 731249.660000 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 783728.621639 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 52027.498361 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 7729.845257 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 733283.193361 \n", "\n", " StdDev (us) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 6040.856511 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 264.829443 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 12709.927696 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 5239.730301 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 2360.191223 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 379.059845 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 12705.393838 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 3765.904024 \n", "\n", " Median (us) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 779343.408198 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 51439.416601 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 19.724999 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 731423.700001 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 784531.191600 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 52042.658400 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 15.683199 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 734320.525001 \n", "\n", " IQR (us) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 8662.600000 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 276.491602 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 10139.645799 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 6487.666798 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 3942.325001 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 196.658398 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 10173.683301 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 1548.925001 \n", "\n", " OPS (Kops/s) \\\n", - "particle_filter_1d_predict_pytensor kalman_filter_inputs 0.001278 \n", - "particle_filter_1d_predict_numba kalman_filter_inputs 0.019443 \n", - "particle_filter_1d_predict_jax kalman_filter_inputs 0.129362 \n", - "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 0.001368 \n", + "particle_filter_1d_predict_pytensor kalman_filter_inputs 0.001276 \n", + "particle_filter_1d_predict_numba kalman_filter_inputs 0.019221 \n", + "particle_filter_1d_predict_jax kalman_filter_inputs 0.129369 \n", + "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 0.001364 \n", "\n", " Samples \n", "particle_filter_1d_predict_pytensor kalman_filter_inputs 5 \n", @@ -5915,7 +6910,7 @@ "particle_filter_1d_predict_pytensor_numba kalman_filter_inputs 5 " ] }, - "execution_count": 54, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -5939,7 +6934,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 56, "id": "2bd23897", "metadata": {}, "outputs": [], @@ -5951,1055 +6946,39 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 57, "id": "7caac5a5", "metadata": {}, "outputs": [ { "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "legend": "legend", - "marker": { - "color": "cornflowerblue" - }, - "mode": "markers", - "name": "actuals", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x", - "y": { - "bdata": "AADAQQAAcEEAAIhBAACgQAAAMEEAAMBAAADgQAAAEEEAAIA/AAAAQAAAoEAAAKBAAABAQAAAgD8AAKBAAACAQAAAQEAAAIA/AACAPwAAAEAAAABAAAAAQAAAQEAAAABAAACAQAAAAEAAAAAAAACAPwAAAEAAAIA/AACAQAAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAIA/AACAPwAAQEAAAEBAAAAAAAAAAAAAAIA/AACAPwAAoEAAAAAAAACAPwAAAEAAAAAAAAAAAAAAgD8AAIA/AAAAQAAAgD8AAABAAACAPwAAAAAAAABAAACgQAAAoEAAAABAAAAAQAAAoEAAAMBAAAAAQAAAAAAAAAAAAAAAQAAAgD8AAKBAAABAQAAAgD8AAIA/AACAPwAAAEAAAABAAABAQAAAgEAAAABAAACAPwAAQEAAAAAAAACAPwAAgD8AAIA/AABAQAAAgD8AAABAAACAPwAAgD8AAABAAACAPwAAQEAAAABAAAAAAAAAgEAAAIBAAAAAQAAAQEAAAIA/AAAAQAAAAAAAAIA/AACAPwAAAEAAAAAAAACAPwAAgD8AAABAAAAAQAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAQAAAAAAAAIA/AACAQAAAAAAAAIA/AAAAQAAAQEAAAABAAACAQAAAAEAAAAAAAACAPwAAAAAAAAAAAAAAAAAAQEAAAEBAAACAPwAAgD8AAIA/AAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAABAQAAAgEAAAABAAAAAAAAAAEAAAIA/AACAPwAAQEAAAABAAAAAQAAAgEAAAAAAAAAAQAAAgD8AAIA/AAAAAAAAAAAAAABAAACAPwAAgD8AAEBAAACAQAAAAEAAAIA/AACAQAAAgD8AAIA/AAAAAAAAgD8AAIA/AABAQAAAgEAAAAAAAAAAQAAAgD8AAEBAAABAQAAAgD8AAIBAAACAPwAAgD8AAMBAAACAPwAAgD8AAKBAAACAPwAAAEAAAMBAAACAPwAAgEAAAAAAAABAQAAAgD8AAEBAAADAQAAAwEAAAKBAAAAAQAAAAEAAAABAAABAQAAAgD8AAABAAACAPwAAgD8AAEBAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAgD8AAAAAAACgQAAAAAAAAIBAAACAPwAAAEAAAIA/AAAAQAAAgD8AAMBAAABAQAAAgEAAAABAAABAQAAAgD8AAABAAACAPwAAAEAAAIA/AAAAQAAAAEAAAAAAAACAPwAAAAAAAAAAAABAQAAAgD8AAIA/AAAAQAAAAAAAAIA/AAAAAAAAAEAAAABAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAAAAQAAAAEAAAIA/AACAPwAAAAAAAABAAACAQAAAAEAAAIBAAABAQAAAgD8AAIA/AABAQAAAAAAAAAAAAACAPwAAQEAAAAAAAAAAAAAAgD8AAAAAAAAAQAAAgEAAAIA/AACAPwAAAEAAAABAAACAPwAAAEAAAAAAAABAQAAAAEAAAIA/AABAQAAAAAAAAAAA", - "dtype": "f4" - }, - "yaxis": "y" - }, - { - "legend": "legend", - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "predicted mean", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x", - "y": { - "bdata": "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", - "dtype": "f8" - }, - "yaxis": "y" - }, - { - "legend": "legend", - "legendgroup": "predicted mean 95% CI", - "line": { - "width": 0 - }, - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x", - "y": { - "bdata": "AzL/QW7XxUEGcL1BqF1+Qds7gEFCIlJB4HBDQSyrTUE0/A5B3V7qQORg+0BWIgNBjo/sQF+svkC/rN1Au4ngQBZ41EAQ0rFApVmcQLdJmUAcWZdAkBqWQFz1oUDwbZ1AS5+1QEA5q0Am14pAYpuBQLTWhUBQW3lAxDqcQLSHgECGvF1AyOlDQEC4LkBN4jBA1A41QHs0OUBpETtA6P8qQECRHUClvCRAAOUrQO49XECKIIRAtCVgQExJRUCUeEZAakBHQML1kEBAX3VANWNqQOBteEAcqVZAgvE8QH8wP0BiMEBAzPdWQGOOUUC5SGRAXPtcQNhSP0DuPlVAS4CdQBoEyECnDbVAXompQB3pzED16fJA+gTRQGcUpEAES4hAEx2LQKgqgkCiGq1AomyzQP68m0C6SItA16GAQHBhhEB8aodAj0mVQEjcrUAzi6VABcCUQHhCoUB+/oNAb3t4QMTGakCmV2JAaXiEQHvteEBqBYFAIbx0QKAeaUDzaHlA1C1sQCHPiECcvotAUixsQD0ml0AP2rFASBqnQO63rUC6pJlAmuCWQBB9ekBEV2xARB9lQNzUdUCKuFFAkLRPQDeHTEDS7GBARsRyQLJXUUDOcUxAphFKQOl5SUDXP0lAmmRdQDwfQUCslEJAtU2BQK3XXUAu91hA2FlrQOBfiUBu8olAJuemQC6In0ADDINA4sB1QOaPVEDBmj1ARpcsQMW8WkC0MIRAGld6QI5Hb0CojWRAeOFzQJaegUCJ4YZAzTKLQIlVjUCSWI5A1uOdQOIat0CCaa1A9EOLQCB+jUD77oJA8n92QKGSjEDC2I1AnHSPQI6xq0DxNIpATLWLQFf3gUAm5HVAdjBUQAyYOkCtPVFAmG9PQM4+S0CTGnhA7OCbQFewl0AQB4hAqDykQP6fkUBR44VASA5iQIYcW0D+kVZAUxOBQGJ1n0Dkx4JAFdiGQBKae0C4ipBAf/CeQEBwj0AAJatADDCVQKGRh0DoP79AuuaiQIx3kUAJtrdA5hieQJb6mkCa+s9APKOtQK7XwUB4uZdAmGGiQI7CkEAShp5AwG7UQChL/kA4GgRBoNfdQMvpxUDs1bRA7nS3QPT3oEDigJxAkmSMQPSJgUArKJJA4VF2QIGBVEDmCDxAiOMpQBalQUA2z1pAlu0/QFa5QEDUDSxAApGGQLpvZkDSTpJAbnuFQHNViEAUxHtAY7CDQEK1d0AqybVAhI22QGN6x0DoobVAvVu5QPpfn0Ba0ptAZM2MQK5YjkCFWINARW+GQN3NiUB+EmhA3MtdQHjgQ0DwODBAKs5gQFAJWUDq8VNAZhhpQMLxS0BH5EpA3Bc1QPQtTEBYpGBAoBhFQBRjMEALoTRArF8kQHJ3KkAE3xpAE8YhQL94EkCMhwhAslklQFwLQkByf0BAVlZCQKOeLUBSjEZABAmIQEfCikBzwapApj6yQNaNmkAbcIxAKsGcQABafkAb1FpAIsJVQDpTgEB0VFpAedY+QEtEP0AN4CxAec9FQNHnhEBl+HdAXNpsQEynfEBpaoNAq3x2QFlOgUAeY1xAjd6CQLOehkAef3lAXmaQQP7ncEAECVFA", - "dtype": "f4" - }, - "yaxis": "y" - }, - { - "fill": "tonexty", - "fillcolor": "rgba(235, 140, 52, 0.2)", - "legend": "legend", - "legendgroup": "predicted mean 95% CI", - "line": { - "width": 0 - }, - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "predicted mean 95% CI", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x", - "y": { - "bdata": "pkxPQSALB0EL3flAsh9dQNJyYUCYHgZAPEfWP7Cd+z+QwKc+gLVdvgCXQ72AKYc9gBtIvvDTF7+QdKu+IBievign1b6wiC+/aIVRv7C9Vb/MU1i/SPNZv7heSb+c/k+/uMQov3zCOr+MTme/AFlwv5RtbL8SanS/xLBRv2RIcb+ou3y/zvB/v9/Kfr+BFH+/pYV/vzXRf79w53+/6jN+v0IHe79M7ny/Elt+v5ILfb9WD26/wDJ8v1bkf7+m1n+/Jsx/v3xaYL+Q5nW/PIJ5v8DEdL8KFH6/mvZ/v1j/f7/2/3+/4gZ+v+zVfr88MXu/euR8v4r/f79uTn6/eORPv+QrBb9Yyym/zIU9v8Dk9b4AVwi+aETkvvglRr/Y+mm/KgNnvwDab7+0oDe/qLQsv6xgUr/o02a/+DFxv3jSbb+E3mq/7v9avzxaNr+o4UO/+q5bvzRqSr8gL26/nL90v75keb+mrXu/2rxtvyyUdL8M3HC/NCF2v7bgeb/UZHS/avh4v/Zyab+KU2a/3vh4v6KWWL+wei+/6G1Bv7CXNr90QlW/0vFYv7b5c7+263i/ovl6v+a7db9m0H6/oBB/v8Rmf7+CBHy/cNJ2vwLdfr/IaH+/jpx/v9Snf7/0q3+/Ws58v8D+f79g+X+/IJ1wv9S1fL9grX2/wDh5v37caL9qQmi/5L5Bv3j2TL+yDm+/KsN1v2Bpfr88+n+/Snh+vyxYfb80AG6/iAh0v/L9d79+H3u/2G52vy5WcL9eZ2u/qOtmvw6QZL/4aWO/RFZPv5QSJr8AHDe/FNlmv1JiZL8gKW+/Rn11v+ppZb+6+2O/lCFiv2z7Ob/w+2e/tl1mv7AHcL9WtnW/uHd+v3bif79c4H6/phh/vz6Ef79E5HS/iC5Sv8DgV78sQGq/FOhFv8yNX79OYWy/eL97v35Ffb/eF36/9s9wv+QRTb+cTG+/vnBrv1aJc78a2mC/KNNNv6wmYr/o4zq/giBbvx63ar/stRa/gPJHv56+X78o9iS/MApPv3BuU78Yxei+pLo2vwChEb+y1Fe/3LtIv6aXYL8YbU6/cFDVvoAukbzAfrE9wK2qvmh4Cb+ELyq/rG0lvwDZSr88TlG/+Jxlv1RocL966F6/NI51v4xrfr8o8H+/xQB+v079f7+YVH2///9/v3r/f7/dYX6/HrdrvyCger9OuV6/6sVsvyjwab+eeHO/sHduv14Kdb/8eCi/iBQnv9BGBr/8vyi/WOohvxwxTb/gQlK/jihlv9hpY7+yyG6/YNhrvwZpaL/OLHq/Xrh8vxbxf78X/36/sAt8vxKqfb/6gH6/fuJ5v5B0f7/Ui3+/cIZ/vxhvf792FXy/SOZ/v4IEf7/Ae3+/mth8v7gbfr9jL3q/GDR8v2sXd79SeHK/PBJ9v9b7f7/A/3+/kPp/v3ehfr+o1X+/MD5qv/pkZ7/Yhzu/KMouvzQEVL8ykGW/mPNQvw5scr+kU32/rjl+vzR1cb9AbH2/pf5/v3f/f7/og36/nN5/v1JTbb8k8XS/QMN4v4gdc79AuG6/fH51v5CccL/6A32/EDhvv5ipa79KXHS/OgVhv5B0d78S536/", - "dtype": "f4" - }, - "yaxis": "y" - }, - { - "legend": "legend2", - "marker": { - "color": "cornflowerblue" - }, - "mode": "lines", - "name": "true latent state", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x2", - "y": { - "bdata": "WDwTFtasCUCRf+noCkwHQIhGXEn3LwVAsIFPu2c1AkBLnl1BpdgCQIS6z7/ckvs/LtI5jP03AECQaI3umBf8P1J9miw51Ps/dqz4j52L+T931SMQxX/9P0CP/NlPp/Q/OZJhgqV38j+4T3nmgivwP2NqgKDyavM/h2zpyggG7T/szWpPrlbqPxlaE1B/veI/824f9PIa4j/+z2d7y17lP8gJwYdP2tg/WvZUyfz+4z9AJ/Zkj3LpP45wZG9Lxes/tShAxgBq8D8oFWWtXEvqP2ZXUmqvGeg/54pjHhIz4D+82Cy5AfLaPy6ztCcNmOA/U70j8lih1T8UtZt1473NP4R5FE1bLLE/ZClbUq0IwL94ZMyd4TjRv2aBrr7VitC/D8F4LHG03792Dn4e0sPav8D/6I/Axpq/0qPXshAPwj8UUaHwm1S3P3TAohyZpby/I0uJw/9+0b+gjvFciGW+P5NDigMCyb8/ME2lQkISmb9cIDrelOWTP/r3ePzePN8/9+XNGT1l3z97rvveRVTjP7bKbhS1guQ/VkAr4uz24D8IcNmBt8PPP7UA8v9xLcQ/fzFo+iVhuj9iSTEoBVLNP5xZ/oUJ79k/hEWLjR/74j9psoddTRPkP9fppiG6Z+k/fg+8+6S84j8IzTO5zMPqP7nfja/JGO0/LsM/T06C6T/0YjrYprrrP8T7T7JJzek/c2+cs/ZN8D/RBvR4Qe30P8Lwl6sls/s/VqS9RoxR9T88kB9KCCzuP6OaP77BDek/FfO3Bzny6D+bxdDK3fftPzjvn/Jyuu4/+vjEEMVx3T+KfQiPFJfXP+7ULXo8IeE/GqWCfXXr4T/IsByX7XnmP7gX7lH5wuM/gIl/ekdW4T99Y1IgG87hPy/e4PBT2eM/OGqMG4FG5D9lXyZD+hzkP6NxB2IJntw/N1t82ntL4D+CBYdqD1rgP74/ISS7nec/+xTpRJsD7z/ruSwVy8nuP+hSsfZCkOo/wNDnAjuq5D88GpxreKnmP/T/00ARFeY/ZZWMIIyE4j+kjMFRYefhP2b6w+IAJdk/cvJf+jjw4D+O2KQBvMjZP1cEstBiAuU/wcwy0JPY5j+MubM3dfPpP/6pmsuj0eA/4JHhXqEw4T8Y1WTzI6HlP2dWVUOdcts/oCPn8vhD1j9/JWmqdZ7VP4AUvJ4KZ4w/28MZ+t9ptT/SA8zQ6jHRP8QQPnCvI7A/ehoVeQ2zwT9YLIpPy77Evw7r5DzI0MS/5VH4HFaB4L9MSA44fJ/OvwgBj7dvY8G/F2WflDw5wb9l/IjKP0bTvwBCaRm0CVW/LeEz6aIS3D8AU8GHb3NUP62EAd00xNE/c5njSugV5D9RAPk3+n/lPzZA/D7zr9c/TkSgSddt4T+ZB7bWrobePyY3HehwW9Q/8NyvPF3Hmz+eYwEOWA7DP9YVcUa4ZdQ/vIQD5pDoxD/4rut/o2HRP4CJQXyJY2E/IfQmfW41xz+TAIzDkGHHPzyKhlFD38A/uuQb6ZU7uj/vaQIcLqrSP2Bdo6J1eNw/iPbMyuJP4T8ewOnnh27hP+IKWcD0HeE/dOlqX5mv5D9YibMbs1DlP+H1qkMnIuk/PSX5u2Co5T94HgPRcDi5P0R8ZBk329Q/n/tFNzWO6T9Yx81ElW/rPwDlxt3wWOk/SuuoX44a5z8uNa0WvxjlP7QHI3WZKuQ/nq6KLldC1j/Zz5wIBX7LP4ggg7TzWZO/woJOUtNKoz+SLrLhf0Sfv+ZxEnzn67Q/AFMcLOq/oz/0uV3P5nXQP+oh9POAsdI/t9DWYQKO6D99Ay+k9YPTPxz4Q+NEkMI/jrZu1v231T9n7K+QWWjsP4J5elRJNek/lpQcSp1C6D/7n+ozhm3lP2TjLpYx4u0/RmxDsWVV6j+EyQgFEuLtP5r1sSzCGeo/5q4Vbzph3z8fnYvSIibhP5lF+Udb5OM/k3njJ6cm7D8opnlAAfTpP+WeN83tPOQ/f79Jqb1A5z9ihfc2FdDnPxyytbdloeg/1vTtWDPg5j892qIu4gjuP6jLVnFFLe8/3fJGepGf9T/qBlk/ZoT4P/NY8eUypvk/Is+JKlSL8j8HyrRjn8XzP5wEp6Z5SfQ/5mJs+Iss9j+sprAsUc34P+leyoSwIPY/0J1kCSj49z/gtAYzVsL0P1qx0HMUt/o/dhWxOTOd9D9M2ydWeZHqP8mziOtC29o/WyK4tsOJyT+EIiyBMBSvv46njR5xTdg/2izY+zZq0j/Ag+XlzYebv9lcX11SoMw/wOJGZ7fQtD9ndOKFd4PJv6DVZoQ9kHo/ANiDSVmhwj/AjBjljv+kP6CD6GL5otY/Olqv2DJa1z8gPp8pjanmPxGmBVRjIOk/6DfuhRWD8T+RCrCOIQfxPxL2TIoJoOc/fnnZqi388z+sbdKcfwjxP9Gt5PG38O4/NiLhqbNh6D9FwYmbCrXlP0q3sEO1W+Y/ruZ6hzuv5j+O/MMduEfqPz5lBrMX5fI/FWx+veeE8T8AY/JrgXboP5McCDlAj90/cQD499iN0j8kpC0hvVS5vwifrYm6Kbc/2AAIyecOmr8KqLcNm/23v1t13WU+5ra/DQsupOds2b8pJlJSej3iv2A7/QMnANm/kEPrfinMzb+SD6dV+H7Uvzj9W2+gwbk/sWek+Ecjyb+u2t0GpeDQvy2VxJJPVtO/nrCJ77sr7b8kZh5DarLbv9ruRFrPEdW/FgfJXYZ74b+gc8Xk+eauvwrGEwfA2LI/Ms0rLPU+xT9wMrxAi3uWP8pOmSUf16Y/AdoawRgf078gkvMI0ia7v1CMpFs0nce/jESr3cCYwr9HQWLp6rzAP4uikisQDcg/1flGA1lczj8YtzE812DSP7BAVAHR3Ls/AFviEc+U0j8ahFrVlt7jP+cbuOA6Tug/BJ/0NRVs7T/So9llfKzlP8Tdhrbrwtw/nO1ZjxPQuj9omtkNqwDYPylGEWM6KtM/Rb6tkqwe4z8nFX8oSiPZP2jcRcOtntE/4nIQ3r0a0j/2lmgNzmLeP8uJx25tvN0/yEJ490ZF3z83K2o1kPHdP5pPRels+94/2F8F8yrpyj8alNOXrOHLP5Xm2duyJcU/LD0+Aqd2wj8eQ4UKvqHPP3BSUCTaIrU/hcsa0c57rj94zHZwj1aEv928LNn8eLU/vENZiZlU0D+Y+c8ByHSdP6xb0RuFRMQ/", - "dtype": "f8" - }, - "yaxis": "y2" - }, - { - "legend": "legend2", - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "filtered state mean", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x2", - "y": { - "bdata": "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", - "dtype": "f8" - }, - "yaxis": "y2" - }, - { - "legend": "legend2", - "legendgroup": "filtered state mean 95% CI", - "line": { - "width": 0 - }, - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "", - "showlegend": false, - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x2", - "y": { - "bdata": "W3JhQB28SkCnNUdAp4kqQMuqLEAQbx5Ak3YZQKmoHUC5PgNAKAjpP+aV8j+U8Pk/fAzqPy0oyj87b+E/4l7iPyCl2T8Jr70/KlirPy6XqD9K5aQ/ulKjP/l6sD8qqqs/DZHDPzZmuT90xZs/Ay2SP2/WlD9mnIc//pStP5baij+uoWc/PKJCP/uyHD9JtyA/diklP3+ELD9GPy8/uiwPP8g72j5g6wM/ItoVP1z/az+UIZU/y2JsPyioPj/BID8/O6dBP6Jlnz/KpYU/6+p8P9j4hj8iS2Q/Lzs6P1uJOj+9yTs/w9ZgPzHwXz9Y+Hc/upVrPyjYOz9+5V4/9LO1P8gz1j9hmMM/9pO4P6Ku1D+F7e4/E0/WP6qErT9Lyo4/CACXP1Fbjj9JUrw/Nu3BP3CsrT9JfJs/DaCMP/a1kT/hcJU/lJ6kPxilvD8nzrI/Hs+hP0rvrz+mGI8/XI+IP1Scej8sP24/k1WPPzaXhT8aMY0/8YaHP6Xnez+pDog/FFCBP4vMlz8DqJo/yreBP7xvpz9jR8A/yfi0PxITuz8mDqg/Xe6kP/gtiD8oSXk/9rpyP9Knhj8Qs1o/xKtWP0xNTj9HhHA/PKSGPxtUVD+9T0w/XcJJPz4qSj9rN0s/D81rP3XROj8NZjs/J++LP0Sfaj/dPGQ/fJuAP3/zmD83aJg/tES2Pyb4rT9Uf48/FB6CP6TsVz8SDTI/pqAVP3bYZj+/mJM/0/qJPyuugz9tB3c/c2GGPzGKkT8vDJc/y2mbP2ETnz/4pJ8/oriwP+RTxz+T7bw/qDOZP+ZcnD/wRI8/aYGFP99DnD+89Jw/HYyeP0ISvD9C2ZU/L7GYP+d9jD80E4Q/IKRXP6KaMD83llY/ytxPP2jGSD+nKYo/r2WvP8TeqT9mMZY/0AO1P3SioD9kypM/UGZrP7aqZD8T22E/GKiOP8MPrz9rkJE/qDaUP2lXiz8qaKE/FGuvP4jGnz/CTrs/HjOkP8RrlD8Dg80/cXiyP4CWnj9GDcY/fC2tP3Rtqj9Undc/eYS5P9pizj/sd6Y/3m2xP/itnj8joK4/zEbdP5DZ9z+AlP0/wtzfP+H0zD/++78/+0nCP6LTsD+nKaw/oi+ZPz6NjT9kaaI/NmuHP3xSZD9pYDo/LlYSP1JDQD/nRms/0DM8P7HyQD/LHhw/inuUPySYeT/E+qE/IeiRP7LIlT/c6Ik/5q2SP6S9hz9uuMU/lfLEPwqk0j80VsM/+ejGP5rMrT+e26k/VuOZP3Q0nD/0gJA/roWTPxqulj/wFHU/2ixoP+paQz8d2CA/LldyP7LIaD8bZF0/8o5/P9dCTD9sxks/meYgPwM4Tj9T8HE/7k1GP2k7IT+bBSk/tDENP4brFz/VDfA+FLgJP25Pzj7G+5U+mhsQPwnASz8fGkE/BstBPwQNGD86b0Y/LdOdP9wtoD9s2L8/glvEP84lrD8+Wp0/KuetPzjEjj9J0GY/U/djP+yDjz9LCmk/pEA8P4iyPT8i1hg/jdpHP5rBlD+2Uoo/bdeAP9WejD9pLJI/76OGP+E9jj8MqWc/IL6QPx8XlD+kcoc/2OKiP0CFgj/2OVs/", - "dtype": "f4" - }, - "yaxis": "y2" - }, - { - "fill": "tonexty", - "fillcolor": "rgba(235, 140, 52, 0.2)", - "legend": "legend2", - "legendgroup": "filtered state mean 95% CI", - "line": { - "width": 0 - }, - "marker": { - "color": "#eb8c34" - }, - "mode": "lines", - "name": "filtered state mean 95% CI", - "type": "scatter", - "x": { - "bdata": "AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgBzAHQAdQB2AHcAeAB5AHoAewB8AH0AfgB/AIAAgQCCAIMAhACFAIYAhwCIAIkAigCLAIwAjQCOAI8AkACRAJIAkwCUAJUAlgCXAJgAmQCaAJsAnACdAJ4AnwCgAKEAogCjAKQApQCmAKcAqACpAKoAqwCsAK0ArgCvALAAsQCyALMAtAC1ALYAtwC4ALkAugC7ALwAvQC+AL8AwADBAMIAwwDEAMUAxgDHAMgAyQDKAMsAzADNAM4AzwDQANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkA6gDrAOwA7QDuAO8A8ADxAPIA8wD0APUA9gD3APgA+QD6APsA/AD9AP4A/wAAAQEBAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsB", - "dtype": "i2" - }, - "xaxis": "x2", - "y": { - "bdata": "CagpQLmBGkAfYxdAgm3qP04g6D8gvcM/n5K1P1zGvT/fZXA/B5YgP3uTPz9xdk0/uIUlP4SWlT62KQg/fK0PP7JI9D5AMEk+cFYLvag5k72oPZq9SECwvcC25jyAmoC8QKpQPpCJ8D34X4m+v/TNvoE1pL46Vti++CSIvW6XtL6ySB6/INhbv4ukiL/s74W/9uF7vx8Ecb+GXWy/zHqJv90ZmL9+CJO/NseLv7iKK7/6N76+56MbvzCRUL93QUu/Jc9Kv4hnJb4Iy+q+xY4Kv5Ex3L5+Oje//ztyv9uwZ7/thmS/O5cxv5USSL8odBu/Cpgnv9plab9IFja/EK8Dvo6uoz7w7EQ+UO+/PXoP1D62qi0/NHbrPvidzj1iw0e+bHNYvlGFsb5AU/w9QE45Pshqlr1f7oO+yBa+vqd6pr4ENpO+8KbzvWyKCD5wRJs9gJnOvaDpnzzGJ52+ldvkvraxBb92NhW/XB2XvloV0L4+Krq+CDH5vpnMDb+97tq+GUgLv7lBjr4uJ3C+NHoMv5A92r2gnyw+EEiqPey+FT5ANnC9cAmvvbbT075ETvu+JIAQv4tA7b7k8T+/8sFCvxw4Rb8fSx6/xb8Bv3OXOL8D+kK/AxBKvzLZTL+TpU+/declvxHjXr8hWFi/Ry+vvjhrIr/JLi6/6t8Mv+mqjb4ZfIO+uMiJPYCHkzvqrKu+rlDTvoxkL7/WXWO/AqSJv+xiKb8D4rK+XA/evlRNBr9t8xi/WFb5vksyy74Eo6O+IwSEvrAGfL4wPGm+YGl4vdxuQT7QuPo9QKptvowsWb6Plqy+3ATivu4qcL6Ibla+WCZCvvikxz0GbWO+3sJdvivbqb5Fo96+MMgwvygTcL8nhTu/fpM6vyaSQ78xafK+ICzDvfhl/r0SxI++4EbRPAgHJL5pHp6+nvQSv/bfJb8NWjW/mYnBvgBWBrw0vLq+rm2Tvlir3L6Mi0a+oF3OvBRqTr6Yz8E9OC/xvZZoi75kyYc+gODMPMhJEr40Kls+wN6ZvPAFX72uYNw+MDgmPj5dmT6Ykqu9IC/RPCymIr4AQcW8kHTgPtXEOj8HyUk/x6QMP5Tnwz5wSmg+oLF/PgDxbjvAxSq9SG5Svoestr6kKyq+2ajsvhoOQb9tkXe/QoCPv6CtZL/dkTC/ZJdmv91Rab9cIJC/cj6Xvm4NFb+EcyG+E9KYvvJAib7m0NO+lMm0vltU5b6wOTs+qEpRPrYisj7MvlI+SK5wPgAA/zpAAvi85AhQvuATQb4RJa2+IoOUvtZqdr4qoQi/Anofv0o7Xb/ZuYe/roAgvwySM7+FZzm/hnwTv5G+RL9EO0m/dVN2v61jRr9lNyG/9KFbv3e7h7+0BoK/iRGbvyV0kb8hXai/32Cgv0zJt7+81MW/f6mavzugc78rIGu/boRiv4G9iL98q1W/7dW+vno5pr7QTh09XOAHPrgaqb36xH2+UEtavfyK3b5LAyq/DSo7v6v00L7nxS6/2k9sv9xea78IQIu/neRav0nQr75GffK+Tt8Hvw9H3r6Iwba+CD7oviTvvL5aIiS/jqy2vrV0lr46Ede+bPZbvkPd+b6e7EK/", - "dtype": "f4" - }, - "yaxis": "y2" - } - ], - "layout": { - "annotations": [ - { - "font": { - "size": 16 - }, - "showarrow": false, - "text": "Observation Predictions", - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 0.9999999999999999, - "yanchor": "bottom", - "yref": "paper" - }, - { - "font": { - "size": 16 - }, - "showarrow": false, - "text": "Latent State Estimation", - "x": 0.5, - "xanchor": "center", - "xref": "paper", - "y": 0.46499999999999997, - "yanchor": "bottom", - "yref": "paper" - } - ], - "height": 1000, - "legend": { - "orientation": "h", - "x": 0, - "xanchor": "left", - "y": 1, - "yanchor": "top" - }, - "legend2": { - "orientation": "h", - "x": 0, - "xanchor": "left", - "y": 0.465, - "yanchor": "top" - }, - "showlegend": true, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#f2f5fa" - }, - "error_y": { - "color": "#f2f5fa" - }, - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "rgb(17,17,17)", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "baxis": { - "endlinecolor": "#A2B1C6", - "gridcolor": "#506784", - "linecolor": "#506784", - "minorgridcolor": "#506784", - "startlinecolor": "#A2B1C6" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "line": { - "color": "#283442" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#506784" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "header": { - "fill": { - "color": "#2a3f5f" - }, - "line": { - "color": "rgb(17,17,17)" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#f2f5fa", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#f2f5fa" - }, - "geo": { - "bgcolor": "rgb(17,17,17)", - "lakecolor": "rgb(17,17,17)", - "landcolor": "rgb(17,17,17)", - "showlakes": true, - "showland": true, - "subunitcolor": "#506784" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "dark" - }, - "paper_bgcolor": "rgb(17,17,17)", - "plot_bgcolor": "rgb(17,17,17)", - "polar": { - "angularaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "radialaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "yaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - }, - "zaxis": { - "backgroundcolor": "rgb(17,17,17)", - "gridcolor": "#506784", - "gridwidth": 2, - "linecolor": "#506784", - "showbackground": true, - "ticks": "", - "zerolinecolor": "#C8D4E3" - } - }, - "shapedefaults": { - "line": { - "color": "#f2f5fa" - } - }, - "sliderdefaults": { - "bgcolor": "#C8D4E3", - "bordercolor": "rgb(17,17,17)", - "borderwidth": 1, - "tickwidth": 0 - }, - "ternary": { - "aaxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "baxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - }, - "bgcolor": "rgb(17,17,17)", - "caxis": { - "gridcolor": "#506784", - "linecolor": "#506784", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "updatemenudefaults": { - "bgcolor": "#506784", - "borderwidth": 0 - }, - "xaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "#283442", - "linecolor": "#506784", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "#283442", - "zerolinewidth": 2 - } - } - }, - "width": 1200, - "xaxis": { - "anchor": "y", - "domain": [ - 0, - 1 - ], - "matches": "x2", - "showticklabels": false - }, - "xaxis2": { - "anchor": "y2", - "domain": [ - 0, - 1 - ] - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.5349999999999999, - 0.9999999999999999 - ] - }, - "yaxis2": { - "anchor": "x2", - "domain": [ - 0, - 0.46499999999999997 - ] - } - } - } + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" From 254e48c9bfc5345804fdfa922d2578d84b5fa1e4 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Mon, 6 Oct 2025 15:29:39 -0600 Subject: [PATCH 03/11] Updated how jax functions are blocked and updated jax fibonacci algorithm to prevent constant folding --- doc/gallery/scan/benchmark_backends.ipynb | 852 +++++++++++----------- 1 file changed, 441 insertions(+), 411 deletions(-) diff --git a/doc/gallery/scan/benchmark_backends.ipynb b/doc/gallery/scan/benchmark_backends.ipynb index ee078e8a49..b4aa86076d 100644 --- a/doc/gallery/scan/benchmark_backends.ipynb +++ b/doc/gallery/scan/benchmark_backends.ipynb @@ -53,7 +53,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "pytensor version: 0+untagged.31336.g403c7f5.dirty\n", + "pytensor version: 0+untagged.31337.g1580b09.dirty\n", "jax version: 0.7.2\n", "numba version: 0.62.1\n" ] @@ -258,6 +258,30 @@ { "cell_type": "code", "execution_count": 5, + "id": "799a759b", + "metadata": {}, + "outputs": [], + "source": [ + "# def block(func):\n", + "# def inner(*args, **kwargs):\n", + "# return jax.block_until_ready(func(*args, **kwargs))\n", + "# return inner\n", + "\n", + "\n", + "# I believe the above will only work if the return is a single jnp.array (at least that is what AI thinks) I would appreciate your insights here, Adrian.\n", + "\n", + "def block(func):\n", + " def inner(*args, **kwargs):\n", + " result = func(*args, **kwargs)\n", + " # Recursively block on all JAX arrays in result\n", + " jax.tree_util.tree_map(lambda x: x.block_until_ready() if hasattr(x, \"block_until_ready\") else None, result)\n", + " return result\n", + " return inner\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, "id": "6e76a860", "metadata": {}, "outputs": [], @@ -292,7 +316,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "ed368809", "metadata": {}, "outputs": [], @@ -316,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "bf48d6bf", "metadata": {}, "outputs": [], @@ -332,29 +356,32 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "893c3124", "metadata": {}, "outputs": [], "source": [ - "# This is faster than running a scan or a fori_loop\n", + "# This is faster than running a scan or a fori_loop (so this was due to constant folding) switching back to a fori_loop\n", + "@block\n", "@partial(jax.jit, static_argnums=0)\n", "def fibonacci_jax(n):\n", - " a, b = jnp.array(1, dtype=np.int32), jnp.array(1, dtype=np.int32)\n", - " for _ in range(n):\n", - " a, b = a + b, a\n", + " def body(_, val):\n", + " a, b = val\n", + " return a + b, a\n", + " a, b = jnp.array(1, jnp.int32), jnp.array(1, jnp.int32)\n", + " a, b = jax.lax.fori_loop(0, n, body, (a, b))\n", " return a" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "63bfdffe", "metadata": {}, "outputs": [], "source": [ "fibonacci_bench = Benchmarker(\n", - " functions=[fibonacci_pytensor, fibonacci_numba, jax.block_until_ready(fibonacci_jax), fibonacci_pytensor_numba], \n", + " functions=[fibonacci_pytensor, fibonacci_numba, fibonacci_jax, fibonacci_pytensor_numba], \n", " names=['fibonacci_pytensor', 'fibonacci_numba', 'fibonacci_jax', 'fibonacci_pytensor_numba'],\n", " number=10\n", ")" @@ -362,7 +389,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "65bf994e", "metadata": {}, "outputs": [ @@ -404,52 +431,52 @@ " fibonacci_pytensor\n", " fibonacci_inputs\n", " 10\n", - " 68155.341699\n", - " 69006.229100\n", - " 68637.53498\n", - " 277.683947\n", - " 68645.579100\n", - " 151.466600\n", - " 0.014569\n", + " 64686.808300\n", + " 66047.833300\n", + " 65296.890820\n", + " 521.516870\n", + " 65249.033400\n", + " 913.420902\n", + " 0.015315\n", " 5\n", " \n", " \n", " fibonacci_numba\n", " fibonacci_inputs\n", " 10\n", - " 86.483300\n", - " 108.250001\n", - " 95.49680\n", - " 6.168624\n", - " 95.529199\n", - " 5.229100\n", - " 10.471555\n", - " 13\n", + " 90.433301\n", + " 96.358400\n", + " 92.130650\n", + " 1.726383\n", + " 91.416649\n", + " 2.119800\n", + " 10.854151\n", + " 14\n", " \n", " \n", " fibonacci_jax\n", " fibonacci_inputs\n", " 10\n", - " 2.400001\n", - " 9.104201\n", - " 3.79250\n", - " 2.656539\n", - " 2.462500\n", - " 0.154199\n", - " 263.678308\n", - " 5\n", + " 179.050000\n", + " 207.683300\n", + " 188.989706\n", + " 6.309722\n", + " 187.704150\n", + " 7.456250\n", + " 5.291293\n", + " 34\n", " \n", " \n", " fibonacci_pytensor_numba\n", " fibonacci_inputs\n", " 10\n", - " 3398.070800\n", - " 3432.645799\n", - " 3416.00250\n", - " 11.031143\n", - " 3417.499999\n", - " 3.904101\n", - " 0.292740\n", + " 3271.316699\n", + " 3350.558299\n", + " 3305.100820\n", + " 25.673223\n", + " 3299.187499\n", + " 8.516600\n", + " 0.302563\n", " 5\n", " \n", " \n", @@ -458,31 +485,31 @@ ], "text/plain": [ " Loops Min (us) Max (us) \\\n", - "fibonacci_pytensor fibonacci_inputs 10 68155.341699 69006.229100 \n", - "fibonacci_numba fibonacci_inputs 10 86.483300 108.250001 \n", - "fibonacci_jax fibonacci_inputs 10 2.400001 9.104201 \n", - "fibonacci_pytensor_numba fibonacci_inputs 10 3398.070800 3432.645799 \n", + "fibonacci_pytensor fibonacci_inputs 10 64686.808300 66047.833300 \n", + "fibonacci_numba fibonacci_inputs 10 90.433301 96.358400 \n", + "fibonacci_jax fibonacci_inputs 10 179.050000 207.683300 \n", + "fibonacci_pytensor_numba fibonacci_inputs 10 3271.316699 3350.558299 \n", "\n", - " Mean (us) StdDev (us) \\\n", - "fibonacci_pytensor fibonacci_inputs 68637.53498 277.683947 \n", - "fibonacci_numba fibonacci_inputs 95.49680 6.168624 \n", - "fibonacci_jax fibonacci_inputs 3.79250 2.656539 \n", - "fibonacci_pytensor_numba fibonacci_inputs 3416.00250 11.031143 \n", + " Mean (us) StdDev (us) \\\n", + "fibonacci_pytensor fibonacci_inputs 65296.890820 521.516870 \n", + "fibonacci_numba fibonacci_inputs 92.130650 1.726383 \n", + "fibonacci_jax fibonacci_inputs 188.989706 6.309722 \n", + "fibonacci_pytensor_numba fibonacci_inputs 3305.100820 25.673223 \n", "\n", " Median (us) IQR (us) \\\n", - "fibonacci_pytensor fibonacci_inputs 68645.579100 151.466600 \n", - "fibonacci_numba fibonacci_inputs 95.529199 5.229100 \n", - "fibonacci_jax fibonacci_inputs 2.462500 0.154199 \n", - "fibonacci_pytensor_numba fibonacci_inputs 3417.499999 3.904101 \n", + "fibonacci_pytensor fibonacci_inputs 65249.033400 913.420902 \n", + "fibonacci_numba fibonacci_inputs 91.416649 2.119800 \n", + "fibonacci_jax fibonacci_inputs 187.704150 7.456250 \n", + "fibonacci_pytensor_numba fibonacci_inputs 3299.187499 8.516600 \n", "\n", " OPS (Kops/s) Samples \n", - "fibonacci_pytensor fibonacci_inputs 0.014569 5 \n", - "fibonacci_numba fibonacci_inputs 10.471555 13 \n", - "fibonacci_jax fibonacci_inputs 263.678308 5 \n", - "fibonacci_pytensor_numba fibonacci_inputs 0.292740 5 " + "fibonacci_pytensor fibonacci_inputs 0.015315 5 \n", + "fibonacci_numba fibonacci_inputs 10.854151 14 \n", + "fibonacci_jax fibonacci_inputs 5.291293 34 \n", + "fibonacci_pytensor_numba fibonacci_inputs 0.302563 5 " ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -506,7 +533,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "7b8bb97b", "metadata": {}, "outputs": [], @@ -530,7 +557,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "14327cbf", "metadata": {}, "outputs": [], @@ -546,11 +573,12 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "3943328f", "metadata": {}, "outputs": [], "source": [ + "@block\n", "@jax.jit\n", "def elementwise_multiply_jax(a, b):\n", " n = a.shape[0]\n", @@ -562,7 +590,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "d43c4f9c", "metadata": {}, "outputs": [], @@ -573,13 +601,13 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "id": "f0f4ede5", "metadata": {}, "outputs": [], "source": [ "elem_mult_bench = Benchmarker(\n", - " functions=[elementwise_multiply_pytensor, elementwise_multiply_numba, jax.block_until_ready(elementwise_multiply_jax), elementwise_multiply_pytensor_numba], \n", + " functions=[elementwise_multiply_pytensor, elementwise_multiply_numba, elementwise_multiply_jax, elementwise_multiply_pytensor_numba], \n", " names=['elementwise_multiply_pytensor', 'elementwise_multiply_numba', 'elementwise_multiply_jax', 'elementwise_multiply_pytensor_numba'],\n", " number=10\n", ")" @@ -587,7 +615,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "id": "cdab8946", "metadata": {}, "outputs": [ @@ -629,53 +657,53 @@ " elementwise_multiply_pytensor\n", " elem_mult_inputs\n", " 10\n", - " 3.120801\n", - " 24.929100\n", - " 3.680448\n", - " 0.486678\n", - " 3.595800\n", - " 0.133300\n", - " 271.706047\n", - " 13825\n", + " 3.041701\n", + " 16.812500\n", + " 3.474337\n", + " 0.532641\n", + " 3.462499\n", + " 0.37500\n", + " 287.824674\n", + " 11685\n", " \n", " \n", " elementwise_multiply_numba\n", " elem_mult_inputs\n", " 10\n", - " 0.383401\n", - " 0.695800\n", - " 0.413064\n", - " 0.062775\n", - " 0.397950\n", - " 0.011476\n", - " 2420.933988\n", - " 22\n", + " 0.354100\n", + " 1.437499\n", + " 0.418324\n", + " 0.219827\n", + " 0.358300\n", + " 0.01250\n", + " 2390.492112\n", + " 25\n", " \n", " \n", " elementwise_multiply_jax\n", " elem_mult_inputs\n", " 10\n", - " 7.612501\n", - " 8.129200\n", - " 7.791072\n", - " 0.151626\n", - " 7.762501\n", - " 0.087450\n", - " 128.352043\n", + " 7.687499\n", + " 8.874999\n", + " 7.994042\n", + " 0.374402\n", + " 7.862500\n", + " 0.17085\n", + " 125.093159\n", " 7\n", " \n", " \n", " elementwise_multiply_pytensor_numba\n", " elem_mult_inputs\n", " 10\n", - " 3.875000\n", - " 5.870899\n", - " 4.145834\n", - " 0.611565\n", - " 3.925001\n", - " 0.083400\n", - " 241.206018\n", - " 9\n", + " 3.641599\n", + " 5.820900\n", + " 4.144570\n", + " 0.605796\n", + " 4.016650\n", + " 0.20215\n", + " 241.279555\n", + " 10\n", " \n", " \n", "\n", @@ -683,37 +711,37 @@ ], "text/plain": [ " Loops Min (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 10 3.120801 \n", - "elementwise_multiply_numba elem_mult_inputs 10 0.383401 \n", - "elementwise_multiply_jax elem_mult_inputs 10 7.612501 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 10 3.875000 \n", + "elementwise_multiply_pytensor elem_mult_inputs 10 3.041701 \n", + "elementwise_multiply_numba elem_mult_inputs 10 0.354100 \n", + "elementwise_multiply_jax elem_mult_inputs 10 7.687499 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 10 3.641599 \n", "\n", " Max (us) Mean (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 24.929100 3.680448 \n", - "elementwise_multiply_numba elem_mult_inputs 0.695800 0.413064 \n", - "elementwise_multiply_jax elem_mult_inputs 8.129200 7.791072 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 5.870899 4.145834 \n", + "elementwise_multiply_pytensor elem_mult_inputs 16.812500 3.474337 \n", + "elementwise_multiply_numba elem_mult_inputs 1.437499 0.418324 \n", + "elementwise_multiply_jax elem_mult_inputs 8.874999 7.994042 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 5.820900 4.144570 \n", "\n", " StdDev (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 0.486678 \n", - "elementwise_multiply_numba elem_mult_inputs 0.062775 \n", - "elementwise_multiply_jax elem_mult_inputs 0.151626 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 0.611565 \n", + "elementwise_multiply_pytensor elem_mult_inputs 0.532641 \n", + "elementwise_multiply_numba elem_mult_inputs 0.219827 \n", + "elementwise_multiply_jax elem_mult_inputs 0.374402 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 0.605796 \n", "\n", " Median (us) IQR (us) \\\n", - "elementwise_multiply_pytensor elem_mult_inputs 3.595800 0.133300 \n", - "elementwise_multiply_numba elem_mult_inputs 0.397950 0.011476 \n", - "elementwise_multiply_jax elem_mult_inputs 7.762501 0.087450 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 3.925001 0.083400 \n", + "elementwise_multiply_pytensor elem_mult_inputs 3.462499 0.37500 \n", + "elementwise_multiply_numba elem_mult_inputs 0.358300 0.01250 \n", + "elementwise_multiply_jax elem_mult_inputs 7.862500 0.17085 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 4.016650 0.20215 \n", "\n", " OPS (Kops/s) Samples \n", - "elementwise_multiply_pytensor elem_mult_inputs 271.706047 13825 \n", - "elementwise_multiply_numba elem_mult_inputs 2420.933988 22 \n", - "elementwise_multiply_jax elem_mult_inputs 128.352043 7 \n", - "elementwise_multiply_pytensor_numba elem_mult_inputs 241.206018 9 " + "elementwise_multiply_pytensor elem_mult_inputs 287.824674 11685 \n", + "elementwise_multiply_numba elem_mult_inputs 2390.492112 25 \n", + "elementwise_multiply_jax elem_mult_inputs 125.093159 7 \n", + "elementwise_multiply_pytensor_numba elem_mult_inputs 241.279555 10 " ] }, - "execution_count": 16, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -745,7 +773,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "id": "c1226cfc", "metadata": {}, "outputs": [], @@ -807,11 +835,12 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "id": "14937a2a", "metadata": {}, "outputs": [], "source": [ + "@block\n", "@jax.jit\n", "def cusum_adaptive_jax(x, alpha=0.01, k=0.5, h=5.0):\n", " \"\"\"\n", @@ -868,7 +897,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "id": "815967a4", "metadata": {}, "outputs": [], @@ -907,7 +936,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "id": "024f421f", "metadata": {}, "outputs": [], @@ -917,7 +946,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "id": "6c892129", "metadata": {}, "outputs": [], @@ -932,13 +961,13 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "id": "d21873d6", "metadata": {}, "outputs": [], "source": [ "cusum_bench = Benchmarker(\n", - " functions=[cusum_adaptive_pytensor, cusum_adaptive_numba, jax.block_until_ready(cusum_adaptive_jax), cusum_adaptive_pytensor_numba, jax.block_until_ready(cusum_adaptive_pytensor_jax)], \n", + " functions=[cusum_adaptive_pytensor, cusum_adaptive_numba, cusum_adaptive_jax, cusum_adaptive_pytensor_numba, block(cusum_adaptive_pytensor_jax)], \n", " names=['cusum_adaptive_pytensor', 'cusum_adaptive_numba', 'cusum_adaptive_jax', 'cusum_adaptive_pytensor_numba', 'cusum_adaptive_pytensor_jax'],\n", " number=10\n", ")" @@ -946,7 +975,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "id": "d8eab72d", "metadata": {}, "outputs": [ @@ -988,66 +1017,66 @@ " cusum_adaptive_pytensor\n", " cusum_inputs\n", " 10\n", - " 128.400000\n", - " 299.025000\n", - " 143.153589\n", - " 9.045458\n", - " 141.397951\n", - " 4.814550\n", - " 6.985504\n", - " 700\n", + " 117.220900\n", + " 232.295900\n", + " 133.656559\n", + " 7.147122\n", + " 133.312501\n", + " 5.929149\n", + " 7.481863\n", + " 751\n", " \n", " \n", " cusum_adaptive_numba\n", " cusum_inputs\n", " 10\n", - " 1.912500\n", - " 2.754100\n", - " 2.054171\n", - " 0.286152\n", - " 1.937500\n", - " 0.024949\n", - " 486.814287\n", - " 7\n", + " 1.595799\n", + " 1.887501\n", + " 1.643737\n", + " 0.092613\n", + " 1.612500\n", + " 0.018701\n", + " 608.369744\n", + " 8\n", " \n", " \n", " cusum_adaptive_jax\n", " cusum_inputs\n", " 10\n", - " 13.299999\n", - " 15.166700\n", - " 13.695474\n", - " 0.484202\n", - " 13.493751\n", - " 0.295901\n", - " 73.016826\n", - " 34\n", + " 15.895799\n", + " 65.595801\n", + " 21.025784\n", + " 11.468858\n", + " 16.758300\n", + " 1.229101\n", + " 47.560653\n", + " 37\n", " \n", " \n", " cusum_adaptive_pytensor_numba\n", " cusum_inputs\n", " 10\n", - " 25.820901\n", - " 33.770800\n", - " 27.558320\n", - " 3.108080\n", - " 26.070800\n", - " 0.154100\n", - " 36.286682\n", + " 22.312500\n", + " 26.791700\n", + " 23.701660\n", + " 1.633376\n", + " 22.958299\n", + " 1.304199\n", + " 42.191138\n", " 5\n", " \n", " \n", " cusum_adaptive_pytensor_jax\n", " cusum_inputs\n", " 10\n", - " 19.604200\n", - " 33.145801\n", - " 22.009776\n", - " 2.327129\n", - " 21.483301\n", - " 0.612499\n", - " 45.434356\n", - " 29\n", + " 23.045800\n", + " 27.145800\n", + " 24.714578\n", + " 1.031385\n", + " 24.504150\n", + " 1.190700\n", + " 40.461949\n", + " 32\n", " \n", " \n", "\n", @@ -1055,35 +1084,35 @@ ], "text/plain": [ " Loops Min (us) Max (us) \\\n", - "cusum_adaptive_pytensor cusum_inputs 10 128.400000 299.025000 \n", - "cusum_adaptive_numba cusum_inputs 10 1.912500 2.754100 \n", - "cusum_adaptive_jax cusum_inputs 10 13.299999 15.166700 \n", - "cusum_adaptive_pytensor_numba cusum_inputs 10 25.820901 33.770800 \n", - "cusum_adaptive_pytensor_jax cusum_inputs 10 19.604200 33.145801 \n", + "cusum_adaptive_pytensor cusum_inputs 10 117.220900 232.295900 \n", + "cusum_adaptive_numba cusum_inputs 10 1.595799 1.887501 \n", + "cusum_adaptive_jax cusum_inputs 10 15.895799 65.595801 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 10 22.312500 26.791700 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 10 23.045800 27.145800 \n", "\n", " Mean (us) StdDev (us) \\\n", - "cusum_adaptive_pytensor cusum_inputs 143.153589 9.045458 \n", - "cusum_adaptive_numba cusum_inputs 2.054171 0.286152 \n", - "cusum_adaptive_jax cusum_inputs 13.695474 0.484202 \n", - "cusum_adaptive_pytensor_numba cusum_inputs 27.558320 3.108080 \n", - "cusum_adaptive_pytensor_jax cusum_inputs 22.009776 2.327129 \n", + "cusum_adaptive_pytensor cusum_inputs 133.656559 7.147122 \n", + "cusum_adaptive_numba cusum_inputs 1.643737 0.092613 \n", + "cusum_adaptive_jax cusum_inputs 21.025784 11.468858 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 23.701660 1.633376 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 24.714578 1.031385 \n", "\n", " Median (us) IQR (us) \\\n", - "cusum_adaptive_pytensor cusum_inputs 141.397951 4.814550 \n", - "cusum_adaptive_numba cusum_inputs 1.937500 0.024949 \n", - "cusum_adaptive_jax cusum_inputs 13.493751 0.295901 \n", - "cusum_adaptive_pytensor_numba cusum_inputs 26.070800 0.154100 \n", - "cusum_adaptive_pytensor_jax cusum_inputs 21.483301 0.612499 \n", + "cusum_adaptive_pytensor cusum_inputs 133.312501 5.929149 \n", + "cusum_adaptive_numba cusum_inputs 1.612500 0.018701 \n", + "cusum_adaptive_jax cusum_inputs 16.758300 1.229101 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 22.958299 1.304199 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 24.504150 1.190700 \n", "\n", " OPS (Kops/s) Samples \n", - "cusum_adaptive_pytensor cusum_inputs 6.985504 700 \n", - "cusum_adaptive_numba cusum_inputs 486.814287 7 \n", - "cusum_adaptive_jax cusum_inputs 73.016826 34 \n", - "cusum_adaptive_pytensor_numba cusum_inputs 36.286682 5 \n", - "cusum_adaptive_pytensor_jax cusum_inputs 45.434356 29 " + "cusum_adaptive_pytensor cusum_inputs 7.481863 751 \n", + "cusum_adaptive_numba cusum_inputs 608.369744 8 \n", + "cusum_adaptive_jax cusum_inputs 47.560653 37 \n", + "cusum_adaptive_pytensor_numba cusum_inputs 42.191138 5 \n", + "cusum_adaptive_pytensor_jax cusum_inputs 40.461949 32 " ] }, - "execution_count": 23, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -1099,7 +1128,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "id": "3e9c3339", "metadata": {}, "outputs": [], @@ -1109,7 +1138,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "id": "b85d0c0e", "metadata": {}, "outputs": [ @@ -5011,9 +5040,9 @@ { "data": { "text/html": [ - "