diff --git a/docs/tutorials/gentle_intro/03_filtering_mll_no_numpyro.ipynb b/docs/tutorials/gentle_intro/03_filtering_mll_no_numpyro.ipynb new file mode 100644 index 00000000..b442a119 --- /dev/null +++ b/docs/tutorials/gentle_intro/03_filtering_mll_no_numpyro.ipynb @@ -0,0 +1,406 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b9ed09ab", + "metadata": {}, + "source": [ + "# Part 3 (NumPyro-free): Filtering and the marginal log-likelihood with `dsx.condition`\n", + "\n", + "This notebook is a NumPyro-free counterpart to [Part 3: Filtering and the marginal log-likelihood](03_filtering_mll.ipynb). We use **filtering** (e.g. the cuthbert particle filter) to compute the **marginal log-likelihood** (MLL) $\\log p(y_{1:T} \\mid \\theta)$ at fixed parameters $\\theta$, and show how to switch to a different filter (e.g. Taylor KF) --- all **without writing a NumPyro model**, using `dsx.condition` instead of `dsx.sample`." + ] + }, + { + "cell_type": "markdown", + "id": "8dac55d8", + "metadata": {}, + "source": [ + "## 3.1 Why filtering? Computing MLL without sampling states\n", + "\n", + "Dynamical systems are a special problem in that they carry lots of structure that we can exploit in inference --- in the types of dynamical systems specified in dynestyx, observations depend only on the state (and possibly observed control inputs), and the next state depends only on the current state (and possibly observed control inputs). This suggests a family of algorithms that exploit this structure, using only the relevant information when inferring a particular state.\n", + "\n", + "Additionally, sometimes we don't want to infer the full state trajectory anyways -- we only care about **parameters** $\\theta$ that describe the system. The resulting problem is called **system identification**, and only necessitates the **marginal likelihood** $\\log p(y_{1:T} \\mid \\theta)$, which implicitly marginalizes the states.\n", + "\n", + "Mathematically, both of these goals are accomplished by a **filtering** algorithm; filtering algorithms exploit the structure of a dynamical system for efficient estimation, whilst also providing an estimate of the marginal likelihood. In the original notebook, dynestyx's filtering handlers add this marginal likelihood as a NumPyro factor inside a NumPyro model. Here we instead use `dsx.condition`, which runs the same filters but simply **returns** a `ConditionedResult` carrying `.marginal_loglik` (along with the filtered states), with no NumPyro model, trace, or sites involved.\n", + "\n", + "We'll use the **particle filter** (from the library [`cuthbert`](https://www.github.com/state-space-models/cuthbert)) to compute a \"profile likelihood\": that is, we will plot the marginal log-likelihood (MLL) vs $\\theta$." + ] + }, + { + "cell_type": "markdown", + "id": "ac49f430", + "metadata": {}, + "source": [ + "### Generate synthetic data with $\\rho = 0.3$\n", + "\n", + "Our model definition and data generation are the same as in the original notebook, providing a linear Gaussian system with data generated at a true value of $\\rho = 0.3$.\n", + "\n", + "> **Note:** to keep the data (and hence the figures) identical to the original notebook, this data-generation section reuses the NumPyro-based simulator exactly as in the original. Everything from the inference sections onward is NumPyro-free." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9ccc821d", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:35:00.922524Z", + "iopub.status.busy": "2026-06-11T17:35:00.922286Z", + "iopub.status.idle": "2026-06-11T17:35:02.417879Z", + "shell.execute_reply": "2026-06-11T17:35:02.417603Z" + } + }, + "outputs": [], + "source": [ + "import jax.numpy as jnp\n", + "import jax.random as jr\n", + "import numpyro\n", + "import numpyro.distributions as dist\n", + "from numpyro.infer import Predictive\n", + "\n", + "import dynestyx as dsx\n", + "from dynestyx import DiscreteTimeSimulator, DynamicalModel\n", + "\n", + "# for convenience, we can define \"fixed\" things in the model outside of it.\n", + "# this is not required, but it helps keep the model clean.\n", + "state_dim = 2\n", + "observation_dim = 1\n", + "control_dim = 1\n", + "\n", + "# Create the known matrices B, C\n", + "B = jnp.eye(state_dim, control_dim)\n", + "C = jnp.eye(observation_dim, state_dim)\n", + "\n", + "# create the initial condition as a distribution\n", + "initial_condition = dist.MultivariateNormal(jnp.zeros(state_dim), jnp.eye(state_dim))\n", + "\n", + "\n", + "def lti_model(\n", + " sigma_obs=0.1,\n", + " sigma_process=0.1,\n", + " obs_times=None,\n", + " obs_values=None,\n", + " ctrl_times=None,\n", + " ctrl_values=None,\n", + " predict_times=None,\n", + "):\n", + " # sample the unknown parameter\n", + " rho = numpyro.sample(\"rho\", dist.Uniform(-0.5, 0.5))\n", + " A = jnp.array([[0, 0.3], [rho, -0.2]])\n", + "\n", + " # create the state evolution as a callable mapping to a distribution\n", + " # Crucially, this depends on A, which depends on rho, which is unknown.\n", + " # Thus, the state evolution MUST be defined within `lti_model`, not outside.\n", + " state_evolution = lambda x, u, t_now, t_next: dist.MultivariateNormal(\n", + " A @ x + B @ u, sigma_process**2 * jnp.eye(state_dim)\n", + " )\n", + "\n", + " # create the observation model as a callable mapping to a distribution\n", + " observation_model = lambda x, u, t: dist.MultivariateNormal(\n", + " C @ x, sigma_obs**2 * jnp.eye(observation_dim)\n", + " )\n", + "\n", + " # create the dynamical model\n", + " dynamics = DynamicalModel(\n", + " control_dim=control_dim,\n", + " initial_condition=initial_condition,\n", + " state_evolution=state_evolution,\n", + " observation_model=observation_model,\n", + " )\n", + "\n", + " # sample from the dynamical model\n", + " return dsx.sample(\n", + " \"f\",\n", + " dynamics,\n", + " obs_times=obs_times,\n", + " obs_values=obs_values,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " predict_times=predict_times,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "ff280b4a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:35:02.419121Z", + "iopub.status.busy": "2026-06-11T17:35:02.418994Z", + "iopub.status.idle": "2026-06-11T17:35:03.376212Z", + "shell.execute_reply": "2026-06-11T17:35:03.375996Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "make_data shapes: (1, 1, 100) (1, 1, 100, 1)\n" + ] + } + ], + "source": [ + "# create a synthetic control sequence as i.i.d. Gaussians\n", + "obs_times = jnp.arange(0.0, 100.0, 1.0) # T=100 steps\n", + "ctrl_times = obs_times # same times for controls\n", + "ctrl_values = jr.normal(jr.PRNGKey(0), (len(ctrl_times), control_dim))\n", + "\n", + "rho_true = 0.3\n", + "\n", + "\n", + "def make_data(sigma_obs=0.1, sigma_process=0.1):\n", + " predictive = Predictive(\n", + " lti_model,\n", + " params={\"rho\": jnp.array(rho_true)},\n", + " num_samples=1,\n", + " exclude_deterministic=False,\n", + " )\n", + " with DiscreteTimeSimulator():\n", + " pred = predictive(\n", + " rng_key=jr.PRNGKey(0),\n", + " sigma_obs=sigma_obs,\n", + " sigma_process=sigma_process,\n", + " predict_times=obs_times,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " )\n", + " print(\"make_data shapes:\", pred[\"f_times\"].shape, pred[\"f_observations\"].shape)\n", + " # Expected: f_observations has shape (1, 1, T, obs_dim)\n", + " obs_values = pred[\"f_observations\"][0, 0, :, :]\n", + " return obs_times, obs_values, ctrl_times, ctrl_values\n", + "\n", + "\n", + "obs_times, obs_values, ctrl_times, ctrl_values = make_data(sigma_obs=0.1, sigma_process=0.1)" + ] + }, + { + "cell_type": "markdown", + "id": "347f2d84", + "metadata": {}, + "source": [ + "**Shape convention note:** simulator outputs include a leading `n_simulations` axis (size 1 by default). Under `Predictive`, there is also a leading `num_samples` axis. In this notebook we index those axes explicitly (for example `[0, 0, ...]`) rather than applying generic squeeze helpers." + ] + }, + { + "cell_type": "markdown", + "id": "eac07fa3", + "metadata": {}, + "source": [ + "### Define the dynamics, NumPyro-free\n", + "\n", + "In the original notebook, the unknown parameter $\\rho$ was a latent NumPyro sample site with a uniform prior. Without NumPyro there is no notion of a prior: $\\rho$ becomes a plain argument, and the model is just a factory returning a `DynamicalModel`. Note that `numpyro.distributions` objects still appear --- dynestyx uses them as plain distribution objects to describe the model; no NumPyro model, trace, or effect handlers are involved." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "05ddc1bf", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:35:03.377313Z", + "iopub.status.busy": "2026-06-11T17:35:03.377261Z", + "iopub.status.idle": "2026-06-11T17:35:03.379036Z", + "shell.execute_reply": "2026-06-11T17:35:03.378853Z" + } + }, + "outputs": [], + "source": [ + "def make_dynamics(rho, sigma_obs=0.1, sigma_process=0.1):\n", + " A = jnp.array([[0, 0.3], [rho, -0.2]])\n", + "\n", + " # create the state evolution as a callable mapping to a distribution\n", + " state_evolution = lambda x, u, t_now, t_next: dist.MultivariateNormal(\n", + " A @ x + B @ u, sigma_process**2 * jnp.eye(state_dim)\n", + " )\n", + "\n", + " # create the observation model as a callable mapping to a distribution\n", + " observation_model = lambda x, u, t: dist.MultivariateNormal(\n", + " C @ x, sigma_obs**2 * jnp.eye(observation_dim)\n", + " )\n", + "\n", + " return DynamicalModel(\n", + " control_dim=control_dim,\n", + " initial_condition=initial_condition,\n", + " state_evolution=state_evolution,\n", + " observation_model=observation_model,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "aeaf07b8", + "metadata": {}, + "source": [ + "### Build the data-conditioned filter-marginalized model\n", + "\n", + "To condition a model using a filtering algorithm, we use a `Filter` object, which takes a `FilterConfig` from `dynestyx.inference.filters` that specifies which filtering algorithm to use.\n", + "\n", + "In this notebook, we'll compare several available options: the ensemble Kalman filter (EnKF, well-suited for non-linear Gaussian models and used by default), the particle filter (PF, more computationally expensive but fully general), and the extended Kalman filter (EKF, less accurate for strongly non-linear systems, but efficient and optimal for linear-Gaussian models).\n", + "\n", + "Next, we'll build a function that evaluates and returns the MLL at a fixed value of the parameter $\\rho$, conditioned on data, and use it to plot a *likelihood profile*. Instead of evaluating a NumPyro model with `Predictive` and reading the MLL factor from the trace, we call `dsx.condition` inside the `Filter` handler and read `.marginal_loglik` off the returned `ConditionedResult`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "48f51ba9", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:35:03.379909Z", + "iopub.status.busy": "2026-06-11T17:35:03.379858Z", + "iopub.status.idle": "2026-06-11T17:35:04.894706Z", + "shell.execute_reply": "2026-06-11T17:35:04.894491Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Array(30.354883, dtype=float32)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from dynestyx import Filter\n", + "from dynestyx.inference.filters import EnKFConfig, EKFConfig, PFConfig\n", + "\n", + "def get_mll(rho, filter_config):\n", + " \"\"\"Run the filter via dsx.condition and return the MLL from the ConditionedResult.\"\"\"\n", + "\n", + " with Filter(filter_config):\n", + " result = dsx.condition(\n", + " \"f\",\n", + " make_dynamics(rho),\n", + " obs_times=obs_times,\n", + " obs_values=obs_values,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " )\n", + "\n", + " return result.marginal_loglik\n", + "\n", + "\n", + "get_mll(0.3, EKFConfig())" + ] + }, + { + "cell_type": "markdown", + "id": "438b1bbb", + "metadata": {}, + "source": [ + "Since dynestyx and its dependencies are written in `jax`, we can exploit its tools for efficient inference (such as jit-compiling or vectorization). In this case, we will generate the likelihood profiles by vmapping over different values of $\\rho$.\n", + "\n", + "One difference from the original notebook: outside a NumPyro model there is no seed handler to supply PRNG keys, so the stochastic filters (EnKF, PF) need an explicit `crn_seed` in their config. Using a fixed key across all values of $\\rho$ gives common random numbers, just like the fixed `Predictive` key in the original." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "26b17b17", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:35:04.895785Z", + "iopub.status.busy": "2026-06-11T17:35:04.895709Z", + "iopub.status.idle": "2026-06-11T17:35:08.799030Z", + "shell.execute_reply": "2026-06-11T17:35:08.798731Z" + } + }, + "outputs": [], + "source": [ + "from jax import vmap\n", + "\n", + "# Profile over values of rho, keeping other parameters at their true values:\n", + "rho_grid = jnp.linspace(-0.8, 0.8, 50)\n", + "\n", + "mll_enkf = vmap(lambda p: get_mll(p, filter_config=EnKFConfig(n_particles=100, crn_seed=jr.PRNGKey(0))))(rho_grid)\n", + "mll_kf = vmap(lambda p: get_mll(p, filter_config=EKFConfig()))(rho_grid)\n", + "mll_pf = vmap(lambda p: get_mll(p, filter_config=PFConfig(n_particles=1000, crn_seed=jr.PRNGKey(0))))(rho_grid)" + ] + }, + { + "cell_type": "markdown", + "id": "4bc7028c", + "metadata": {}, + "source": [ + "We now plot the likelihood profiles, which should be at a maximum at or near the true data-generating value $\\rho = 0.3$." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "45c37723", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:35:08.800256Z", + "iopub.status.busy": "2026-06-11T17:35:08.800201Z", + "iopub.status.idle": "2026-06-11T17:35:09.139270Z", + "shell.execute_reply": "2026-06-11T17:35:09.139062Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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bNgwz2fumeoeeeQR84QdGBho4pRnzJiB8847z/U5wzGmTZuGBx54wORIPvroo82Avfbt21fo/gghhBBCiMqhWohjxiUXFZs8dOhQ8yoKDuTjSwghhBBC1DyqhTj2J2xPNVO6VVS8DvP2+Vu8TmUju8guOl90HdWE3xgWrrLhfcfOGVvT7eJvyC7+YRdbmxVV/07iuIyxE0wz36QQQghRUdSvX1/GFsJHrVarVq2aVz66Mp+CmFIuKiqqQnI82kVHmOeyIoqOVBVkF9lF54uuI/3G6LfXX9A9yT/sQslLYcwHycI81fIclzE0tuegwIqAJ5XEseyi80XXkX5f9NvrD+ieJLv46/lSmMfYRgFBQgghhBBC5CJxLIQQQgghRC4Sx1UcVkQaM2aM+S9kF50vuo70+6Lf3spE9yTZpTqcLxqQJ4QQQgghRC7yHAshhBBCCJGLxLEQQgghhBC5SBwLIYQQQgiRi8SxEEIIIYQQuUgcV0H27NmDSy+91CTMrl27Nq655hocOHCg0O9s374dl19+OerWrYuIiAh07doVH374IWq6XciiRYvQv39/Yxd+94QTTsChQ4dQ0+1iVxM69dRTTbXHTz75BNWJ4tqF7W+99Va0atUKYWFhaNy4MW677Tbs378fVZnnn38eTZs2RWhoKHr27InFixcX2v79999H69atTfsOHTpgzpw5qI4Uxy6vvPIKjj/+eMTExJjXgAEDirRjTTlfbKZPn25+R84++2xUR4prl3379uHmm29GvXr1TKaGli1b6lrK5ZlnnnH9zrJ63p133om0tDRUKCwfLaoWgwYNsjp16mT9/PPP1g8//GAdddRR1sUXX1zod04++WSre/fu1i+//GKtXbvWeuSRR6yAgABr6dKlVk22y8KFC63o6Gjr8ccft1asWGGtXr3amjFjhpWWlmbVZLvYTJo0yTr11FNZYt76+OOPrepEce2yfPly65xzzrFmzZpl/fvvv9ZXX31lHX300da5555rVVWmT59uBQcHW1OnTrX++usva9iwYVbt2rWtpKQkr+1/+ukny+l0WhMnTrRWrlxpPfDAA1ZQUJCxTXWiuHa55JJLrOeff976/fffrVWrVllXXnmlVatWLeu///6zarJdbNavX281aNDAOv74462zzjrLqm4U1y7p6enWMcccY5122mnWjz/+aOzz7bffWsuWLbNqum3effddKyQkxPynXebNm2fVq1fPuvPOOyt0uyWOqxi8IVGoLFmyxDXviy++sBwOh7Vly5YCvxcREWG99dZbeebVqVPHeuWVV6yabJeePXuaG3x1paR2IbzR84a2bdu2aieOS2MXd2bOnGl++DMyMqyqSI8ePaybb77ZNZ2VlWXVr1/fPCx644ILLrAGDx6c7xq6/vrrrepEce3iSWZmphUVFWW9+eabVk23C23Ru3dv69VXX7WGDh1aLcVxce3y4osvWs2bN7cOHz5sVXd6FNM2bNu/f/8884YPH2716dPHqkgUVlHFYAgAu4CPOeYY1zx24QUEBOCXX34p8Hu9e/fGjBkzTNdwdna26eJiN8WJJ56ImmqXHTt2mM8SEhKMfRITE9G3b1/8+OOPqOnnS2pqKi655BLTVchQnOpGSe3iCUMqGJYRGBiIqsbhw4fx22+/mf224f5zmvbxBue7tycDBw4ssH1VpCR28Xb9ZGRkoE6dOqjpdnn44YfNbyzDlqojJbHLrFmz0KtXLxNWwftO+/bt8dhjjyErKws13Ta9e/c237HDUtatW2fCTU477TRUJFXvF72Gw9hh/tC4wxszf4T5WUHMnDkTF154IWJjY0378PBwfPzxxzjqqKNQU+3Ci4489NBDePLJJ9G5c2e89dZbOOmkk7BixQocffTRqKnnC2O8+CN11llnoTpSUru4s2vXLjzyyCO47rrrUBXh9vNmzJuzO5xevXq11+/QNt7a+2qz6moXT0aOHIn69evne5CoaXaho+G1117DsmXLUF0piV147/n666/NmAcKv3///Rc33XSTeaBitbiabJtLLrnEfO+4444zY14yMzNxww034L777kNFIs+xnzBq1CgzWKGwl68/zN548MEHzQCABQsW4Ndff8Xw4cNxwQUXYPny5aipdqEHnVx//fW46qqr0KVLFzz99NNmIMDUqVNRU+1CrwZ/uDkooqpR3teRTXJyMgYPHoy2bduahyshbMaPH2965uh84OCsmkpKSooZBM7BinFxcZW9OX4F7z18OH/55ZfRrVs347i6//77MWXKFNR0vv32W+NFf+GFF7B06VJ89NFH+Pzzz40joiKR59hPGDFiBK688spC2zRv3tx0cTMcwB0+WTFcoqDu77Vr1+K5554z3tB27dqZeZ06dcIPP/xgus39+YIsT7twlDChwHGnTZs22LRpE/yZ8rQLhTHPGYYduHPuueeaEfn88aqJdnG/6Q8aNAhRUVFGAAUFBaEqQsHidDqRlJSUZz6nC7IB5xenfU2xiw17oCiO6YTo2LEjqhPFtQt/QzZs2IAzzjgjn0OCvTR///03WrRogZp4vvDew98Nfs/9vsMeGIYiBAcHozoQVwLb0JHHh6prr73WTDMjzsGDB00PHR8gGJZREUgc+wnx8fHmVRSMU6IHmDE5fOK0xQx/dJg+pqD4N+J5UvGktX+saqJdmHaHXZ/8kXbnn3/+MenLaqpd6H21f5hs+ANFr7r7ja6m2cX2GDPGlqmX6GGvyp5B3oC571999ZUrvRb3n9O33HJLgXbj53fccYdr3vz588386kJJ7EImTpyIcePGYd68eXli2WuqXZjuz7Nn8oEHHjAPl5MnTzYpumrq+dKnTx9MmzbNtLPvy7zvUDRXF2FcUttQr3jTKoRhFhVGhQ7/E2WWgqpLly4mLRvTwDCdlHsKKqYPatWqlfmccEQs01QxjQ7nMQ3Vk08+aUbmf/755zXWLuTpp582qdzef/99a82aNSZzRWhoqLFRTbaLJ9UtW0VJ7LJ//36TmaFDhw7m/GAWD/vFEflVNc0S0ya98cYbJoPHddddZ9Isbd++3Xx++eWXW6NGjcqTyi0wMND8fjBl2ZgxY6ptKrfi2GX8+PEma8kHH3yQ57xISUmxarJdPKmu2SqKa5dNmzaZbCa33HKL9ffff1uzZ8+2EhISrEcffdSq6bYZM2aMsc17771nrVu3zvryyy+tFi1amEw5FYnEcRVk9+7d5iYeGRlphN1VV12V50eYuQEpZr755hvXvH/++cfkaOUFGB4ebnXs2DFfareaaBfClDINGzY0dunVq5fJeVudKKldqrs4Lq5d+J/T3l5sW1V59tlnrcaNGxtxx7RLzPts07dvXyNoPNPXtWzZ0rRv165dtXrALqldmjRp4vW84I2+ulHc86UmiOOS2IU59vmwTeHItG7jxo2rsg/ZZWkbpsV86KGHjCCmo6pRo0bWTTfdZO3du9eqSBxWhfqphRBCCCGE8F+UrUIIIYQQQohcJI6FEEIIIYTIReJYCCGEEEKIXCSOhRBCCCGEkDgWQgghhBAiL/IcCyGEEEIIkYvEsRBCCCGEELlIHAshhBBCCJGLxLEQQgghhBC5SBwLIYQQQgiRi8SxEEIIr3zzzTfo1q0bIiIizOvCCy/E/v37ZS0hRLVG4lgIIUQ+Xn31VQwYMABt2rTBE088gcGDB2PmzJm44447ZC0hRLXGYVmWVdkbIYQQwn9YvXo1OnTogEmTJuHWW291ze/bty8WL16MlJQUBAYGVuo2CiFEeSHPsRBCiDw89NBD6NixI2655ZY880844QSkpaVhz549spgQotoicSyEEMJFZmYm5syZg/POOw8OhyOPZQ4ePGjmRUdHy2JCiGqLxLEQQggXS5cuNWETnTt3zmeVZcuWoVOnTggNDZXFhBDVFoljIYQQeQQwYXYKd7Zt24Yff/wRQ4YMkbWEENUaiWMhhBAu/vzzT/P/u+++yxNqceONN6JWrVq4/vrrZS0hRLVGw42FEEK4WL58Odq2bYtx48aZGON69eph+vTpWLJkCT744AMkJibKWkKIao3EsRBCiDzi+Oabb0bjxo3xyCOPYMeOHejatSu+/PJL9O/fX5YSQlR7lOdYCCGEYfPmzUYUT5s2DRdffLGsIoSokSjmWAghhMtrTNq1ayeLCCFqLBLHQgghXIPxnE4nWrVqJYsIIWosEsdCCCFcnuMWLVogJCREFhFC1FgUcyyEEEIIIUQu8hwLIYQQQgiRi8SxEEIIIYQQuUgcCyGEEEIIkYvEsRBCCCGEELlIHAshhBBCCJGLxLEQQgghhBC5SBwLIYQQQgiRi8SxEEIIIYQQuUgcCyGEEEIIkYvEsRBCCCGEEMjh/8E7CYHsf3a9AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "fig, ax = plt.subplots(figsize=(7, 4), constrained_layout=True)\n", + "ax.plot(rho_grid, mll_pf, \"o-\", color=\"C0\", label=\"Profile likelihood (PF with 1000 particles)\")\n", + "ax.plot(rho_grid, mll_kf, \"o-\", color=\"C1\", label=\"Profile likelihood (Taylor KF)\")\n", + "ax.plot(rho_grid, mll_enkf, \"o-\", color=\"C2\", label=\"Profile likelihood (EnKF with 100 particles)\")\n", + "ax.axvline(rho_true, color=\"k\", linestyle=\"--\", label=r\"$\\rho_{\\mathrm{true}}$\")\n", + "ax.set_xlabel(r\"$\\rho$\", fontsize=12)\n", + "ax.set_ylabel(r\"$\\log p(y_{1:T} \\mid \\rho)$\", fontsize=12)\n", + "ax.set_title(\"Profile likelihood (filtering algorithms)\")\n", + "ax.legend()\n", + "ax.grid(True, alpha=0.3)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "85d4af68", + "metadata": {}, + "source": [ + "We additionally note that for non-Bayesian analysis --- for example, obtaining a maximum likelihood estimate of the system's parameters --- you can consider the filter-based MLL as a \"loss function\" and proceed from there with learning dynamical systems from data. This is exactly what we do in the NumPyro-free counterpart of Part 5: [MLE via filtering + optax](05_svi_no_numpyro.ipynb).\n", + "\n", + "For posterior inference over unknown parameters with these likelihood approximations, see the original NumPyro-based tutorials, e.g. [Part 4 --- Filtering + NUTS: pseudomarginal inference](04_filtering_nuts_pseudomarginal.ipynb)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv (3.12.11)", + "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.12.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/tutorials/gentle_intro/05_svi_no_numpyro.ipynb b/docs/tutorials/gentle_intro/05_svi_no_numpyro.ipynb new file mode 100644 index 00000000..c858712e --- /dev/null +++ b/docs/tutorials/gentle_intro/05_svi_no_numpyro.ipynb @@ -0,0 +1,472 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a9a399a4", + "metadata": {}, + "source": [ + "# Part 5 (NumPyro-free): Maximum-likelihood estimation via filtering + optax\n", + "\n", + "In the original [Part 5](05_svi.ipynb), we used Stochastic Variational Inference (SVI) to infer parameters by treating the filter-based marginal likelihood as a black-box objective. In this notebook, we replicate the filter-based strand of that workflow **without NumPyro PPL**: since there is no longer a notion of a prior, the natural analog is **maximum-likelihood estimation (MLE)** --- we treat the negative marginal log-likelihood returned by `dsx.condition` as a loss and optimize it directly with [`optax`](https://optax.readthedocs.io/).\n", + "\n", + "The joint state + parameter SVI strand of the original notebook is intrinsically a PPL construction and has no NumPyro-free analog, so it is omitted here; see the original notebook for the Bayesian treatment and that comparison." + ] + }, + { + "cell_type": "markdown", + "id": "6ec77f20", + "metadata": {}, + "source": [ + "### Defining and Sampling From the Model\n", + "\n", + "We return to defining and generating data from our running LTI example.\n", + "\n", + "> **Note:** to keep the data (and hence the figures) identical to the original notebook, this data-generation section reuses the NumPyro-based simulator exactly as in the original. Everything from the inference sections onward is NumPyro-free." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "568d9057", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:36:35.738188Z", + "iopub.status.busy": "2026-06-11T17:36:35.738030Z", + "iopub.status.idle": "2026-06-11T17:36:36.801145Z", + "shell.execute_reply": "2026-06-11T17:36:36.800860Z" + } + }, + "outputs": [], + "source": [ + "import jax.numpy as jnp\n", + "import jax.random as jr\n", + "import numpyro\n", + "import numpyro.distributions as dist\n", + "from numpyro.infer import Predictive\n", + "\n", + "import dynestyx as dsx\n", + "from dynestyx import DiscreteTimeSimulator, DynamicalModel\n", + "\n", + "# for convenience, we can define \"fixed\" things in the model outside of it.\n", + "# this is not required, but it helps keep the model clean.\n", + "state_dim = 2\n", + "observation_dim = 1\n", + "control_dim = 1\n", + "\n", + "# Create the known matrices B, C\n", + "B = jnp.eye(state_dim, control_dim)\n", + "C = jnp.eye(observation_dim, state_dim)\n", + "\n", + "# create the initial condition as a distribution\n", + "initial_condition = dist.MultivariateNormal(jnp.zeros(state_dim), jnp.eye(state_dim))\n", + "\n", + "\n", + "def lti_model(\n", + " sigma_obs=0.1,\n", + " sigma_process=0.1,\n", + " obs_times=None,\n", + " obs_values=None,\n", + " ctrl_times=None,\n", + " ctrl_values=None,\n", + " predict_times=None,\n", + "):\n", + " # sample the unknown parameter\n", + " rho = numpyro.sample(\"rho\", dist.Uniform(-0.5, 0.5))\n", + " A = jnp.array([[0, 0.3], [rho, -0.2]])\n", + "\n", + " # create the state evolution as a callable mapping to a distribution\n", + " # Crucially, this depends on A, which depends on rho, which is unknown.\n", + " # Thus, the state evolution MUST be defined within `lti_model`, not outside.\n", + " state_evolution = lambda x, u, t_now, t_next: dist.MultivariateNormal(\n", + " A @ x + B @ u, sigma_process**2 * jnp.eye(state_dim)\n", + " )\n", + "\n", + " # create the observation model as a callable mapping to a distribution\n", + " observation_model = lambda x, u, t: dist.MultivariateNormal(\n", + " C @ x, sigma_obs**2 * jnp.eye(observation_dim)\n", + " )\n", + "\n", + " # create the dynamical model\n", + " dynamics = DynamicalModel(\n", + " control_dim=control_dim,\n", + " initial_condition=initial_condition,\n", + " state_evolution=state_evolution,\n", + " observation_model=observation_model,\n", + " )\n", + "\n", + " # sample from the dynamical model\n", + " return dsx.sample(\n", + " \"f\",\n", + " dynamics,\n", + " obs_times=obs_times,\n", + " obs_values=obs_values,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " predict_times=predict_times,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2c1d50c1", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:36:36.802343Z", + "iopub.status.busy": "2026-06-11T17:36:36.802222Z", + "iopub.status.idle": "2026-06-11T17:36:37.761916Z", + "shell.execute_reply": "2026-06-11T17:36:37.761717Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "make_data shapes: (1, 1, 100) (1, 1, 100, 1)\n" + ] + } + ], + "source": [ + "# create a synthetic control sequence as i.i.d. Gaussians\n", + "obs_times = jnp.arange(0.0, 100.0, 1.0) # T=100 steps\n", + "ctrl_times = obs_times # same times for controls\n", + "ctrl_values = jr.normal(jr.PRNGKey(0), (len(ctrl_times), control_dim))\n", + "\n", + "rho_true = 0.3\n", + "\n", + "\n", + "def make_data(sigma_obs=0.1, sigma_process=0.1):\n", + " predictive = Predictive(\n", + " lti_model,\n", + " params={\"rho\": jnp.array(rho_true)},\n", + " num_samples=1,\n", + " exclude_deterministic=False,\n", + " )\n", + " with DiscreteTimeSimulator():\n", + " pred = predictive(\n", + " rng_key=jr.PRNGKey(0),\n", + " sigma_obs=sigma_obs,\n", + " sigma_process=sigma_process,\n", + " predict_times=obs_times,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " )\n", + " print(\"make_data shapes:\", pred[\"f_times\"].shape, pred[\"f_observations\"].shape)\n", + " # Expected: f_observations has shape (1, 1, T, obs_dim)\n", + " obs_values = pred[\"f_observations\"][0, 0, :, :]\n", + " return obs_times, obs_values, ctrl_times, ctrl_values\n", + "\n", + "\n", + "obs_times, obs_values, ctrl_times, ctrl_values = make_data(sigma_obs=0.1, sigma_process=0.1)" + ] + }, + { + "cell_type": "markdown", + "id": "94415871", + "metadata": {}, + "source": [ + "**Shape convention note:** simulator outputs include a leading `n_simulations` axis (size 1 by default). Under `Predictive`, there is also a leading `num_samples` axis. In this notebook we index those axes explicitly (for example `[0, 0, ...]`) rather than applying generic squeeze helpers." + ] + }, + { + "cell_type": "markdown", + "id": "567bd71a", + "metadata": {}, + "source": [ + "### Define the dynamics, NumPyro-free\n", + "\n", + "In the original notebook, the unknown parameter $\\rho$ was a latent NumPyro sample site with a uniform prior. Without NumPyro there is no notion of a prior: $\\rho$ becomes a plain argument, and the model is just a factory returning a `DynamicalModel`.\n", + "\n", + "One further change from the original: the exact (cuthbert) Kalman filter we use below requires the model to be declared in structured linear-Gaussian form --- `LinearGaussianStateEvolution` / `LinearGaussianObservation` rather than anonymous callables --- so we build the same LTI system with the `dsx.LTI_discrete` factory (exactly as dynestyx's own tests do)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "bb2b7dc0", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:36:37.763010Z", + "iopub.status.busy": "2026-06-11T17:36:37.762943Z", + "iopub.status.idle": "2026-06-11T17:36:37.764561Z", + "shell.execute_reply": "2026-06-11T17:36:37.764355Z" + } + }, + "outputs": [], + "source": [ + "def make_dynamics(rho, sigma_obs=0.1, sigma_process=0.1):\n", + " A = jnp.array([[0, 0.3], [rho, -0.2]])\n", + " return dsx.LTI_discrete(\n", + " A=A,\n", + " Q=sigma_process**2 * jnp.eye(state_dim),\n", + " H=C,\n", + " R=sigma_obs**2 * jnp.eye(observation_dim),\n", + " B=B,\n", + " initial_mean=jnp.zeros(state_dim),\n", + " initial_cov=jnp.eye(state_dim),\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "164c8b1b", + "metadata": {}, + "source": [ + "### Maximum-likelihood estimation of $\\rho$ via the filter MLL\n", + "\n", + "We follow the same pattern as the original notebook --- condition the model on data using a filter --- but instead of wrapping it in a NumPyro inference method, we minimize the negative MLL with `optax` (this mirrors the optimization pattern used in dynestyx's own tests, see `tests/test_filter_standalone.py`).\n", + "\n", + "We use the (cuthbert) Kalman filter: for this linear-Gaussian model it computes the marginal likelihood exactly, and its output is differentiable, so we can use plain gradient descent. Stochastic filters (EnKF, PF) can be used the same way, but note that (i) outside a NumPyro seed handler they need an explicit `crn_seed` in their config, and (ii) their MLL estimates are noisy, so the gradients are stochastic." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "6381d66f", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:36:37.765526Z", + "iopub.status.busy": "2026-06-11T17:36:37.765477Z", + "iopub.status.idle": "2026-06-11T17:36:42.189109Z", + "shell.execute_reply": "2026-06-11T17:36:42.188877Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MLE estimate: rho_hat = 0.3349 (true value 0.3)\n" + ] + } + ], + "source": [ + "import jax\n", + "import optax\n", + "\n", + "from dynestyx import Filter\n", + "from dynestyx.inference.filters import KFConfig\n", + "\n", + "\n", + "def neg_loglik(rho):\n", + " with Filter(filter_config=KFConfig(filter_source=\"cuthbert\")):\n", + " result = dsx.condition(\n", + " \"f\",\n", + " make_dynamics(rho),\n", + " obs_times=obs_times,\n", + " obs_values=obs_values,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " )\n", + " return -result.marginal_loglik\n", + "\n", + "\n", + "num_steps = 300\n", + "optimizer = optax.adam(learning_rate=1e-2)\n", + "rho_hat = jnp.array(0.0)\n", + "opt_state = optimizer.init(rho_hat)\n", + "loss_and_grad = jax.jit(jax.value_and_grad(neg_loglik))\n", + "\n", + "loss_history, rho_history = [], []\n", + "for _ in range(num_steps):\n", + " loss, grad = loss_and_grad(rho_hat)\n", + " updates, opt_state = optimizer.update(grad, opt_state)\n", + " rho_hat = optax.apply_updates(rho_hat, updates)\n", + " loss_history.append(loss)\n", + " rho_history.append(rho_hat)\n", + "\n", + "loss_history = jnp.stack(loss_history)\n", + "rho_history = jnp.stack(rho_history)\n", + "print(f\"MLE estimate: rho_hat = {rho_history[-1]:.4f} (true value {rho_true})\")" + ] + }, + { + "cell_type": "markdown", + "id": "fe28231e", + "metadata": {}, + "source": [ + "### How did the optimization do?\n", + "\n", + "In place of the original notebook's posterior plots over $\\rho$, we plot the optimization trace: the loss and the running estimate $\\hat{\\rho}$, which should converge to a value near $\\rho_{\\mathrm{true}} = 0.3$." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "10c6dae4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:36:42.190203Z", + "iopub.status.busy": "2026-06-11T17:36:42.190128Z", + "iopub.status.idle": "2026-06-11T17:36:42.427129Z", + "shell.execute_reply": "2026-06-11T17:36:42.426896Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA/MAAAFpCAYAAADQnnivAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAAfIBJREFUeJzt3Qd4VFXawPE3vQABQkjovXekiQ1FBFxdsYPuJ4iKBV17wwIi7mLFimCjrLrKupbdtaCIYANBKSJIF6QmoaWQkH6/5z2TO07CJKRMMu3/e56baWfu3Dm5c89972khlmVZAgAAAAAA/EaotzcAAAAAAABUDsE8AAAAAAB+hmAeAAAAAAA/QzAPAAAAAICfIZgHAAAAAMDPEMwDAAAAAOBnCOYBAAAAAPAzBPMAAAAAAPgZgnkAAAAAAPwMwTwAtx555BEJCQkhd4rNmzfP5MfOnTvJEwAAfJiW13oeAwQ6gnmghoK+6Oho2bt373Gvn3nmmdKjRw+fyPfs7GxT2C1dulR87SJCaGio7N69+7jXMzIyJCYmxqS55ZZbnM9rkK3PPf300+Wuv02bNnL++efXyLYDAPyzzLYXLbs7depkypeUlBQJZMuWLTNlblpamvijTz/91OcCdl88r0JgI5gHakhubq48/vjjPp2/WuhMnTrVbaHz0EMPybFjx8RboqKi5J133jnu+Q8++MAr2wMACFyPPvqovPnmm/LSSy/JKaecIrNmzZLBgwebcjKQg3k9B/DnYF633x09f9HzGF86rwJqAsE8UEP69Okjr732muzbt88v8zg8PNzUUHjLn/70J7fB/D//+U8577zzvLJNAIDAdO6558r//d//yXXXXWdq62+//XbZsWOH/Oc//6nWeouKiiQnJ0eCiS9cANHzFz2PAQIdwTxQQx544AEpLCyscO38W2+9Jf369TNNyOPj42XMmDFum5nPnDlT2rVrZ9INHDhQvv32W9N0XxdbXl6eTJ482ayvfv36UqdOHTn99NNlyZIlJZqlN27c2NzXq8h2E0O7yVrpPvPaNeCss85ye6LSvHlzufTSS0s899xzz0n37t1NgZqUlCQ33HCDHDlypML5d+WVV8ratWtl06ZNzueSk5Plq6++Mq/5ipdfftl8T21J0KxZM7n55puPq+XYunWrXHLJJdKkSROTHy1atDD/3/T0dGeaRYsWyWmnnSYNGjSQunXrSufOnc0+BACofUOHDjW3GtAr7cKlNfaNGjUy5a+Wr//+97+Pe5/dBeztt992lg0LFy6s0jree+896datm0mrrQR++eUX8/orr7wiHTp0MOWJlv3uxnJZsWKFjBw50pwDxMbGypAhQ+T77793vq5l/D333GPut23b1nkO4LquipyX2F0HV61aJWeccYb5rBOVXVqu6zmDrlO/Q//+/eW///1viTT5+fnm3KRjx44mjeaZlpFaVqqrr77anA/Z+WUvrnno2gTfPqfZsmWLuWij+aLnQA8//LBYlmW+16hRoyQuLs6U1c8880yJ7fHEeVVFvztQGQTzQA3RwnHs2LEVqp3/29/+ZtJqoTVjxgxTI7B48WJTMLoGhtrsTwt4DQaffPJJU5BceOGFsmfPnuP6lb/++uumkH3iiSdMQXLgwAEZMWKECZCVFji6PnXRRReZ5oW6XHzxxW63cfTo0fLNN9+YgNrVd999Z76fFvI2Ddz1JOHUU0+V559/XsaPH29ObPTztYCuCP3u+j21Jt62YMECE+j6Ss285qsG7xrEa8GvAbueZA0fPtz5PfUEQL/3Dz/8IH/961/Nycf1118vv/32m/N/u2HDBtOPX7tmaFNPXdcFF1xQ4sQLAFB7tm/fbm41iFRalvXt29cco//+97+bWt/LLrtMPvnkk+Peqxed77jjDlNu6vt0rJbKrkMv1N91110ybtw4U9Zs3LjRlBNahrzwwgsyceJEU84uX75crrnmmuM+X8tQPReYMmWK+Swtb/QCxcqVK00aLeuvuOIKc//ZZ591ngPYwWhFz0vUoUOHTMsGbZGoF/LdXfi3aXl38sknm+9z//33m/JOA2M9l/nwww+d6fQ7a0Cs69KuDw8++KC0atVKVq9e7TzPOOecc8x9e9t1ORH9n2iFg1a0DBo0SB577DGzzbourZjQcya9UHL33Xebcx5PnldV9LsDlWIB8Ki5c+da+tP68ccfre3bt1vh4eHWrbfe6nx9yJAhVvfu3Z2Pd+7caYWFhVl/+9vfSqznl19+Me+1n8/NzbUaNWpkDRgwwMrPz3emmzdvnvk8Xa+toKDApHd15MgRKykpybrmmmuczx04cMC8d8qUKcd9D33O9RCxefNm8/jFF18skW7ixIlW3bp1rezsbPP422+/NenefvvtEukWLlzo9vmy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DgCAoGH3l2fwOwBATQTzu3fvlpYtW8oHH3xQZppFixZVdfVgRHsAAIK8Zp7B7wAAZaty260uXbqYkWqzs7OrugpUoJm92nOEPAYAICjkZYuk/Oq4T808AKAmgnmtdf/888/NnK/z5s2r6mpwgmb2imb2AICaorPOvPXWW/Lee+/Jtm3byGhvS/5FxCoUqZMoEtfc21sDAAjEYP6UU04x88hPnz5dHn74YenXr598++23nt26IGfXzOto9jqgIAAAnvTCCy9Iu3btZOLEiXLddddJ586dZeDAgbJuXfG0aPBeE3utlQ8J4T8AAChTtYdIHTt2rGzevFnOO+88Offcc+XSSy+VHTt2VHe1cKmZz8orlLTsfPIEAOBR06ZNk/vvv1/S0tIkPT3dlOennXaaDB48WL777jty25uD39FfHgBwAh6b72T48OHmqv6HH34o3bp1k3vvvVeOHj3qqdUHpeiIMEmsF2Xu76bfPADAw7ScvvrqqyW0ePqzDh06yIwZM2TSpEly1113kd/erpkHAKAmgvnZs2fLtddea6afq1+/vpx99tmmmf2NN94ozz//vPz0008mqNdbVF2r+Fhz+/shBsEDAHiWluHLly8/7vnLL7+cpvbecCxN5FDxuAXUzAMAampqur/97W8yaNAg08z+5JNPNn3mY2IczcLV9ddfL3//+9/NFf/169dX9WOCXqtGsfLT70dk12GCeQCAZz3zzDNy8cUXS2RkpAngQ4r7aOuYODrALWrZ/rWO2watROo0IvsBADU3z/yJaM29Do6H6tfM76JmHgDgYdo/Xmek0VZ1f/3rX6VPnz6Sl5dnLsK/+eab5Hdto788AMAbfebdSUxMlK+++qomPyJ4gnlq5gEANeBPf/qTbN261QT1GsxHRESY588//3xp3LixDB06VG6//XbyvjbsW+O4pb88AMDTNfM6F22rVq0qnH7fvn0yZMiQynwESmndiGAeAFCzoqKiTFCvi2sLvLVr18qaNWvMglpsZt+sL9kNAPBszfyAAQPkhhtukB9//LHMNDq1zWuvvSY9evSQ999/vzKrhxsti2vm96Ufk7yCIvIIAFArWrZsKX/+859l8uTJZqYa1LDswyJpuxz3m/QiuwEAng3mf/31V6lTp46cc8450qRJEzO3/IQJE0w/u//7v/+Tk046yTStnzNnjjz55JNy6623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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "fig, axes = plt.subplots(1, 2, figsize=(10, 3.5), constrained_layout=True)\n", + "axes[0].plot(loss_history, color=\"C0\")\n", + "axes[0].set_xlabel(\"optimization step\")\n", + "axes[0].set_ylabel(r\"$-\\log p(y_{1:T} \\mid \\rho)$\")\n", + "axes[0].set_title(\"Negative MLL loss\")\n", + "axes[0].grid(True, alpha=0.3)\n", + "axes[1].plot(rho_history, color=\"C1\", label=r\"$\\hat{\\rho}$\")\n", + "axes[1].axhline(rho_true, color=\"k\", linestyle=\"--\", label=r\"$\\rho_{\\mathrm{true}}$\")\n", + "axes[1].set_xlabel(\"optimization step\")\n", + "axes[1].set_ylabel(r\"$\\rho$\")\n", + "axes[1].set_title(\"Parameter estimate\")\n", + "axes[1].legend()\n", + "axes[1].grid(True, alpha=0.3)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "83e1b471", + "metadata": {}, + "source": [ + "### Latent-state recovery\n", + "\n", + "As in the original notebook, we can also recover the latent states. Here, we rerun the filter at the MLE $\\hat{\\rho}$ and read the filtered state distributions from the `ConditionedResult`; this corresponds to a \"filtering\" distribution.\n", + "\n", + "What is \"smoothing\" and \"filtering\":\n", + "- The filtering distribution at time `t`:\n", + " - $p(x_t \\mid y_1, \\dots, y_t, u_1, \\dots, u_t)$,\n", + " - only uses data up to the present\n", + "- The smoothing distribution at time `t`:\n", + " - $p(x_t \\mid y_1, \\dots, y_T, u_1, \\dots, u_T)$\n", + " - uses all available data.\n", + "\n", + "Unlike the original notebook --- where the uncertainty band came from the spread of filtered means across posterior samples of $\\rho$ --- here the band is the filter's own 95% credible interval at the single point estimate $\\hat{\\rho}$." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "89c5ff63", + "metadata": { + "execution": { + "iopub.execute_input": "2026-06-11T17:36:42.428299Z", + "iopub.status.busy": "2026-06-11T17:36:42.428061Z", + "iopub.status.idle": "2026-06-11T17:36:49.708410Z", + "shell.execute_reply": "2026-06-11T17:36:49.708200Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAscAAAH/CAYAAAC7N3BzAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnQd4HNXVho+6tOq9WLJkuTfANtX0QCghdEhI6BAISWihJDbN2BRTQgmE+kMgtEBMMRBa6L3j3i3L6mVVV6uuXf3Pd3fuaLSardqu8/IIWavV7uyUO+ee+53vRA0PDw8TwzAMwzAMwzAUzfuAYRiGYRiGYWxwcMwwDMMwDMMwChwcMwzDMAzDMIwCB8cMwzAMwzAMo8DBMcMwDMMwDMMocHDMMAzDMAzDMAocHDMMwzAMwzCMAgfHDMMwDMMwDKPAwTHDMAzDMAzDKHBwzDAMwzAMwzAKHBwzDMMwDBMx3HPPPfT2228HezOYMCZqeHh4ONgbwTAMwzAMM15WrVpFF1xwAcXFxdGOHTsoOzubdyrjMRwcMwzDMAwT9vT399Ps2bPpjjvuoFdeeYVyc3PpH//4R7A3iwlDWFbBMAwTIL7//ntavHgxJScnU1RUFK1du5aefvpp8e/du3erz9N7LJS5+eabxfYywdnvLS0tvOuJ6P7776d58+bRr371K3rggQfoP//5D23evJn3DeMxHBwzHiFv2j/88MO499xXX30lBveOjg6/HwV/vNd4XzOQn58JPoODg3T66adTW1sb3XffffTss89SaWmpW387kc6ViXBdebqNwf5MctzH1xdffDHm91BnlpSUiN//8pe/9PieoX19va9vvvnGre3861//Sm+88Yb4d35+PjU3N9OcOXM8/rwMw8ExEzQw4C9fvjxgwbGv32u8rxnIz88En4qKCqqqqqJrrrmGLr74YjrrrLMoMzOTzj77bOrt7XUaKE+kc2UiXFeebmOofKbExER64YUXxjz+6aefUm1tLSUkJIzr9VesWCEmjfZf06ZNG9frMoynxHr8FwzDhB3d3d1iKT+SCfXPiCwWyMjIGPV4TEyM+AoGob7PmNDiF7/4hSh4g2QhNnYkfEDAvGjRonHLO4499ljae++9fbClDDM+OHPM+Bxkx/74xz/SzJkzKSkpSVQLYzlZq5/EEuG1114r/j1lyhR1+Uw+p66uTlQcY2kM2Yi5c+fSP//5T4eau507d9J5550nAo/09HQ6//zzqaenx6330qOrq4uuvPJKKisrE++fl5dHP//5z+mnn35y+Zq++Pye7ANH+wRau9/+9rciO3nQQQd5/Lp43oUXXkhFRUXiedjOP/zhDzQwMDDqeWvWrBE3tbS0NEpJSaEjjjhi1DLoyy+/LLYH2SV7HnvsMfG7jRs3erR9jj7jxx9/LB5/7bXXxrwXbuD43ddff02BBufmoYceKv6NcwHbcdhhh7mlL/bVueKr8wLL6vvss4/IIk6dOlUcQ3cJl+vK1XY6wlfbqMWd5yOj7Gj80+LtmCL5zW9+Q62trfT++++rj2E8wDWOcyoUwBiAQB2TPnz9+te/ps7OzmBvFhNmcOaY8UvREZYBzzjjDCouLhaD+COPPCKCAdyYDQYDnXLKKbR9+3b697//LfSXOTk54m9RXdzU1ET777+/uAFceuml4rF33nlHBGomk0nctOxBAQZuHCtXrhQ3sCeeeELc0O68806n7+WISy65RAz4eH9o1nBDQFCwZcsWWrhwodPXxLaO5/MDb/aBPbgpT58+nW6//XahCfTkdevr62nfffcVN11IAGbNmiVurNgnuOnGx8eL523atIkOPvhgERj/5S9/EfZJCJbwWREM77fffnTccceJoBnFMTJAlLz00kviBo0iGm8+t/1nxPtC+/j888/TySefPOq5eAzB3AEHHECB5ve//z1NmjRJbOfll18ugksEKO7g63NlPOfFhg0b6KijjhK/R9A2NDREy5Ytc/uzhMt15Wo7/TX2eXP8XY1/El+MKZgs4PrBtmBCDPAaCD7xmZFRHg94HfvsM7bXXTs2fG5cawji8bk++eQTMe5gvz/11FPj2jZmggGfY4Zxl6eeegp30+Hvv//e4XN6enrGPPb111+Lv3vmmWfUx+6++27xWGVl5ajnXnjhhcOFhYXDLS0tox4/44wzhtPT00e9/rJly8RrXHDBBaOee/LJJw9nZ2e7fC9H4H3+9Kc/OX2Oo9cc7+f3dB/YI/fJb37zG69f95xzzhmOjo7WPc5Wq1X990knnTQcHx8/XFFRoT5WX18/nJqaOnzIIYeoj2Fb8vLyhoeGhtTHGhoaxHusWLHC4+1z9hmXLl06nJCQMNzR0aE+1tzcPBwbGyv+Llh8/PHHYptXrVqle01pzwP7x3xxrvjivMDxTkxMHK6qqlKfs3nz5uGYmBjx2pFyXbmznXr4Yhv1cPR8d8e/8Y4p2nH/H//4h7i+5fNPP/304cMPP1z8u7S0dPi4445z+LeuXl/vC9eyO2zZskVc4w888MCoxzEO4ZwdHBx063UYBrCsgvE5WE7UVugj64KCCiz5uVqWRCYL/pTHH3+8+DeyCPLr6KOPFpkFvddApkcLspl4X2REvAHb+u2334oMaiA//3j2gat94u7rWq1WWr16tXienv5PWnZZLBb63//+RyeddBKVl5ervy8sLBRLrMi0yf2PpU1obpHJkSAzh/fC77z93PafEZxzzjnC7xSvr81QI8uJIrhIwhf7zN3XwPF+7733xPGePHmy+vfwlcXzIum68nY7x7uN3uJq/PPVmCKz1Cgg/e9//yvkJ/juK0nFQw89JCQb2i9kpt0BKxl77LGHyIprOeSQQ6ivr0+4xDCMu7CsgvE5GDixvIdlLCzFa5swutJ+GY1GsZT/+OOPiy9nhU1atDdrAD0laG9vF0v+nnLXXXfRueeeK5booV9DIQqCLm0Q6I/PP559YA+WWb15XTwPN1UpdXC2nZBYQF9pDwImBL41NTVCNnHMMccILSSCVGiSAf6911570YwZM7z+3PafEUACAtkCZBRYWgX4N5aUnVW9QztpfwPF0jOCQk8eD2RxnS/2mSfnBc5tSDLswTngTrvecLmuvN3O8W6jt7ga/3w1pshz/MgjjxQaflz/uA5OO+00H3wKElIubwryMPHF+bd06dIxftsoOsVj3twHmIkLB8eMz7nsssvEzQEaNujTEBRhcIImDQGTM+TvkeHDzUkPZAfscRSQeNsdHdkRZF9Q2IXs6N133y30e6+++qqqtfPH5x/PPnCWxfLkdf3RUR7FP8g4Yn8+/PDDQv/45ZdfCt2rp9vn7DNKEMhcccUVwl4KWWQUCLrqlAWt6OGHHz7qscrKSqEb9eRx6DIDhS/2mbuv4c65GynXlbfbOd5t9BZX45+vxhQJMsUXXXQRNTY2iv1h78ASaJD1RhYbk2170Ghnzz33FAWkDOMuHBwzPgfL2RiA77nnHvUxLGvZe3TqddRCViI1NVVkI5Cd8BXedO+CPACV5/hCVgWFOLfddpt6c3T0muP5/P7cB+6+Lm6kyLJoHSQcvR4KXbZt2zbmd1u3bqXo6GiReZNAPvGvf/2LPvzwQ1HYhBu3lFR4sn3ugGDkqquuEoVDyOahUFD7XnrgBqqtwgcFBQUiwPHkcX/gz3PF3dfA7xFY79ixY8zv9M6BcL+uXG2nP7bREePtPujrMQXFrih8w6QTK0DBBgEwsLclbGhoEPKuG264IUhbxoQrHBwzfsli2GcfH3zwQTEwa5EDmfbGgb899dRTxZIdgjP7pX0sDzpzmXCE3ns5AttpNptF8CNB5TcszZCFdPWa4/n8/twH7r4uglpkeZ977jnR1cp+mROfDTdrvB6cC15//XWRRZUZU2SF8R6wCdMuZeKmnJWVJW6mCI6xhKpd4vfl50ZFP4IYfAYEJ5B1yCp/R2ApWi9wQMbJk8f9gT/PFXdfA8+DPhV69OrqanUpH8cSWuRIua7c3U49xruNjvD0+Xrb5csxBe4zcOHAdQ8dc7BZv369+A6HHGiMpdQC1pM4jgjkGcYTODhmvALemO++++6Yx7GUjfah6GqEQQk2SPCV/eCDD8bY8UDLB66//nqR6UN2DwPtHXfcIbwqYQOGpTu8BrSdWDrD63hTWOHovfQaIGB5DjZM0NEhm4gbAd4XNk3ajJCj1xzv58c2+WMfAHdfF3IHLCfDeg1WbtAQIwuDBgDIxMhl1FtvvVVkTxEII8OGxgCwckMQAd2mFnw+2FK9+OKLQgf4t7/9zevtcwdIK6QW8pZbbqFwxt/niruvgS5tuO4hOcDxRgCC4A+6chmgOCJcrit3t1MPX2yjHo6e7wm+HlMcyTO8uWdIUHyHVSd7Fi9e7FTvDYtBfB5k9jG2IOuPcQbHDNl8d60GGUaFTTsYT3BmuYOvmpqa4fb29uHzzz9/OCcnZzglJWX46KOPHt66dauw+Tn33HNHvd4tt9wyPGnSJGHppbUqampqElZKJSUlw3FxccMFBQXDRxxxxPDjjz+ua2VkNBp1t1NrfeTovezp7+8fvvbaa4f33HNPYVmUnJws/v3www+Pea7ea/ri83uyD+xxtE88fV3YdcHSLTc3V9gplZeXi7/D/tHy008/ic+Iz2owGISt01dffaX73u+//77YtqioKHGueLt9rj4jwHZmZmYKm6re3t7hYDMeKzdfnCu+Oi8+/fTT4UWLFgkLP5wTjz76qPrazgiX68qT7bTHV9uoh97zPRn/3PnsjnDHjs2VlZuze4ar5+D3zsB1fsMNN4jPgc+G8eqAAw4Y/vDDD53+HcM4Igr/GwmVGYZhIgNkNbEUjgzbk08+GezNYRjGD8ARBxIfSEbQ/INhfAH7HDMME5FAGwstJeQVDMNEJpBUAEh7GMZXsOaYYZiIAs0boH+FznjBggVjWlYzDBM54FpHwaGe3zrDeAtnjhmGiShQRY8qdTgMPPPMM8HeHIZh/Jw5njp1qvBSZxhfwZpjhmEYhmEYhlHgzDHDMAzDMAzDKHBwzDAMwzAMwzAKHBwzDMMwDMMwjAIHxwzDMAzDMAyjwMExwzAMwzAMwyhwcMwwDMMwDMMwChwcMwzDMAzDMIwCB8cMwzAMwzAMo8DBMcMwDMMwDMMocHDMMAzDMAzDMAocHDMMwzAMwzBMOAbHjzzyCO2xxx6UlpYmvg444AB65513gr1ZDMMwDMMwTIQQNTw8PExhwptvvkkxMTE0ffp0wmb/61//orvvvpvWrFlDc+fODfbmMQzDMAzDMGFOWAXHemRlZYkA+cILL3T5XKvVSvX19ZSamkpRUVEB2T6GYRiGYRgm+CDk7erqoqKiIoqOdiyeiKUwxWKx0KpVq6i7u1vIK/To7+8XX5K6ujqaM2dOALeSYRiGYRiGCSVqamqouLg4coLjDRs2iGC4r6+PUlJS6LXXXnMY8K5cuZKWL18+5vGffvpJ/G0gQLbaZDIJjbSzWQoTXvBxjUz4uEYmfFwjEz6ukYfVzzGT2WymhQsXCgVBRMkqBgYGqLq6mjo7O+nll1+mJ554gj799FPdANk+c4wdXlJSQu3t7WLHB+pAG41Gys3N5eA4guDjGpnwcY1M+LhGJnxcIw+rn2MmxIGZmZkihnQWB4Zd5jg+Pp6mTZsm/r1o0SL6/vvv6e9//zs99thjY56bkJAgvuzBDg9kFhf65kC/J+N/+LhGJnxcIxM+rpEJH9fII8qPMZO7rxkdCbMMbXaYYRiGYRiGYbwlrDLHS5cupWOPPZYmT54sqg1feOEF+uSTT+i9994L9qYxDMMwDBNhQHk6NDQkTACYwCQ8BwcHRV3ZeDLHcXFxwvp3QgTHzc3NdM4551BDQwOlp6eLhiAIjH/+858He9MYhmEYhokgUOOEeKOnpyfYmzKhJiNWq1UkQMdjuYu/hRuFt+YLYRUcP/nkk8HeBIZhGIZhIhwEaJWVlSL7CE9c1Dtxf4TAZepjY2O93t94DRT11dbWiqZx3mSQwyo4ZhiGYRiGCUTWGAEyHK4MBgPv8DAKjgHcLnbv3i0kGt4Ex2FfkMcwDMMwDOOKQYvV453ELlPhyXiz/BwcMwzDMAwT8fT0c1Ed4x4cHDMMwzAME/H0DA4FexOYMIGDY4ZhGIZhIpr27gF6f3MTDXkhrYg0Tj/9dPr6668pFDj44INF4WOowcExwzAMwzARzZ3vbqWbXt9E72xspInMd999R21tbXTAAQdQKHD11VfTsmXLKNTg4JhhGIZhmIimusVEFnM7ba9v99pFoWdgyK9feA93+N3vfkdLliyxfa7qapo9ezZ9/vnndNlll4lM7O233+7wbx977DH67W9/O6pw7bbbbqP99tuPysrKaPXq1bRy5Urae++9hQ0aGq1Jvv/+e/rZz34mfrdgwQJatWqV+rszzzxTPI7+E8cddxw1NjaOeg9s07777ktTpkyhp556Sv0dnvvOO+9QZ2cnhRJs5cYwDMMwTMSybt06+vihv1Kb0UiPfVtERxb9nfbcc0+PXqN30EJzbvJvN97NK44mQ7zrsOyWW24R2//rX/9aNEb7+9//TklJScL+DEHyaaedRk1NTZSfnz/mbxHs/vnPfx71GBplfPvtt/Thhx/SiSeeSP/4xz/ohx9+EMHvtddeK4Lijo4Ouvjii+ntt9+mwsJCamlpoYULF9LixYtp0qRJdP/99wv7NHDHHXfQzTffTI8++qj6HgkJCSJrvXXrVtpnn33o7LPPFtuLTnbz588X2/3LX/6SQgXOHDMMwzAME7F+xTfccAOZGmsoKjaOmmt3i5/xeLiC4PSSSy4Rgeny5cvpqKOOEsEtsrrg0EMPpR9//FH3b9EYwz5oRpANkPnt7u6mM844Q/yMTO+OHTvEv7/66ivatWsXHXvssbTXXnvRkUceKR7ftm2b+P7CCy+Iv583bx498cQTtHbt2lHvgcwymDVrlgiKtZnlgoICsV2hBGeOGYZhGIaJSKCvRRY1JjmDhmMSKSYhVvyMxxGUuUtSXIzI7PoTvIc7IGv7xhtvUFpaGk2ePFk8hswuAlOQmpoqftYDDU36+vpGPZaYmCi+y2YZiZqf0ZADQPIxd+5cESTb88UXX9ADDzwgivzy8vLEtt10002672H/ugDbg8x3KMGZY4ZhGIZhIpKsrCyRKR3oaidrfzf1dLaLn/G4J0A3C8mDP7/caVwBbe4vfvELWrp0Kd19992ioA1kZGSQyWQS/+7q6hI/6wFNsMz2esLixYuFq8QHH3ygPobsMDLw7e3tIiDPzs4WP0PX7AlbtmzxWObibzg4ZhiGYRgmIomPj6dbb72VYrOKaHhokGIyC4VmF4+HGz09PUKXC+0vpBBnnXWWCIhRRAcJxMcffyye99lnn9GiRYt0XwN65Pfe81w7nZmZSW+99ZYorEMgO2fOHFEUiBbbxxxzDM2cOVN8oSAQsgt3QYtni8UScsFx1LC75ZERAE6i9PR0MfPCckQgwInT3Nwslhq4DWXkwMc1MuHjGpnwcZ3YxxVto6cteYOsvWaKTkqhjbccR6mJcU5fG0v9yJTCXUErCQhl/vSnP9H69evp6KOPFrpqPcxms8gCQwKRnJxMwWbJkiU0bdo04cABEJJCcgFd8nhaQDs6fu7Ggaw5ZhiGYRgmottGR8XEUUxKpvjZ2NXvMjgORx566CGXz4EzxX333ScCR6lRDiZFRUV0wQUXUKjBwTHDMAzDMBGLeWB022gEx+W5KTRROeKIIyhUuPzyyykUYc0xExAmkHqHYRiGCSG6++2CY3N/0LaFCQ84OGYCQv8Q97NnGIZhAo/ZPjju4uCYcQ4Hx0xAGLBwcMwwDMMER3OshYNjxhUcHDN+Z8hipSELyyoYhmGYwMOZY8ZTODhm/M69726i3z/2AfX0ju7KwzAMwzCB1hw3mfhexDiHg2PGr6xbt45uveoieuPuK+kXJ54sfmYYhmGYQNGjuFXI9szNrDlmXMDBMeM30Eby+utvoN6WWoqKjaPdFTuFMTkeZxiGYZhAYFY0x2U5tqYXLexWwURScLxy5UraZ599RA9vdMQ56aSTvOoRzgSGtrY2amhspBhDOkUnJFN6Vg41NTWJxxmGYRgmkLKKsmyD+N7ePUgWa2TVwXzyyScetW0O5Ha9++676s/19fWixXSoE1bB8aeffiraI37zzTf0/vvv0+DgIB111FHU3d0d7E1jdMjKyqLs3Dyy9HSStb+b2lqMlJ+fLx5nGIZhmEDQrcgqJmcZCA2JLcPD1N7j3xVMrJA2NjZGxErp0NBozfZ4gmN0xPv8888p1AmrDnnaHQyefvppkUH+8ccf6ZBDDhnz/P7+fvGl7akt+7HjKxDgfdAAI1DvF0qgN/ofrlpKX/zharJ0t1PBlDJasWKFeDzc98dEPq6RDB/XyISP68Q+ruY+W3CXmhhLmYY4ausZpKbOXsoyxLl8bfnlCaitufHGG8VKKRJCt9xyC+25557kK9577z267rrrRNCamZlJDz/8sNhG/HzOOefQTz/9RAkJCfTEE0+IbPKOHTvo/PPPJ7PZLD7XCSecQLfeeqtIMGI7P/74YxHEz5gxgx599FHxmnh+VFQUVVRUUHNzM5111lnU0NBA//jHP8Q24LVKS0tp69atYhLwxz/+kXp6eqivr49+85vfCAnl2rVrxetZLBYRJJ988sli+xYsWEDt7e0OP8v06dPF8y+77DKRZf7qq6/E7xHz7b333mQ0GtXtwTYuWrSI/vnPf47aR/K42cd77t6zwyo4tqezs1N8d5SJhAxj+fLlYx7HjsUBDAQ4ENhOHKTo6LBK1PuEpKwCyj15KVl7zXTOsXOosLBQXGjhzkQ/rpEKH9fIhI/rxD6ubSbb6rJ1oJcykmJEcLyztpmyYxzHAQgc8foIyjzJnNpqba6nnTt3Um5uLm3fvl0Eii+99BLFx8fTeMH988wzzxSr5/Pnz6cXXniBTjvtNHrggQdo06ZNdM8999CTTz5Jq1atojPOOIM2bNhADz74IB177LH017/+1bY/2trEZ7rzzjspKSmJvvzyS/H4bbfdJrb9gQceEJ8dwS2CVEhZa2pqaP/99xd/g8Abn+fQQw8VAS0SXkhe4vHe3l6RrDz88MNpv/32o4suukgcI2wX2L17t/iO93f0WZDwxO8ReD/22GNiex5//HGxbW+99RY988wzIjDHv7WfRwt+xmdobW2luLiRSVBXV1dkB8f40FdeeSUdeOCBNG/ePN3nLF26lK666qpRmeOSkhJxwqalpQVsOzGzwXtOxCAqto0oKiaOYlIyKTE1XWT6I4GJflwjFT6ukQkf14l9XIeiqsT3guwMKszooV2tfTQYk+T0foQEGgIpBH74cpeWlhaRgEPGOD09XWwXgkDEHwUFBTReEDgikET2FSATe8UVV4jsbVlZmZCaAmRvkc1FdhVB7F/+8heR2cW/jzzySLFdb775pghcV69erQb2eI3Y2Fjx+9NPP10Ev2DKlCniPd9++23x+LPPPkvXXHONeC4mEtgGBNP4OwTSCMoRn+FnHCO5D7XfnX0W/H7atGm0ePFi8Tu81n333Scex2MImBHsIxA/5phjxhwj+Rmys7MpMTFRfVz774gMjqE93rhxI33xxRcOn4NZDL7swQ4LZECDE8Pd97Rah0U3uUTFciZSqoRB36A1ogJJT44rEz7wcY1M+LhO3OPaM2C7D6UmxlF+mi04aukecPo3MqiTX+6CYAyBMaQMAIExZAJ43JPXcYR8DfvX0ntc7htkYxFcIkP70EMP0d///ncR5CLjjqyyDKjtSU1NHfV6F1xwgSptQGYc2Wj8HhndnJwcWrNmjQhKTznlFCFp1e4/++3Te8z+syCQlf/G6yIbjJ8RHCMQ/+CDD+i1116jm266Sbx3TMxI3CRf3/7ccPd+HZZ39UsvvZT++9//Cp1McXExRRJtPQPUNzi61WU409U3qP67J4I+F8MwDBNeSZrkhFjKTUvwawtpSCeg50VAjOwzvuNnX0gqAKQNyMoiOQhefPFFmjRpkviCZAFxEXj55ZdFkI4YCYE6/o3M7F133SVMDQAcv5CNRUYZ4DukGY7A87///nshWYXmV2ZroR/G++BnOIghCJdglV5KYD35LM6orKyklJQU+tWvfiWCe0hXoIH2JWGVOcYsBwJtzBSgg0GaP9LABZuV7JuLKBQwKYUQoFeZvTMMwzBMoDD325I0yQkxlJtiC46b/dglD8V3r7zyitDCoibKV4ExgITk+eefF4GuLGKDvhgZ6rlz54rM7uWXXy7e89///rfIniJQfu6558RjkKKgSA5AloAML7TBMkOLx+bOnav73liJR0CKorktW7aoj0NTffbZZ9O//vUvmjp1Kv3sZz9Tf4ciPEgwUBiIjDK229ln+c9//uMyw47479577xWZYvzd3XffLSQsviRq2NMyzCAC/QwE26+//jrNnDlTfRw7BaJyV0Dzg+diFhNIzTFOWmib3Enn/29DDWVGD9Ke04t9ekEFi5XvbKHHPt0l/v2rvYvprtN8V7EbTDw9rkx4wMc1MuHjOrGP66Jb3qfW7gF698qDaVtjF13x4lrab0oWvfT7Axz+DbK+yFAiCeeuTpUZP9J1A1no8chQHB0/d+PAsLqrP/LII+IDHXbYYcL1QH6hajIS+OKbH+isM35Nhx11LJ148ikR0Wq5S5s5HmTbM4ZhGCY4PsfJ8bGUm+pfWQUTGYRVcKz1HNR+nXfeeRTuoEr0L0uvo/bGarJEx9KWrTb7l3A3EDf1jmiOe5UBaiISSYbwDMMw4cKQxSqKwaXmOE8JjrmFNBMxwXEkA21SVW2D2mo5JSMrIlotazPHsmJ4ooEVgJNPOUUYr5966qkRsSLAMAwTDnRr7js2zXGiWg/TP+T6nhRGylPGh8eNg+MQISE5jYYS0tRWy60R0mpZmzmeiMExMsVYAdi5YwfFJySIquFIWBFgGIYJB3qUFcvYmChKiI2htKRYiouxaVlbzI7HYdk4Qjo5MOGFvMdq7d0i1q0ikmnsGqL4/X5DcZ8+K1otZ5WW+tT+JViYNFZukWRR5y7I/GMFICc3l1LT0ik6KkpdEfCFITzDMAzjmO7+Eb0xQJFXdnICNZr6hO54UoZ+MT+CqoyMDLWjq8Fg8IlPMeP/gjwUaqIRC46ZJw1ctHBwHCJ8usNIMblT1FbLxx0826e92EPBym0iZo6R+ccKwIbNW4XurbuzTfhehvuKAMMwTHh5HI9kEHNT49Xg2BkygSEDZCYwwTGCW9mExVvw95MnT/b6NTg4DgGge/qmolX8Oykxgfpi4sjYa4m8JiATsCAPmf8lNy6jo8/6E7XUtdLhC2ZExIoAwzBMONCjZI5TEkbCnbxU6I5NLoNjBFZwxIJVHFokM76XPsCBDNZq8p6IwLi1tVV0FByPTSpebzx/z8FxCIALdH2drYPM4TPz6J2NjWQ0hb/NzKCmSniiZo5Bftksyj7RtiLw9O0nU3ZacrA3iWEYZkJglrIKbXCstJBu7nKvEQgkFt5qVxl9UJh+/fU3UHNzk1hdRdIIq+UIjqH3hjdxMHsIcEFeCPBjVTu1dQ+IIoHj9ywSjxnN4R8ca50qpOZ4Ilb+YnCOiomjmJRM6uifeJ+fYRgmFDyOJex1HBqF6jt2bBdBcCgWqnNwHAIejF/sbBH/nlWQSnOLbB1bWs0DYR9ISkmFVPxYhyEhsU7YghDQ5MeWpQzDMIz9+KunOZYtpMM/CRXehep5QlIB2UqoWddycBxkkDFeX2OTVOxTlkUF6bblniHrMHX0hLfGydRrCwqzU0b0tb0BklbYJB2WkFrWA9yViWEYJghuFRpZRW5KgkeyCsa3oCA9IzuXahsaqaWtXRQ8hpp1LWuOg0xlSzftbDaLfx82M0/1YURgCWlFZnJ82GeOMwzx1Nk7SIOWYeoZtFCmHwa/uo5eEXj3Dtq+LJZhiouNpgOnZlNsTHDngGaNvIQzFQzDMMGzchslq4gA+WI4Eh8fT/NOuJi+uOd2GmrupIWzpquF6tAchwIcHAcRyCY+22Eky/AwFaQl0vxJ6eLxnJQEW3Dc1U8z8lMp3G3c0pPiyBAfKwJkf7SQRva9unWsUfvgkJWq2npoam4KhYLmDbCsgmGYiQLG5fz0BJH0Cb6Vm9atImGUfJH9iwOPobBcWNeev3cuXXfyPiHn4MSyiiDS3jNI6xRJxR7F6SKIHLGZCf8lH9kAJDUxlpLibYNj74DvZ4XO5BMYnN1pERooWQW8NRmGYcIRFEw1Nja6VTiFZMhOYxcNBLnORFqIpmg0x0hAAdTAdGnGZyaw8U9UTBxNnlQUcoEx4OA4iDSb+miDYuG2eCo8/Wyla/lpypKPCw/GcHGrSE2MI0NcjN+8jmEXZx0epvaeAdrR1EVf72qlN9fX0wvfVVNNW4+QrgQTLshjGCYSrLdOPfVUOvrY48R3/Oys0HxjXSf19w1QdV19UF0IZHICq5cSJGtkgV6432fDlY4e2zmRmWxLCoYaLKsIImtrOsTsOiE2mg6aljtmySfcL1pTry1znKbJHENz7EsgU7j8+e+osq6JhhNSxExUC/TchRmJNDnLMGpwnCia44bOXipM12+PykwMUJw6ZBlWr0GG8dZ6a/v27ZSQkkkbt2wTP7/yyiu6Wb8tDV20cf16euCuW6i/q51ml5eoPrbBSk5om4DI7HF3f4+4zwZbejcRae9WapKSQi9rDDhzHGR/YzC7MI0KMmxSilE2M5GUOVZlFb4Njp964xP69v9uoIZVK8i4eiUZumqEJd5B03IoIdpCldV19NX2Rqpo7g665i3QBSD9/f309cYK6u5lKcdExgLnm97Q8Q9lwtd6KzM7l5JT0yg1PYsqa+qopcXW2VVLbXsP1baY6IG7bqXtO3ZQXdcQbdu+PWg+tt0DYzXHWseKcE9ChSsdypiUYQjNzDEHx0FkTU2H+L5gcoZOa0uips7I0BzDfSNJydr6MjjGQPvMg3fSYHsdpacaKHuoldI3v0pXHDaFDs7qpsF3/0bNr6yg+5ZcQp9/873I0gdbVoEugdqf/QWWPE865RRaesnZdOLJpzhdAmUiP3Mc7raQTHCBxRasthqbmqi1vYPa21spNTOH6ntjyAoDe42EYUeTmWobm2lXTR3FGNIpKt5A6Zk5QfOxHbFyG71ykueGfNEXvQYgMWHGIsekTANnjhk7h4UKaeE2Y0RSMSpzHOY2M9LKDZnjpLhon8sqMNC2tjSLATg1NZ0ys3KorcVI7S1GevqBO2igvZ5i4xOo21hL991xC22pHZvlCHRBXiBWBOQS6NZtO6jPGk3bt4de9yEmcLzyYy29vaGBd/kEx5NiOnsgnYAsos+QR1XNHRSbWUTnXbZEdPxcV9tBfX39VFffQD/uahYuQas2dlBUUgZZejrJ2t9NTUH0sdVrH61NQjlazUN9TIt5/GMmXl87gWBIFGkiURTKmWPWHAeJz3cYCZdLcWYSzSywdcWzD45bwj44HlI1x1Lv60srNwy00YYMsnRUkaUvkdp7TVRcOoWGaZjaWo2UlZVDhuhEqrZahdn49qpGmlaYqVYqBy04NvXRlJxkvy+B9kQnU1d/DGUmpIkbFx4vKCjw2/syobl6c/PqdWTpM9Nv9y6iwqzwtYZkvAcrR5ggY1xAkOqN/nfy9FlkOPYvFNfTRdakFNrQm0Hlw8P03Q9r6IqH7xJJiZTMbJpyzIW0vT2F8g4/hzq/eI56Olopb0qZ6mMbaHqklZtdzclIC2n9Fdq69l5h8Saf5y2wZU1OGKK0xNAMAoMpqYgS8UFo7heWVQSJ9zfWkcXcTnPyDWOqNWVBHi6qYNuQjQcpY8DJrxbk+VBWgYE29/BzKS5zEsUMD9G0adPopptX0KF7TafyyZOor6ud4q29FNVnElmMb+r7RYFeoNtyy2W9GMWNxN+ZY7kE2tHWIrI2rcZmSs3MDanuQ0xg+OrbH6n5tZXU/PIKlteEKeOVosmVpC3btlNiYiLt2OHdStJn21vIGh1LielZovD5vxsa6KXvKumpB+6gyl0V4rFdFTtp9RP30rBlkC444TA66vK7KO/Um+jsG/4elGI8YFat3PSD4yadImlkehs6+1Rp4HhoM3XTrqpaXrnT0KlIKtKS4lSXrlCDg+MgzeJfWnml0MN+8/j1tHXTxlG/h99xrHLC+GJZJ/gFebGqlRu61/my0Kg7pVgYib+6ejW999/X6dhD96finDS64/bbaObMGRRlGaKy8mmUcchZ9OH2NpENwKAXjP2AVYJANALBpOHiq5ZSTEYRDQ8NUnRGEe196iU0HM1uBRMJBD933LpcaPKjYuOoYudOlteEIZ3dvVQ7Djs0rBhh5Sg5PYvS09MpLy/PK/3v1xU2WdrepVl0xj4l4t/v/VhBFdV1lJGZTQnJqdQdlSySPgvy4mjx1ByalJVKMSmZ1Nrrnu62p7fPa+mHHghy5eTCYKc5Hskcjw2OsWr7XWUb/fvb6nElU7767gc6/qRT6NjjjndpfzfRPI5DWVIBODgOMHIWb26uFTestoaqMTcsLOVkp8SHfSXtSEHeSObYlwV5aJKCADk2Lp7mTSsbtWSHLAVsht544w267/F/0aw584Xh+5vr6ml7U5fTxiH+6pAn7YICcUzbE4vEpAFZG3zfNphF9R3hXeDJeAaCn+bmJqHJj05IpuHEtKAVRfkaFDlNBB0ngqlzfvtrOunEE70OrjIzM8mQkUNtrS3U3t5BzV7qf3+qtrkrzcxPpSNn59PZ+5dSdFIKdUenUHV9I+2qa6Z+czsZ0rPp3MPnUlxsNM0pSnM7IYDPdvIpp9Lxx5/gs0BS2500xZFbhY58EfeIxz/bRat+rKUvd7Z49d64p19x7VLqbKqmjgEKy9qPYT+tskqPYw6OfcRnn31Gxx9/PBUVFYkAcvXq1RRuSD1otHLDys3Vn8WHu80MLirp76vtkOdLWUV9R68qQ5GSBS0IlqdMnkTlBZl06sJi8Rjadde29wqD+kDIK/AeUlYhdcaByFz/sLtdLHMumFUmvm+qN9GaqvaAS0qY4IHgJy0rRy2KMne2UW5eXkTIazDRHYhwFwCZSFm7cQv1WKO9lkO09FrpzD9eS+n5JdTV00PTp0/3WP+LYKbCaLPD3GdKpvh+6IxcOv/g6ZR5yFk0mJxP5p5eis+aRFcuuZFSDUk0tyhNXS1rdDHmyc+6c+dOik+I9/qz2iPvN7g/oJ+AnnyxvXtAJFkkSJy8t6mR+gf6RRb8qx1NXr037un1DY2qY0dGVnZITE49cUvqHbQItxt/OVVkhahTRdhljru7u0VG8KGHHqJwRepBB83t4obV1d6qO4vPSwvvFtK4qIaUAQeaY1VW4cPgGEEuKEwf8YjWoyw7meZMSqM9JqUTNmn1mjpxce4KQOc87Ac57pbnJgdEVgFk58UjZuXT3MI0Ufz5v81NAfVZZoILgp9f/f4aocmHvCY2o4jO+MO1Idmq1VMQwCBAjmQQRKG7nImSqLY7yis5BDLscEXa0JdBXQddTgdccqdYUfNU//vFjhYRQGYa4uiYuQU0SQl64Sd/ySlHUN4ptlWqy257hA7cdxGVZhtE4fPIfazfTR/lHEpO8V764bg7XoxIqGnJSo4XBWEYn+EepU26vPXJt2SEVv+VFfTgdX/wKost7ulJ6erktK7RVgwZzMkpAmNtNt0VXd19tLumzufZ7hGP49Adi8LKreLYY48VX+EMbkzLbl5BH/76ErJ0t9P0GTN0Z/Hh3kJa6mxjoqLEwKS6VfhQziBlAsWZBqfPi4+NFgHyKQsniaDxh6p22mU0E8bK7OR4v16gcnDGIIxtcLcgD8WM0J57Q1fvIFW12gL/X8wvoAGLhTY1mOiLnS20u6VbtTBiIp/syTOErMbaaxZL4C3xhRQJ1HX0UmxMFKUnpVOkgiAKhbSWqo2EUKKpaYhmzJjhUXC1u7VH1Fn8b1OTWEHa0hnj1eToq102acH8SekUExMtGldFR0VRTVsPHVCeTbkp80WAuU9ZJqUb4lQJWb4SHOM+hlUr+wBV+1mzc3Lpk+83UHZOH6UMd4sM93gDyRGP47GhTmxMNGUmx4vtxvZBg4xt/HRLA2397/8JrT6yvi11u512A3QEnpt20FnU/t5T4l6fUmTrEhjMySnuK9osuTPWrVtH1y65jozNTVRcVOjTDofhoDkOq+DYmw5h+JKYTCbx3WqFXi0wWQe8Dy447fuVz5yt3rBW3XkKGZISx2yPtBuD7VegttWXdCqaopTEWPH5E6XPcf+Qzz5PtRIAFmeM3X/24DnI3O4zOY2+3lxFT3y6g246YT5tqO2kfadkUlxM9LiPq6NAVQ7OeRoduau/azb1kCEuRVcu4oqvK4wiG4LAf2puMh0xK49e+LZaDEjvbWwUmWRuJTy+4xoumHoHRFCEoijwU3Vb2H82eKSe/eR3hEv2myU/E0FOJB7X2NhY+vXvr6afrrtBBFclZdNoxYoV4nF3Pgey61WtZnrlp1p1Fa+6rYdMPf2U4qF91k9VtoZV+5Zlqu89PS+ZoshKVa29YpzBFyYscwthF4h9PUzZSvCD928194tsraPPesKFf6ZPt19PraYO2mvBdLc+q6vjalbqXpLjY3Sfk60Ex82mXppVkEJt5n5698edYn+nZmRTX1QC4a9Q0NjS0uKRFSZetze1RL3XL5xXSvPnzw/qObhmdxNV1Rvpgp/NdxqkDwwM0PXXX0/fr9tEqZnZ1KN0OFy1apVPgvsOJVOfnjj2+Pr7WnX3dSM6OF65ciUtX758zONGo5H6+gIjV8CB6Oy06Vujo22DeIOpX9ywktKzyNxlEl/2JIlcAVFNi0kUUIQbVfW2BieGuCix/f09XeJnU0+fzz7PrmbbgJ0WO+TWaxq3raFdz99JrbsbqDUpgx4Z+D1ddsJiWrOtk8pybJmO8RxXPWqabAF8UmwURfV3qdlkFLAk2mngRm0rMtt9JkpJ8Hxm/enmOvF9Rk6C2C+pw4N0UGkKvbmlnT7Z2ki/nG6gwgzbsijj3XENF5rabGPLtJxE2tnSRxtrO8NyPNFS29FPHeYeEXBs2LGbJmWlRO5xTctXg6urz1lIhYVZbh8/rB5tqTaJlTJMsZGg6B200gfrKmnxlAy3NwHj1c5m29g1Pydm1Puj3C4nple1QyvJMZCpvZW0d7T0xBjq7LPQlt31ND3X8SrfYHKe+lmXXbI/FeakuPysro5rnXKPSIge1n2tjARb8qGivoVmZQzTtkYTrTMOUkxyJsX1NdFgbCoN9nRSVGIeDQ25d5+RfF1pe285Oa1o6Q3qtbdp0yY660/XU09nG/171mS6+YalNHfuXN3nNjc3U2VVDfXGJFN/fwzNy86g2tpa2r59u5C8jJfGdtv5FGvtH7NP/H2tdnXZ3ntCB8dLly6lq666alTmuKSkhHJzcyktbXTjDX+BAy2MxHNz1QPdMdw1kk10cKKVF2GmXy06EPniZAw0sR22QScjOUFsf2EXNMcVNDgc7bPP09qzVXyfVZJHeXmjuwzqzYSfeuwhMjbUUWF2BlXX1dHHLz5GB+yziPablkFDCalUlJ40ruOqxy6zzf4ozRBPU4oLRFGI0EomplFelv6NAoPCc+s66JDkDCrP83xZcWtLhfi+z1TslzzC3j56z2h6a2s7VbT20cb2KJo/LTdk/SWDibvHNVywxNhuPIfNKqRdX1ZSe+8QdUcn+7UJjTcgywgtJLppuuJ/338q9KDI7l21tZzuv3uly+XecD2uA1EdanAVbch0e+yEj2xHyzC9vLFa1QajO+mPVe20td1KJ+3n/hj844YGwpCFJfAD55aO2X/YpMoWsyiQnJE/9r6an55EnX1mGopLdjpOdwy2qp+1lQy0yI3P6uq4xtbbZBXpyUm6+644u4G+r+mi/qh4ysjKoc9+aKU+awyVHX0+5e94nTburCJL5iTa/4xLqbjYVtTtLrvX2+o+9ipJp7U1ndRkHiRDetYY14yA2TrefQ+ZjbVCKrJ79266//77HWaCMzIyKCuvkLbX22xmW1oHae7smULW44vMca+lUnwvzssac1z8fa3C65smenCckJAgvuzBDg/kAIkDrX3PnkFbWh86XEfbIQsZ4HMcToO5pEvpSgTdLLZfar5QPeyrzyNdH4qzDC5fs6PDZmFUWJhPUXEG6u23UKupnZ75dBNNL8ykHU3dlGlI0NWmuXtc9egZsB1rLGPGxMQIXRsKCY3mAYfZ6g82N9GDH2ylD3+KptevPsajwQhBxtZG2+QLPqNy2/YoyaQFJZn0Y3U7/W9DHS3Mi6LpJYURUZzla9w5ruGCWbkOsVIAzTuKUL/Z1UZT80KrU57RbLNlTDdEu7zJP/i321U9KJpP3HTTTW7pQcPxuLZ0jzShaOsZdHvbd7Z00/e724XmGBPykxZMojU17SI4Xl/b6dE++HpXm6o3hsxBj6l5aQ41xdAdb28yk7HL+b0MOnLJxrouOmZekVvb5+y4YkIg5X16v89TirlbzIPU1NUvGp2Aow7ej25ceTY9/O5aeuJ7I7XE53t83qDOQ47DNW291No9QNsazbTPlMAX5OH+t7umXrV1TE5JEQWPeFxPKpKYmEi/uuQa+nHp9WISWjBtitAcuxtYuqs5zkpO0N2v/rxW3X3N8BklIgjZztLZDFJaubWaB8LSfqtL0XrJTJCvC/LgodytOF8UuSERULvGtbZQX4+ZYgZMlJqZQ/0xBnrii0rq7u2jbzdV+LwqVxbkpSgG9NI+qFmnK5Pkv598LTJjHz94LZ3iod/npoZOsV/iY6JpYalNZwoKMxLpZ7PyaKB5F71291V0xqmnsCn9BGDkOoylPYptxWvf7Q49n2M4BLgzNsC9AAVC6k0+PSsk7LH8BZpRqP92szgb2l7UqkBrDI6bX0gF6Yn08zn54uetDV0e3VMwoQb7lDkP6hwV2xUoiR5XLj3SfQhsVgJLf99r5X0WrlDf726jHc22Qu1j5hVQdloyHbFwpshmI+Hg6X0YEwKwZ0kGTc2zJULW1dqkFoFGFDYaMlTnjLZWo0vnjOTCqapX/oU3P+jTDoft7HPsW8xmM61du1Z8gcrKSvHv6mrb0lG4IK1Uku069uh178FSlUlxfggn0PqaNH3Tk3xs5YYKbJmZloG3M5BVwswXFdDR1kEqLiuna667iZISE2jTxvV02YVn0R/PPYNOOvkUn3YxksFxsrKN+S4s+hCcv/r4PSIzRjGxtHnLNo/8Pr9SulhNz0+h+NiR8wsFh4unpFHPVy9Qf1sddVuifOYlyoS+a0xaYqwa3KAINZRA4VhFUwd9vXGny3MRN/P41CyPbvLhjDYg1gbKzsDqHGwbkZ1DwRmC4ul5KbRvWZZwD+oQbjY9br0WCop3KEHeIdNzvPoMCMxBkwtbUq3/+44m93Shnli5ObvPYnL2/mabnzEsP+cX2zTZSDBgn8HlQd5z3D2na9pt+3ivkgyaLYoUSfjNBwPc/4qOOE+1dUzLd+2c0dTVp8pcajrH30Zbi0kpVM8MYSu3sMoc//DDD7RgwQLxBaAnxr+xrBZOOLOXkSTGxYhsDzCGodexNmMF1A558P31QWcr2QDElcexFtk1763/vknP/fs/tPfCBfSbRYXU8dlzVFu1i4aiYmnrtu0+DRjlscay3qgbhYPMMTJgHW1GNTMWm5LhUWbspypblkdmCbUkUz8lDXWJ1+60xPnMSzRU8KWHtr8IdFc3eRNCYeeB02zBze7WbvXxUODDL76jS849ky787a/omONPdDo5xc187vEXqzf59ILJQbfHCljm2OzemFTX0UPvbGwU/0bzIwSAkOklxcdSWY6tzuGrCve6vn1Z0SKcJjC5gqzCG6RE0FkjEASTWq/h2o5en3QxVcdfR5ljJThG1lomFg6dmUv5yuO4D0/Otu2zbyvdHyc315sIiWYkb7BaOL/Itu+2KZK3QAPJUlNcvpoJ3u+i21xmghs1xwsuJ74Cx7VP8SiH7V+oElbB8WGHHSaWNuy/nn76aQonpBwg2UXGU7VzC0OvYzVjpXj1amfufUMWnwXH7kgqtOAmCo3V1IIMMTDOzoyhJIstYDT2x1BSeiY1NDb6LGAckVXYjrX0GHa0xJiekUmWhBHj+JZmzzJjG+tsmYl9dXRtZZPyqaykiKw9ndTdZaKa+saIybphwA0HT3AEpoFEnn+YpJblJItMIuLzb3bZAoFgIzqj3XiDaLEbFRtH27a5Xs0YTC9Rb/KH/vEOny73eou/2tFrA0Z3G0I99vF26u1opSmZ8cJ3eHr+iL58nhKkQXvsDl/utJ0n84tt/sbeIAPNRieyCjmew1ED5yoCS19kj9V7rYPgWJW5dfWLexaC2Z/PLhhlDyhbYLu7z8CaGpt8YlpeipCbQFoBdrWYg9L2fEtDJ/UNWtVMsLHH9fnaoAmO4Wft6+54yMinBqE4MSKD40hBzmYNTmQV2gs3HG76eppggIyDVlbhqwxfjbLEJduTegOM7HNysmjq5GJhmwa7ubr6JkrLzPFZwKjKKtTgOMFpFqXJPETpB5+lZsZiMovczoy1dPWpRS0oArEHr7FixS2UWVgqXjurMHKybphs+LLBjD9AG1YEx/DpDfQkVa7goKUvCJXgeFdtI9XUNagrJUlpmS5XM7DqIm/yLW7c5P0NAvn126t8Lk9CwC2DO3czx69/+BW9tPLPorNb2+t3kKl+56hmQrIOQU6iXfGTm3pjZ6hSMid1FnLcKkxPUhuIrFe6fDrD1G2zR3O077tdySpSRq88Hjg1mybbuQgtUALbjfXuy5E21HWo9xgAd5i4mCgRoEq5RSBBES4YWY12HVM0aSYzmLz4qvZJ6o3TkmId6tRDAQ6OgwAaYQBXli7hHByPaB1tA3O0pre97HfvCHcuQjmTtR/IPAGd8/Yqy6XfXbmEpkydLgLGodQCOvniqygqxjczWvtlPVea4x3NXRSfV05TzrhRZMbSj/8LzZk33633+lJZFoTURL6PPT87cF866oq7xGv/esl9IZF18wXIcnQog24oL5HDf761uz9w9mhq5th2HS6YbAuOYC0VCnRY4qkvLk1dKWlvbXG6moEJhjdFav4CEpBTTz2VzvvtaXTKKZ4Vz7rCXmOszSLrgQDx5mU3inqFZEMStTdW0z//fseowBHd7EBFi5n6XazgmfsHabuSvfVWbwzkWITickdZU6nnnZSRRDPybcHxJhcBPPb1KaeeRueeey6dfvrpuvvelawCARqCVslRcwvGLPXLVThor93N+qLoEeypyNuQiS5VOqTCLSTQrFUy2bD0A9Cju5qkGzXXFiZpMuM7XuTrhLLeGHBwHARkNsBVIZnUaoVjcCw1jXKmqp29u8rwYXbtauCu81JWYQ86NiFgvPvRp2n++bdR9olLaLc1V62cxo2lsbHR66zQGFmFbAvuoLgGWjWweEYBpWbl0BDFqo+54jtFEzdXWTrVAx33puZniKxbgzn4WTdfZdge+7SCfvt/3/qskMcf4Gb/5Gc76OM12wNSBGkeGCJ5K5fX4QFTbcHR1kZTUJZ3tQxZrPTR9nZKO+hMdaUkMWeS09UM0YZY87O7Oly/SUJuuIG2b99hk4QoXcR8dWwRTALZXRRFYZgcOALZ9hZjs8jCJ6emUX5+Hhmbm0dl4VGoi7FoyDJMa5SssCOgwR202PTGeyoFat6QkxIvmpBYhoeFnZketZqVQCn9wDnqCOzj666/nioqdgq71u0O9v1I8bv+vRaZy+xk25g8qyCVFiqTRy1zCtOE+w/uW9uVZiiu9L2VLd2jss5ghuJYsT4IjhWyEPDwmXnqZMDRPUjet3qUOEU6Lfkq4y2TGKHcOhpwcBwERmazzmUVslggFDXHrrK7UlahNfWXRXmuMsfm3j7asbvG6U1G6qGQaRgvaHual5FCxx8wRyzXomq5otlMa9asFVmhE044wWvbM+kzay+rgJuHnk5xe7OtMhzZE9zIACyG3EHaBC0qdX4jm1lg0yB6Un0dyuxu6aYvdraIm+/XISIX0Lth3vvi/+j1v11Nl573m4DY6MnVG9wMUVgEFk3OECsmuAY3uLFs7U+gQf1sh1GslBxw8W1iNaP81zc5Xc2QulUpFUDAIsfTQIOgExKQgbgUquwcpthkz4pnXSFXGLAkD32meMzJZADZ9rgUm5PH8EAPmdpax2ThEQwiCNROph3x5U5b0d7cSd7rjWXWVLaNdlRrIQu+UPwmi4krjI71+djHdQ2NlJaRJRp6OSou7nbDNrUkI54s5nY6qDxdWF7qbb+0YvvWjfEFDVHQ6AkrpVMUiYg2aSF96AMFZIzolgj2L89S7eucWes1K79DQkvKXHxVlAe3FOColXiowMFxKGeOlUDKlT9koMFyn9aT0nlBnjZzrHgdOwmOETCcdcav6Lenn+owgMBykFxOHW/mWN4wkK1YPDWbsgzxwjrvo031dO3S64TdGYzPvbU9s1/Ww00dWQhHKwIIysHsgjQ1g+KONyaycNJXc7GydOaIcqU7miyCCXf+t8mW2ccNrqIxOD6irqhp7aTPX/yHWPLutUbTFh+7ouhhVq5BbWAQFxujLlu761jgz6VeBAoI+85cPFWsZjT3WJxOvKVWf0p2sroSFayVNemd3mI0CklIfYNvC1xbugbUIt6M5DiXdm7Itk//xe9EFj5ueIhmzJium4WXweeaasfXCibuaCIC9tH4pXvLSKJH/15Wq2QlkeyYWZAmzglkyh0dW7GPEzNo6+46qqhvFbpjvX3vysoN95fW1bcTvX8nffDgEtq8cYPu8+YpWn135Ehyv4pJjaYL6R4ltv0urfECBZIrWCTKNMRRSZZBXZFucuIe0qTow3Hc8Deg2k37P3c1x+lJHBwzDq3cwi9zjLak8El1lf0dkVXE6cgqhpwuU67ZuIXMQ9EOA1JMFoaVjBiq730Bstoz8lNVo/x3ftxBdfUNIiORnp7ute2ZtLSTAQoCcSwz6h1XBAXSf3RGQSotmGzLALsjq/ipukNMGrCPpW2QI+SEAj6WwV5aHy+4ib/xsa1pCoqQnl5xud8zst7w1nc7aKCrXSx5R8UbfJ5ldKcRjwS+q55W3/saBC3vKXZjKFo6fFaeCIiQcXO09K5dMUKGL1u5jpwtD/sT6Z2ekG2ThAynF9Jfrl/mswLXFiVzDNeiHGXp35XX8YDi5PH3f74gbCv1svCyuM7ZuLKxrpN2qv7Gjls+e6o7dmRhWd+hdDvNTBJjsRyjNjkogouLi6PsQ22Fyx3mHtHWWG8i4Mw2Vd5v6qsrKTM1meqqdjmcsMqx2NH2aJGaYpmhl8hkB1Y/ZNAeCOQKwSxMOqKiKD/NjcxxV5963EoVKztfOe0ghgAI1kMZzhyHqM+xNjh21/w9ENu9trZDLBE70w3j9zI7Lt0qgFzadRRYI1BA5bqJkqipL5qyc3J1AwipN0bnJRT6+QpkLQ6flUvJ8THUZoknSsqg+sYm6uzsdJiZcIVc1tNOhNRJj93ghBsH9is+Elr9wrQfoAWsKw22dB/AgOxqn8BrGc+AnlDegMMVZIq/+c/DIiML3WdL3e6Qa2yCSc/3jYMUk5ypFp41Njb53UZP2wBEizyv4FgQrMlRbVuPahOGYq+SzCQ12HUm92noHKk1ULubOXFB8DcIPieddr2QhGSesIQ6ktxreewOUkKByXRuarxbGmsENZCGzZla6jBIl0V5aJdsPwaJ1zD10Tc7mqi3s5UMscNqYDgepB+93rHCqpcMxiZl2AIxNC1xVryG16mNtvn2zjlnBa1atUp3IiA1x3qyCimLQeIjIyODCgvyHU5Y91OK8nYZXbvNbFG6+82z84XOTI5XkzlbAtgMRBbj7alkruEIIo+/I5qU8wL3WNyLgLuNYyKhOx7g4DiYwbFLWUWiWt3prBAjUBk6LBcNDlnFEthz31Q5lEfI5VxHmWNHwTEChfSsXBFAWPrMVO3Ah1fePH0hqbDXlk3LSxVtlnGDSTrgTCooKaO+vj7RWc8b2zOtz6xENgKxzxzvVCQVCNKhC8VyFnwgMdlwpg9FIPjZuh00bBlUs4LOQLe8HLUzVGhJdjzl9W+30aC5XWRiYQVGSekh19gELgPr6syUcchZlF88RWQZKb2Altzguyyju7p/bcU6MljBkFZgsvDR1mZq6xkQY8LR82y+svJ6lpNfV81/RgqWg3cOY3LRNUhCEoIxA5/LV0jpmMgcp7hOlOC+IifjcozRIyM5niYpFpj2ln64z6B9/b1LLhErMZ1v3kEbHUgNvMkcN5rGHlsEaZijxUZHqVJCaYHmqI30J9uaxSoD9rkpOlX3OsJ5JttH69mmSlkMEh+DvWanCZDyXKWQ0TrstKAO74kW1ECvuC8YbaRlsC5XDNRj4YasojA9UZVV+KpGRbpVZLBbBePK+9YRGUlxqmbJWSGGv8GAicAYATIukLve20Yv/1hLb6yrc3pTToyNFkHeGFmFg+AYA9y5l/9FrVxPzi3WDUjlzXM8HseOgDUcpBXQBbclFtLJ19xDz734isMlSmdgoNRbJcBsXE9/t7mhU9WqASyByeK5HxT9nz2QEJx40sn0zr1/FtKC7P4GjzI54aw7Rjb9p8YhkZGNHzSLjOyAuZ1ycvNCqrEJigVhnZRaNI2e+/eLVHg6LPqWUH9aSUA9jiVZKQnqtfN1RSvtMgZWAwkZxCfbjGpGTp7vsrhW6k/1aFAmcwj+5HUULFmFHOu0yXfoO33VEER+LmTU5WpTq5PPKosVMc66sgmdqwSf9sW+m2ra6LF7VlJ99S6xEjPYVu+TlRhnAZkMuhAYy1UvmXV15D7z8Xbb+QM6+yy6K2tIwshDo7c/pCwGiQ/L4IDTBAjGYqnV/85JgTQ00tBKo35SBvhaAt1GuqGjV8iUojSWdAXpCaNWYXT/rtN2nDABlcExzi8kasYLZ44Zh8jMqaMiAQkGCrkM4253JH9kRtbVdIggDwPzfR9sp+7ePlH8tLm2zWlwLFsmS5LilII8JzeP3NKZaver2Wcu0w1IpcdxSab3HseOQDAPve/Biq/nB9vaKD0n16sMHzIbyDTYB8eO2qnK1qLajlaoFAc4Bo40c5u2bidLVKyQFvz3n/e5dSOTgYg/guPx2t95sjS/obFbZGRxY4u2DomJ1cVXLXV5vAK1jeCDLU1ql7H9pxfQHjPKRMbrgy2+yzI6D47HLl/KVsBwBMBSsbMskq9A0Ij32VDTqTaXOHJ2vppBkp7l1W29LgNATO5kwBhMq0tMegCyngiIUKgMva4vkFnibE3m2NlnlQVWMvvqDCmV0DbaaO8eoO1VDVRZU0eUmEYJhlSaUlzok5WYEZ1rv1vdTuX5iaV8yC60ILnyk51eXk+uISUVUXZNqLTg/oLExxtvvOEyASK3aZ2TojwpYSjOsGmnx7xGgNtIf1NpWxkoyUpSx4F8tUurk4lWZ6963DAJxfmNe5mzLofuwj7HzLg1x8CdQdGfVBjN4mRGcc99H+yg5qptZFxtK356asVlusVPjm7KSfGum4CIWbfS/WpbSx9ZdOQk0ilDLg36mtKsZDpqbr7Q/m5p7KL1OoGpO2gtppI1EpoRF5LRx1RaF2kLORYqNzG5NKYFN6yGhka1u5ghPYtaW4xu3cjkxMJZls4bcD6cdPIpdPzx3tvfucv/NtuWVgvKZtFrr75M+/7+DjGxSimc5nIbx2vR50nxyfeVths5JlzQ3cMVRS5pu9KSjwc0cdDLHINFigPBtqYuscKBVQtfN1HpGRgSE1kU8H6+w0hf7GgRgeOHW5vFjRY6Y+m7DIqV4NhRq1pM1OU4WJA+ojl2dpP3N7IxBzKj0xTLq/9tthUa+lJzjADZ1X1ABi7YN67YX9EdI0hDNhD7dkujiTqH46k7JkVI27Ljh6hDxw7OG5w1P5JjkHYlEP+Gv/OQxjNYgokVJGlYVZVFXdpWx5JujaTCWSc2TKQLCgpcTqhld0G9sdg+OJYrfvYEuo30j8qKo9b73p3+Cc3K73DcsJ+lTMcXjhUjbhWsOWbsdVBqv3fnmeNRTSOCFBxjSaZ/0EIPfrSTGtq7qPvL58nQ0yyW3FrrqnSX3GRwbH/yj1i5DTkNjiXYT3raLJlp8IXHsR6Y8WMw2W+K7Qby7LdVXr2OHJzxelpLnzwHNwr49doPrPuUZqkek/ZyFNyw0CikrcVmJRXdZ3L7RiYnFrINty+QmWy4jETHxXltf+fWew1Z6dPttszr3lMyaVJWGk0tLRYTK2cBv3Ybx2PR5y4/VLWJoAXH/+i5BeKxo+bYvuOm709bJ0eyCtkMAKcktuHdTY2ic9864ULjuyp6ZKQRfKG4p3/QNskdHBigj9ZsF/r4g6bnjMoWyuDIkeYYGmUES1HKBNOVPVggQLYVZCbHqUVbkKqMd/kZgZMMImyaY9cFedqsuiuQBcUqGRouba7vpF0t3WTuHaLnv68X7etzikopKdrq0A7OU+R9DJMJ+0yw9M+Vy/dy1bQ8R78oDz70ADIHaUup57zgbm2Pu+ynaHbRDMORt7aUS8g27fYEuo20XBnQ1qLILL6t0ceQboxilMGxkmWW1+Z4txmvLe/xKFAMZbggL8DgopDDZrIbF+3IjDvwwTEGsc7eAXrkswoxeCZaeig7ppeyc3NFpnI4Ub/4Sa87HmmWtpxljuXfars02V9c8ibg64I8LbCvOUYJZj7f3qKaqHtCl5K5S7E7znJw0i4F4iYrzdGl6bq0rEJVL+61a2vsdMfRsXTChVeJltfQaM90YGekR5EfZBWy+jsrJ4fik1K9tr9zBwRQcnnz57Pzxc0UGX9XlkPaCvXxWPS5y3ubpF1ZqqqtnVOUJs6vYc3vAx0cozDojIVFQh718ve7RRCPYtu1KLr1UfGvvfa2YusmWvqn82jNE0upZfVKmh7bqjrYyKVo7ZKuPVL6geYBKCodcfMJXj2GDGDRZQ0SEbCloWvcKzIYC2R8jc+rFuQ5cZdpVPTYRTqNLOxBAaTs2PbJdiNVt3XTR9uahTNO+qTpdO/jz9CTz6/yqtZCD+wfNDLBZ7K36pMrgfYyuRkFtu3TFiNj0vGtIhVA9luOY3rL/a5aR3tKQUaSkDnChvs/P9QIza599ldqpPcq0feGDmQbaewr2f5bTtzkiq6UdOrJUeDz3684cshJjZQ8eXMf1IJ7P1ySZE1VKMPBcZCK8ZzpoLTIJfhgZI4xQD/9ZZWwfEKB2uW/WCAyk72mdpGpHOxup+ycscVP0l81bUzm2HX7aDmrRHchPS9WaPzkhavXzchXYACBaTsyE7iUvekmpnZnsgtOVBeS3pH+9juVoigcb63cRhTlKRrkH+z2BW7AO4eyKeekpbTPxXfQe/9d7faNTN5A9ZYjvWWk+ttIbR3t1NjkP7uy9zc3ivMIA6zUh0s/TmeaVW2Felt7u9cWfe5e69Jj9MCpOZQQazv/ERDKynF0IfPX8qojn2MAKcmXjy2lvrdXikLOh1/5UEiocPNCNb6rDpjuIK9TyDW+2dlIt61YJlosY9Up2tRILz3yt1EZe7maga6Ssm5BizxXZcJABsdt5gGfFAqNJzhGALt3WaaQeiC7LbOb49UbY/VNuMsowXFH96DD80XuH1mo6Apo4MH3lW1kNPXTa2tsBdanLSqm/MwU2mOGYzs4T8HKiaMueXKlwF4mJ4sGtW2kq9q6aXujWZ0Uyyy5LNTUtXHTmRx6y6zCVLHq8f3mXbS2soW+rGgRK36YUOJ6r1eOgWy0okeg2khvaegUyTisENjbyklJkt6kQtr7pSXGqpNXaee2u2X8kz6A7Lmrmqtgw8FxgJHLGFhqd8ejV9WnBmHp8J+fbqcv1u+kKOsgXXJoOc0syqLf/XkpzZs9k2KU4qcLr1wyZgDFzFPPX1UWKDjrkCeDY7S5BBvtqnplZTNm8DLY8BcYEKQXo9QWeoKjzAV0cihw0Fakb22wzfDLlOyiq0IQBAOwDPp4W7OQEpx60FxKT3G/QFFKUqAn91V1Pc6Dq5bcSMboTKoxdlJxablPlmTtwY3oU6VaXQQkdkt/ziyHZIX6lKnTyGTu9dqizx021XWKTByO9DHzbKsQkiNn56nnd72TqvHxYHKQOZbSktqqSirITKXorkZq+eRZeuCDLWIS3t49OO5WsdAmPvTxTlry6nq65uX19Nj/NogM/XBimlh1KijIE3IgbcYesispxdI7hjKjLCfFCLawb9E2XAapgaatW9pSxVFKYhwtVFq3f76jxSfBsQwopQc0PqsMMOyR7gNy8uCKRYpkC7UOkI5hMgN/YUw2p+SkuOzg6ikyC6nViIuVQCWgtJfJzZ9k25cVzSPZyg83N4t9kJ+aQAsmZ4647uhM8jHJAr4MwnL6G8Rk8sXbLqMVf76QNm/YICw44UiDTp3y3iQ14noEqo30t8rEHMcUGWv9Y9HntDueRGa7xyurkDIkXOfOdOChAAfHAcZVO0t7RhpGBDZzjMzSPYrXZdSH91GyuY5iYqLotJ8fRKtfe5UO/NNdovgpqWDqmL9VM8f2BXluyCpkcHzErHxR/Y2btXYpR2YZ/Jk1lkATJW9O3gTHXQ46Idq65I1uBCKzI9L8Xq8QRJtBgRzi463NYl/iRnH4TNuSrrtgcJLHw5fSiti8KZR94lJKP+EGOu2v99L8+XuQr8H2yhat8KSWem7Vj9PF50F2/dGnn6dlDz5NL7z0H58sG+vxjtIBblpeiuhOpQVLwpgkYeXgQz+5VjjKHEtpSX5eLqWkplFpcQHF9HeSqb2DHvhoh5jAI4s8ni5e9/9vM32+bicZO7tFADu5MJfy8vMpdbiXSlOjRMFXQcHYjL0MdvTa06tyKqXgDBlVOXkNVk2GLGJE23mp5QZrqtvHFbDLYjwZFOOzyomDI69jGdQ48zjWcoCSgMD1gtVBTNjPOaBUrPiVavS/vkKvKA/jqqOVwNmKbhcJBNlV7bMdRnVMRLJFflY9WzJfyyowqfzu5UeEK9DAcAzV7t5FTz94h9DRWyzDqt0mrndnBKqNtBwjZXJFi+q1rxNXyIA5XzPJgtuFo+vSE1S9cYh7HAMOjgPMSDGeexest3ZFzrKz7gwC119/A7U3VIsl0N6WWjEIzMpNEgM0smwzykpExlJPg2Tq1c9YjRTkWVzavJRkG9QBGkvPY5bg/Kg31iIDrvFljuNctgaXDUD0qpz3VoJjZNMQsCDbUtlipv8pS7dHzS1QMwHuggC9IM33jUBwU5duI59XdLq14uGq45SW/v5++s9nG4WdIFYmDlOCEe05gX2kLezUo6PPSrHJWWTs9o9bBLLxssECAmF7WyfYlyHzBWQW3F+aY/vgQEpL2lpbaLC3m0ztbTRzSjFlZWWKpflHPqkQxwSZb28kH5hYv7jySjGxjv7wXvrzgnhafvJedMNNy2na9GlkHRqgWQ708fIY1ulkqOraR1pHh4qbjxwXZHHRYTNzhcsCsvbjabAiA+A8TQZSTtRlcxD7+pBWRY/srqxiUqZBLfQDx+1RKDS88Of1ZedR+4mPNnMsx3NMAuxXAnGvkeMkHCI6ewZUNwh0MtV+Vj3HEk9codwBk8qBrjbhDmSNS6KOYQNV1dRTa6vtOperLY6K8fTaSGMc9xeyOFA602hRu+TpZY6VMbtAcx5JzTHO9/GsNIaLxzHg4DhYDUDcXLLKTUlUB0t3dIA4cWGXJIsWvB0E4HUZnZRGsUkplJOTS32mNooaGAmEpQbJ3mZHW4hmn7HyRHOMgVFq4qRuE8hCF21lsz+RRSLjC47HrhKMFOX1jSoi0zOOh7sFbmI4+vD3RCCAIkFsEyYguCG7e0PUUuiHojxtVgsNBrY6sT0CCMJwfGWW01XQddyJJ9OdV50vljanRBlHebriJuhsWV6C6+jSF9bQDa9vpE313gWArkDmVRbDHD1PP6uP4yazjCh8DVT7aG3zg+jhQSovn0oXXXkdXXHUHKH1h33hi9/ViL+v9LAAR0o2OpSJdU9LLf370btFdm3qrLl0031P0v1PviBWn/Qy9vK61nNRkfITrRtDsN181OBYyYShnkDqO8ezIqDauGnOb9WxQmcsQlEiTmMUvTlb0rdHjjeoQTh2bgEVZxr8ZrElM5HSj3lUt1MH9nPSHm99XYcozsY5icnHYTPyRmVA4cFvrztXrdx8JA/BpLKosJBShnuJBnqor6uNOiiZbvuoRui1dza0iwLX2fnOEzfaNtLQpvvaQlEmoGTiSkoU9Y6FXs2JPD4FmusM50Sycv8eT7FpuHgcAw6OA4xsZ+lukYCcOWPpydkyJ3SYqJRFtgIart7eftpdU+eVRRUGgWhDhlj6jLP0UY+pnYqLCkctgUptbJWONlG9KSfpa46d2UVJtwpcjPsqRUvaql7pgSor2/2NzNZ406FQ7ge9zIW2hTSCaJn5kDcDe2RGGQWK0n4LHDErT7hbeJPpGbHO8p2lkHYSgcKk9zY1ObQ9khkhTOiQ5XAWpOI8vu6662nb9h3UY4kRS5vV7z9NVsuQbubRmTYO+kQEX7iePtjc7BcnGLwuPg68fPcs1m/pDUkIglEUmX6zy7duGZgAyDbuegV52uYH77y5mvbca0+RHfr9IeVElkH68Kft9FNlsyg2cpWF15NsDCfZtMWZWblCW9zVacv4JRsSacHMKQ413iONQMYeP6lNLUgbufal1VSwuuTBXk5auQFchwcr7blR6OZtlk1tAJKcMKaQVy9zLCUnyMBqbSNdcd6BZcLm6+KDy4Vmemru2JoHXyETAtqAzFExnrYADmB8kK25odmV90WsHODjwgDBXm6iFuS5YZnqDnJSucfcmVScFktl5dNoytEXUK8lml778Eta/69lYrXksZsudemdLttIo8kJsuHjkTDpgQJyjD+QbmHC4/hY9LosfJUrjdIZZDz1CHIiwJljZgzygpWzMFcgoJSaVb3sCG6CKH7BrBoXGvxKYZm04soL6ZSTTvSqyQEGgfJjLhAFd0nRFpoza+wSqLyJ6c0i5c00NcEzzTFm/lKnC70yfFBlVhVLaqBOtSsKbHDc5sRCyWXmWGciNNKlqE/4wcoJgSPvR1mc8mNVm1iuR3CHwOqIOfleN0ORWXFfeh3LSYTcb59tNzrMNOBxeU6bXWQpEXRV1dVTfEoGUXwSxSVn0nBPxxgLNhnwO9PGrVO0eNLGCob8vgZNL8A+U7J0g1OZLcMSLKrf3/h6s0+9lrE6g8IlR1Zu2uYHhqREESAlxEWL2gLr+/eIm/ytV11E69et9yi7jgl0dk4uDXV3CEebHlMbFRUW0L6zJ9Piadl0yIxcp5pYeS7bZ/613qvazHFukDPHssBInu8ADYSilOtqR7N3RVfy8+SkjrzuiNexTnCsE9C4A7zcLz18mgigMAG3L9zyJdLfXSu1koGWvJ/YI/Wy6Mb6xYad4lo5cFq2WswlXDAcNALxtaxCTiqfef4luvWhZ+mB/3uW7vvDiXTR4hIa+ObfYsIen5BINZW7XHqnw9oRn2XH7lqRyIKFoq8KowHcYZDFnp6TpFv45swidkRznKC/quPEDYgmeua4vb2dXnrpJbr33nvF14svvigeY1wjL1iDBxdsjpI9sD+RcTHB3gvLt/AoBVi+fOhvt9LGLduoayja6yYHDbEFouDursee1/W6lIMZBmV7U/eRzLEDWYWD4Fi7tI5AERXTWH7CfVn6HcuKdX91x3McHLufPRuTudBZ1pPLwdh/25ps0oMyxYpMj0VKFfz2JrPIxgJUlc/KTxXFOt4gJxjOJAieInWPx80vFPZ/yNIiQLYPrnAdoCAFy6GPfrSNvttcQTvq23UtvMBgrIFSM3PI2Nwsgq64QdOY1QwwOdu1HyeWaLUTuY+3NHuUHXWFuW9QbV5z1BzHhZLIMk6JahESkWeW/9Gn3frkNYhldneKf2HZNDvfIGoLrJ0NFJ+YKGoN7r59OXV29apWg65AwH3xVdeJiTXaee85dxbdf/cdVJaX7tbytsz822e0oOGVcixtcD3SJS/wbj44p/UKjKbmpqoZWBTN+ipzLPXVeqtY8vO7W4wniY+ykqnNSFmJI77R/kLN8muOlVwJxAqLHrBEG2jeRV89dh399H9LxbVSSqP3aW6K7T5j3wLd101AJDnpyZSVm0dx8fHiGp6eHiX8/6eUFNGe5YWUn+/aOz29x+Z68ebdVwrv700b1osCOl94jIti+r/8XkxwN/zrJt0xRT0WXWPlmjLOyLObaMl7/niSCbLdenokao6ffPJJOuCAA+jbb78lq9UqvvDvxYsXi98xzpFZU72AyREIpDDL3F5Zowa5GDxh1SKreOVjj7y3jrZV1tJgfAoZ+2O8anKAYAkXSHRMHP1y/9m6S6DQesKrEDGP/YzdYRMQKatwMEOWNxpoyuDNCKR+D9lSTAbkxRWogjwZHKOQwFPvV2eyipEsSr9q4yaX2vSQvrg4LpsbTGIpERmq8Wiv/dEIRC5vIyO6T5mtEOSjrcZR2SIEFVj2Q+vku//9P3r7/mvplivOpxsvu4Be//CrMYE0bhiVbf10yBmX0lCKreEJ9LK33Ta2oEtaDjlrcyoLVWTrWbQzdtSy2BugI4TRPQI3rfm+PbiWf3z1UZFxGqQY2rR1m8+69annXqLz1rlahnq6RG1BVnYOlRfmisKjVmMzfb6xUuwfmSV1RUbxdDGxRjtvT5tIyMw/rnPtJFoGPlrv1dFuPoEPjrGP5amqXSbG2LVfebYYs9//YZtXx1M2NsnVZo6ddAQccfJwPziWbdRvuvRcuvHy8/3aRl2biWzrGVSDQFeyiqLUOOr8/DkaaKsTGnYyNdA//37XqH2ar2TU7ZvHSCs3X2aOAc6/6fkpYqUFpKZnUFZOrvD/H+wzu/ROx7Z/+NzfKcrUQMMxsbRl23Z6/L7bqaOrh9bVdIyrBkJq/o11VWJ/mZtrdMcUmZyBXFNaPo7pjpc2+lwqVyZ842khLWsrIjJzfNddd9GPP/4oMsbXXHON+Lrvvvvo+++/pzvvvJMCwUMPPURlZWWi/et+++1H3333HYWdlZsHOqjotmoxy1x26bliMHvz469snayGrCJTXFtXTy9+s4tuWL2R1rUMUUxyptAL93WbvGrEIN0hEHihql53m6Kj1CIKew2S48xxrFqEpWfary3Gk8hKW+iyZBAHeUag+rLL4HhII/nwhaxC29wFfsVglo5ThQTHQbvMhWAZ2jttoOApcoKBG6svmj7IhgxyID1C6RiG7mtoIywRNmF9Q/Taj1W0+c3/E8HhcHQsbd22nR7+2220rWH0KhScPLCq8JHRIIKuk//6d3r5Zf2gS5VVOAn4pTPIGftMFvZV6P749a4WEaz7gu8USycUlDq6fgAmrOaOFkpOzxb63Ogk/Y6T47Jx8yAwwBiBbHx3ZxsN93dTkqVbjCWrt3SKwFivvkAPFM7BsaSsZJLH/tFai0GtJZ8M/uxv2KqbTxC65Em9MSRy9k4LZWQUY/b7f7+aTjr5FI8DT6nd12aOZRGXnqyiQdlXBQ4K25y1Uc9INVDFzp1+baMuAyKph5YBmJz0OJLJmTo7KKbfJCZquEaysnPJ2Dz6GslLVWQVJkeyCt/74WMSjsY+cyelUWaagc67bAkVl06hoYEBl97p2HasgE2bXESGlDSKSkqjbZU11NBsFLKD8fgfq5p/6Seen687puC+IQt1tRNLTEpxr9OuyvhShifP61DvjudVcIwsRFfX2IOHxwJh6gw5x1VXXUXLli2jn376Sdwgjz76aDFbCwd6PPRexGC1dvWjagCxYfNWun3FzSIo3rFlI13+u7PpD+edQS/cfiX1NFbQnElZ9NcbllFSTrHIsBWUTPG4yQFcBoB9Vx17irPGBsfI7g4oWQFH7aMdOVboBceLp2aL7wiu5IwVS4eBMhDHICK3WwZ+HnfI08scK8taCDp2KrpEPacKLfDKRTYKWrIjZmSpWVJvyU9PENpIZDntW7qOd/DDEvBB07JFsIrXf3djo7hZQUYBbTyO59vf7yRLdzvl5uZRTEKKWO2oqWugjRV1qrwCBRxYyXhzXYPISmelGujsI/akSdn6Ewm5PItgQS/gR9AoVzqOnptP+yqZXRTQ+Upegs5UOE6lSQM0ODjoNBgtLIDHsElIRYw+7NY30jo6zuOCozmzZpLFMiDakc/65UXUY4mmZ76pom7FhcYVasDjZqCmBde11BSPCo51nCq0k0xH3r/+RL3R2y0RY8x+9Yl7yNpRTxQTJyRungSeKFiW46P0OdZmjvXaZavd8dLdk0Zo26hnZmT4vY26TKhI3bQsRJZZS0crgbgWEBAj2YNrJKqvc8w1kq9k1+1XwGTht698jvU+DyzRYNV4+tEH0QNPPEdvvvGGy9USaaXY1dFGBYlWol4TWRMz6F8/tVL/oIWqjZ1UWe19Mb1W829qb3E4psh7kLZLnrx2Mw1x6uqtvdcx9rOjZIor1yGpOXaWNAjb4Phvf/sbHXrooSKDefnll4uvU045hQ477DC65557yN8gY33RRRfR+eefT3PmzKFHH32UDAYD/fOf/6RwoHvAM3sZDFb9Jpu34lBsEqVlZIvq79q6Brp52U20u3KnCJqHOxsoc/NrdNlhZXTgvovogItvo7xTb6ILlj3ocZOD9UqrZOmv6wgZnGm9GuVNOUpHOgK5hIxp9Rwr9IJjFAohOO0bsqoODYGSVEjk8rvMFLmLtLTTW9ZDFgh60GFNkaEr8/iCoUaRjTK9cRs9f9sVovByPCDblaXcrHwhrcDESJ7fsJMqzjLQIdNzVfP+bXVt9Pn6HdRh7qEnv6ik6KQUys3Lo5iBLkqPHRQ3wE5KJmt8Mm2uN1FPb594fmVTB/1vs+3Yn7lfqQi6HOmsZWU2tkNPR4zXtW1fPM0pSlc71UG7DwvE8dq64aaxYd16pYvWpU51xNpufZjIUnoh3XLLLT7p1jdi4+ZZhka6WLz15pt0y4P/pCtOP1Jk1+EY8+76OmpoaHB505aTDG/rAvSK8mTwJ/1Z7a0u8Xl9WdDkSeW9fREtxuxWo5FSMmwrAompmR4FnlJTjIJbbWAnM3kIyu2DE0eZdXfaqHd2dvq1jbpeQAaNtJz84DM6msThWjjjD9eoGnZ0Z7VP9uQpY5h9C+mRhlv+CY7tVxj3mZpHRUWFLq9fed1PnTaNLEMDNHvWTCo64jyq6higO//9Hi274kI64cQTvC6mRxdbub9mOPATB3IlUusRLeVveTrnkRxbIQ2VQa4W1B5t0DhLhbvPsdtnDTLDqamp9Mtf/pKOPfZYIWWor68XvysqKqJ9992XYmL8285XaPR+/JGWLl2qPhYdHU1HHnkkff3117oNA/AlMZlsN0aplQ4EeB8MZPL9UKwDkuKi3dqGjIwMysnLo7pNW6knPpairN2UWVhK93+0nTpajRSbnEHFedmUMJxCg93twjIpKyePSnLSaJuxj7Ybez36rLjBVCjLzuig5OxvS5WZJPqty+dJTZFtUMfnHh6TiYWWsLtvkKx2N5UOTWtJ+XpYhZtZkEJrazpF9hFMykgM2PGTAx8Ky1q7+tT3tT+uekgrreR4/WONAE0WP2ACgEHe0evh3F/32mOU1NtM+Xl5VF9dKbJRq1atGlcwVZiWKG7GtW09NM+Feb0rWpSBFcFUSjwmQlF09Nw8evnHGtq9fTOdd+Zt1G9uI1NUCkXt/WsqnjqbzrpuGb3wyN3U3tJMfXkllHjAb+mlnxro5/m76Orf3U0tzU3UYjVQwv6/of33Xkh7FqdTYVqCw/0UH2OrXoeusbq1e4zHLzyFpWUeEiP7TsmkabnJtNPYLbTCe09OpygXx9UZ8Dpt+OhfYqUnq6CMtm/f7vQ4zZ8/n159ZRUdvOK/RIkpFJ83xeV741xAoIVAxtGxN8nrMDHG488SGxtLkycVUkJKH1G9iU7aq4heePdzum/JCnrdMESlJUW0YsUKh5NuGfSgyYw3+1FKY2rautW/l01BCtNHv2ZKQrQ45gOWYVHo5Sggd+d69RSsgsjueNrXxZiNQHNn7UayxhiotbeHZi6cJx535/2NynUEGQK2WQbCmYbYEZ1oLzzO48YWUaW6t89xjHEMb7rpJmpsbBRSAPyMx/05tiIg21BnWwmQiUmsBjh7z0tO/hl91BhH+xcn0F2/XSzOee04nKPY6CHrqX2dkeDYvXttIMF1/8rLL9Mn63dRrCGNqjsG6J53N9EPLz9KseZGKptU6HLscIShoFzIz6anDdOqa48dtb/0gmMcC/l7uUKTr3Me4TpDUgerjLtbzZSeNNqiEkkyrAaY+wZ0JyQ4j2WDsPREx+eZP65V+9f3aXB88MEH07vvviusfxAEoygv0LS0tJDFYhEDjxb8vHXr1jHPX7lyJS1fvnzM40ajkfr6AlPAgQOBmTkONgL5DrPt5LP297gtBTnzosto8/LbaaCvgzLzCqht1kkUE51CSelZlNjdRAmWROpsb6NJJaWEcSI9qpv2yIunD7YQbalr90hy8l1Vp9AcpSbEUEYUttFxRjEjxnaiVzab1PeoarS5BBjio3TfNzEmivCKdU0tQtOopb7FVuEfT5ZRfzsnJ57W1hB1yMrweGtAZTSKpI2qGlupOTtK97g6W2LqN2P/jJ1pZyZFk3R6Kk6PF+elI/B5mxrrqSgvm1LTksmaEEW1tbViAMWSqLfkJNm2fXutkRbmjc/GaWeTtKSLUT9LXuwALShIoDdfeo7MXQ2UkZVNLc27Ka73Obru5H/Q9IJUevyxh2nr7kZqHUqku79ooh8rjbT5n/dQd0sdUWIamYzVlPDFc3TKbw+iJIuZqI+ouc9xc5G8lFgRHG+qaqS8uNHL7fDuBVMyYsQ+NViG6LApKSI4/nRbM50400CTDMNOj6sz3v12m5CKGNKyKNlgIEtmpsvjhNvetMmFVNHaR++vq6Ss6AKHr79p0yZR24H9m5ubS3/9619p7ty5Y54nr6U4u2vJE3Cmpw6b6eCiKHr6mxeov7WOjJRDPVu2iPd94okndG/ade228yDR2ufVe2fF225eOxpGxq5qo+14J0cPjnnNzKRYajIP0rbqRoob1JcaObpeMdHo6OgQgaunk8yaZlsmOClm7Hh05ZVX0q7rVtDO6gZKyCkSP+N93KFCcVNJTxw7hibGRotVtO3VDVSidAqEfEsWL0Ki09zsXuOWwsJCUb+j/fz+HlfT42yBfmVjG5m7bPs71xDt9H3xKe88fqpIuNjvQxzXRGuvWqiIDL2U3HUryYl+MzLjwbH6c8WeJZmi5qTMMEy/mZVId3a3kzUuhczWWMpMTfdqjN9WYxSa/0kF6U7PudRY23W2u2nkOqtssJ3T6fHDusckPzVWBMebdjdSYfzIChLqiCobTWTu6ac15loqLcwbcz2hQFLaSw50d1Bzv/746s69dTzoyYLHFRwvWLBAFL+99957NGvWLPXxtWvX0nXXXUdvv/02hRrIMEOfrM0cl5SUiJtKWtr4smTuggONixXviQM9MFwhHi/IyXT7hD/qZ4fS/euHydprpqGkFIqNiROFaocsv4X+jaxbq5EmlU2jK/56Ax2810yRUYhKaif6tFbMSD25sLautWXWsORsPwmxZ54Fw1aFuDHJ99jWaSvmyzAk6L5vckIctfcOUVJKGuXljZZtDMXYLsz8rNRRf3vIHCu9sGYkcJxRnDOugNBTCrIaiKpMNBiTqL6v/XHVo2fANvhMLsyjPJ2MVlFmNW1TJh/TC9KdfibcvIqLi4XmPDkpQVgnYskMX+PJHE8taKVPKjqoY8jmbDIetnTYjlFuapL6WjnWYdq3pIFWd7fTcEIatQ3FC4lQmtUsPGqnlhZReU4K5eUX0YY6Ex3XGU2rv9pMVQ3NVJKTTfU90bbnD3dTYnws7TVjsstl0rLcWtra3EsmS9yYz1TZvk1833daofq7IwYS6OWNbWKp8LPdvXR8KVFpaako+PUUo7VBFLFF9zRRb2+628dpQVkjVbTW0UbjIF3m4DggkEPxc1VVldh2fL///vv1M0txtuXN3PSUcR3XjKwcevu7rWSwmMkMaVecgQqzUsXnQpbR/rVxQ2tVbA9nlxVQnhe6+JnFCPTqyNhjVV+/tdeW/JhRnEt5eTapjiQv3UBN5k6xbY4+q971iiXrG2+8UQRUSPo4y4brMRhtGyuxP+zfFz8/+MRMOvexT6ikMJcOP/xwt193qErxc84Ye+yg5Uex6XBCqjp+ygJTNLsonVRInoJxJVCUFXQRrTdS11AMxQ/ZVprL822aZ2c0DiQIJw5tx0B5XFHTQFQjVg/iUzPVjLt0RSrB+OtFB9FAkZ49SD9Vd9D+exlocnER7d61kxpbo2gwpk9YIXo6xrcP2u7B0wqcxxjlhbj3NFLHQJT6PLPFFhCX5ev/7ZTcOtrc2EMdg6PHVnihf772J7rvzlsoxWqmfeaUj7me+pTaJEzwJhc5TgC4c28dD+6O624Hx0899ZQogjvooINo9erVYscg5Q992i9+8QsKBDk5OSJrjcFMixzc7ElISBBf9mCH+2OnOwIHWr6n1GSmJsW5vQ356UliJhiTkimqfX+9dwkdPjNXvO6y+58kS18XLZxRQkVZI0VKMwpswT9meV39FrfdHdZU226qC0oyXG5faY5NI4uiCvOARegbpX1OelK87t9Ll46+obGzwq4+299m2P3tgdNzhT5XzjqLM5MDevxkxTiCJ+37ao+rPbAqkoWJaQ72hba4CAb8zj4TLmhox65Zch11thpVLZk3AZwW6IJJ0T2Pd59KL2jIReRr4dvRC6fSbRnZ1NVcI25aMf1dVDZ1lpg0wBMW+7Egw0DN5gHhj/xTpZFakzJod20dRRvSxfMnT51F86cVU0qi65uEaufW1jvqM0ETJ9t0LyjNUn9XnpdKh8/Mo5fe+5weuvFWejW2h6aUThb711O9/taWXso45CzK2bqa+vu73D5OB5Tn0Ms/1okJgqPjgCyQ1IampqWJ/YaxD4/bj39ySdmTcUaPxPho0cAjOzefGrZspe6oKDJahsQyPMZj+9eGtWTvoO28L8owePXe8pyEzlj+PSwPQaHOawpbqjpboZqz99Ner319/XTtkutpx84dVFJUIFwbIDHA/czdQETqLjE+6L3vrJJsMWY3dVuE5Zu7DTaw6iGdOOxfF8EhgmPojuXvmrsGVD1vIMdFb5Bt7qE5lramuF5dbTcKuLLF5xtbiJ0QFyM0rDgeTaYByk5JFJl0qehLdTD+hgpIJKGLJrzRr1pyIy29/gbq7WylxPxiuvyvN3g8xssGSJNd7FfpbALNsXxeo6I/LkjXP5fUzrjtPervcc1Xt3TRw/feRv1tdUQpmbrXk0njYuXqeDi7t44Xd1/To3eGRAGZ2J///Oc0b948kZ6G1vfNN9+kQICdvGjRIvrwww9HzTLwczBkHuNxq/CkSACatjmFaUIH9NdjZoq2szh5sHo0qziLjttv9qjAGCAYltY/MrPgCgQu8NAF8Ol0BZa5pCWL9ImVUgL71tGSJOVz63XJG2kdPfpvkQkvyxnx8w1UAxCJLLjxxNFB2zLZkZVQvqYNriunCoBA7a3XXxMtfz31j3XZCMQHBXmyAYi9BVB5QQadfNHVokgkyjpEs2bOEEUje5XZJnjaCUJSQixdeOgMyjrkbIrNnCRcHxBg/una62lGoX4bZntkIxB77+JdRrPIMiFzUarxh4ZO89BpGcJP1dRUQwMUq+r9PKkYx/WDJi3xeeX0yFPPeXSc0A0yStFNOvIRlUVUsGdsa+9wWkQ14lYx/mKk4uw0WnLDMnH8LIMDVFo+1WGRT4PJdh5hXPDWZlC2hocDBSaZCHTk59FrciGL0NzpkodjhOLT937aSTX1DZSekU2xicleuTWobhUOuloiEEQjHNhWOuvY6LABiN11NLpL3sDYYjwPG4AEA3msEJC58ji2H6ectcXWdhzVNmAChnHYXQYKHOs5hek0ffY8umTFQ6KYPvW4v1BS/lSPbTbV/eqicH2kS17f2O54qfrnUpmSeIDjkGR7cxd9uqGSzO2tYpXPGpdEmdk5Y64n2aMgHDyOgdsjJz7o7bffTv/3f/8nXCKg8T3vvPNEIV4gQXB+7rnn0t577y3eG8uK3d3dwr0iHJCZY0+8FzFbfur8fWh9TYcaTMBmBa01HbUbBlNykkVAt7m+U/ULdgb8Z1Hhj0HIWfMCLRjYoAVGIALfXVcWUnKgcmrlplPJumdJBlUYu0WBHiYJgUROMmQBjjvI/YCKc0cZI2nEDqbnO/Y41mv56ytUr2O7Ri7eICcPWRpvVjkRvOikw8iQN5kmG6w0r3wSLZiSqzaF0bpnwOsZ/t2/OvogeiW7mI6ZlkIn7z+TDphR4LZ9n/TjtA9I1imV1FNyU0ZloPC6RYlWShzqIoshnczDCTQ1z6AO7u7ubxRF4RzGZi6ckjfm87m6UcFXHLaIn+800pnZpQ6r3K+4ZokoxnXmp6r6HHvoVuGIU35+IN151jIytrTR8iuOpD2n6+8T6Sph33rWEyAdQIMhTGREB04lBYj9qefbLCdjsgGNM3eJiso26h2wUrwhTTRuqK2qFL/r62qnmTNneOTWIN1rkLzQA+cYxsfKlm7RGl1m3VzRIltHa2zcJLlK0KK1rpMBjb3NXSgixzxcKzjG7roP2duK2YNCzW1NXer5J5MTOGf0ss2hCCZ+0O4ODBXSW5uN1NY3RJ/vaBFJA09kIfVuTjrkNYqJFgrnsZ+alcxxvoP3k02npJMMzj34JL+3wyzkZChEFr9vaBeSEO31pLq7hIFThUeZ4ylTptBnn30m9G1wjEBG5OKLL6a7776bAsmvf/1rYSeHlP1ee+0lNM8oFHSljw21zHGyh/YyuMhlcJCZHEf7lWc5DYzBjHyb7GGLkg12hWzRXJ6T7HZ7a9lSUs4kpT+tvUvA2BbSY63c5MWjJwHZryxLZBHTqZusFs+acYwXuZ9lpsgdZObCWXcm6dEKdwdH7VP9jcwc47ON1wpLWlBpvVklZdkpdOLCUlowawqV5KY5bHOLQRk30F/ML6R7z9ibTj94Pk3Jz/Co6Yt0O0AzCm3WBXZkjpqtzJlSRCVFhcJOrq2jk+obPW+e82NVmxqcexIYa1vlgm93Oc5ezp47n5be8zg98sxLTrPSI1ZuvrGxgnUeVgAgE6gzOb7+pJ2Wu80o9MBNWi6/Y4IjW0ljUqw3QZKNQJy1kG7q7BOuOj2K7Autf39zybWUnFNMPX19lFdSRitWeGajJ8cDjMeOKFVWMXYZ3SuS0wb5sl20llw1c9w/pgGIN77SgUZmJDGJlOOFL1YCC9VJfu8oWZEnnWhDAax6oVMqVocB7EsxuXKXUd7RLvYrzi9cTVjZwEQP3+XqX76Dya0MjrFagSTGjiYz/W9zE3UOEJUefT5lF5UKW8rUvJIxE3cpQ3IVt4RdcAwf4TVr1tBxxx0nfj7mmGPo448/FgUif/rTnyiQXHrppaIYBTZtaF2NQsFwAJpHVBp709ISy3MA2YeFkzPHdGTSQy7VY6nXHX7QdPZyF7nMIi9gV5njRNlCWkdWoedzLCmhZrK+fw+ZXr/dK/9Hn2SOvZBVODOgx/GJHh6i6alDAQ/4JZjFI7vti+yxzKzL/TWm3XhstAganXUClM1O8Nx0ZWl+qtK21NOAv2/Qqi7lASkZwoqLPSmGRLrx5uWUnFvicHB3BbpWAmR6vEGu1kB76AghCdjSSnd92kgWcjwG+FJWIZmiXOtYYXKEDE7G60WulfvI89JRNkvtkudEVlHf1kVtrUYaHBwQ2bn3NjXS45ut1HvoFZR50g301789Thkl0z3aRtlO29kysTx3pT2mO7Q4mWRKqUWLojMela0Pg8wxtMEyY4xpK8YevfHCU2TbbFhuahsw+aM7nr9Bd9EjZ+eLbDlWkr6rbHO7dbvWO9qVxzkmvLIDLK4xjN9YpEGiPVtnYgYwaUUyB4H0j1Xt4np/R7FYPfsXh9IZS+8XkpD9LhpbrxFODUA8Co7POOOMMY8tXLiQvvrqK/roo498vV0Riaye9eaixSCy1+QM0SjC3eVlOE4Ad2eeG2TzjzLXEgytdGNU5lgJcB3dlKWswpPgGLrPlbcsp2hTIxVkpQqxv79bnWqRA4g0MHcHGZw4C46NVdup6IeHqX7V8oAH/BJRDKcEHeNtBDJyU9crgo0S/tRzi9JcFibhpiADaASa7hYySRBQyyVpre5YBihoLKPHUQfvRyddc48Y3Pc4zzPnArBJaTAyb5J3TjiHzLC5MEBz3GIeO1FBFhyNSl5fW09rajro20rbSo8evpZVaAM9Z1lQT3SkzpAZKvhvN7hoMSyDY7kkbM+aNWvp0t+dTTdf/Ue68qJz6KpHV9OqH2tFdhGFzkZLEn22s4N2t3SrlmiuwDK09GyV44Me03Jt57En2b9WJ5lj+Zh2IiDbJsvrOJQRLgSaz4Vt9kW3U7kSJccwuXKX4sPJYaBA0Ipx7+BpOeJn+PvLQmJXSLmDuxKbEZlLn9oMBAWmMQ6kKHhc7us1Ne302po6MdnEavM+ZZl06OxCsbq0s7U/rBuAgHGXApaVlYkAmXGNXNLDzEtmgt0FA4jeYOmM6YqsAhlPvW5hWrp6B9UL8KCptovSk5tYjWLSr61IdS6rsIy52XQ5+FvZ6jQnNzdgrU61yJsfshH9Q5Zxt44GCOwR4DdW76YUQ1LAA369JcnxFuXJJTm9jBeAZZu7WQNkCecUpamBj6fIQErqjjH4QxuP+7Cj4kcEkoun54nBfUMDAiXPsvnQPAKs7HgDqvaxnImM2ufbbXZMWnAdYwlTurY4y/S7MznzFGi1QVWb6+B4vIGalBkhcyY/p6NstJQn4fyzL17C9bT0+utp586d1NBDVLlrJ1X/72nKSIii8xaX0Tn727Tdr6+rF9rJLY3uSdCwf+VxcHazn6JMKJztMy3IyKkuGDrXkZz0afXV2O5wCY6BVj/raMLjKXJVQZ4r3QHsjucPIFdEe3vEqJsaTLSmukOVijgDTiaeTE5HChn7VVmSthbGkWwNEsdP1+2gL7fbssa/3qdE3EcWK7FDbXvPGJmejEEiTnPsjMxM724GEw15cmv1w/4EyypyMN2h3Lgd8fWuVsJYj+fDAsZdpDMABiUM7FJz7ChzLN0q7AvyuvqHRFCglzmWVfqm9lYymQLX6lS7H2ElB/TaZjqVVTjYDzLgz81DwJ8Z8IBfV6M7zuBYajAdLZN6Whgznhun2mVNmbTJtqaT0pOc6oGPnpNPcdFRQo7xvSIzcvezy8w5ike9RUo+vtHRHSOz+dn2Eb9vmVENlKxCSqhq2xyfJzI4KVQaVHiLbFWLyY0acDvIhsmkAQr4ZDZXguupoqqOuiiJLLFJFJ+cKeoWrj1sEh00LYcOnp5D0/NSRPbrhe+qqbVrJEhwpxgPk31nEje5z7Bf4LzhCmTXMA5GOSj0k6syciIKqZ687vLTA1uo7C1aPWux0mV1vKDTp7ZToDuytlAGq19Y+d271HaPgwxIasudgZUWbVGyK2SGGee8bB3tqgV5oqmGjK+tpNfuuIKaX1tJM2JbaUZ+qljVxkQVTlWQZ2y1q3WS0hBYtYYDoWv+F4H0uFGk5WuQrdMu+ToLjgEs4zxBapBQUQ6RPjLQwJHeCW2S9WQVUo4Bmy37m42s0ocFGDobOqvS9wcI6qSDhiwicQWCfWfHWgb8bS3GoAT8WuRAWuOB3ZTeuQ2NL3CkVwskI5ZDtozd2hqbjndGge16cOaxOzPXdnP4aKv73cJkW2rcbFxp/ZyxT1mWumSpBSstH25tVrtEAlmoZg9WN6THti9lFbL4Fue2LJ7VgqytXJotHGdxmMx8ITCWn9NRZhSBhJwEGO3kKLieBuLTRKElOvZlxvRSWUkRZWXa9jOSFGfvXyqWi+FmArnKtsYul4GsXCJ2lQVDIAhJHIIFe2tBPWShHcYbPTmRlCRgZQqZOWSQ8drY/hw7l5hQRXtuyHNqvEi9NRJQ+BrRHIdncCyLOY+Za3OF+a6iib7bssvlyiJWWjzZr3K/oWBVXrvOViAGBgbox1ceFa4UUbFxNNReR62fPkMFqbHiOsT1hMkmwLWkpb13gskqGM8zx8leVLJ7y3Q3HSt+qGgmi7md9ijyrPhJaJCUiwlaSSmrSPXQrUIuuTiSY0D/iep8X3r8+lN3PJK50D/WMuCHh28wAn4tRUqWzxMvVnvkpAFyoUCe346QNwd5s5CTQ3iJOgOD+8ISm04UhTCQ+7jDT0pwPNNNSz5HIJMJYFsodcOgrqOHPlaCdZmZr1ecIRxljX2dOUPGXa5E7dbxYsa1L1eExrvELzP/kMPIbLSjzLE2eywzh5J+axSlHHim8Gg2xFiouLSczrtsiXCrQOAEbScCcSxhg39/Vy0m6lofV6fFeC6KyXA+yc/ijm5UdXxx8LrIyiEZIZ7bPaDuGxyXcLEs02Ymx1u4qT3PZR0P9okcf0NhLPIWTGwXlGZQsbWZml5dSVde8FuXtSlyDHdXVqHWmyA4duM6a2tro/6uNuFnHJ2QTDm5edTT2UppUf2jCqq1NUyS9u4ILchjfKc5DuRSj8wEO5NVfPr19/TJw0uo+ZUVtPpv13hcGCaXxpAZGWkC4iBz7MCtwplThb3HbzACSLnE6a5jhTvLesEO+O1vUO4s27n2OI4PiGTI3WV5WaAiz/89Slw7sRw0xfac7cI31b19sqnOFnzP9bIYTwI9NDIrkCh9udOmO0aADonH1sYuoZk+ecEk8bijbTMrwTGCBWeNE7xB1hjIjLwWGajhGvbGys7+po1Nh1RCOo44KzKSFmf2jhU/VbVTd0oxFZ56Hd1y78N00/1P0Lw99hDHaf/yLPF5MJH65fwikZXFe61eW0dtpm5qbGx0mKmTUgZHHsd6HRvdcaxw1gAE4NqSE3X4IatOHg6aNoQiQldvGRTJmDyD74JXbSMQcxBWaf1BYWoctX/+rMjUmoeiaMs2582JpDROTsjcb8rS55ZHeVZWFpVMKhIrMVGDvRTdbxI/5+Zkj7GkxHhFE11zzPjO+9bXoKgJ7HJQLY2L7C9Lr6e+1jqKjosnY22lx4VhpVkjFk9q21pXmWMHYn1P/GwDSU6q4nXsZiMQV7KKUAj47bW9kMV42o1J0uaiGC/QlCgTNgz4kHzIQpW9il3rgWfmJYtMHKRCkDIEohhPG/zMU1xmvlGkTtACfrC5SfwbbWbRTc+ZO4M/ivHs5Sp6XTfhKz3eBiASSAq0xZiw/3LmCiGLvOyD4/eV/TZ7UpZoEz2vJIsOKM8WS/tyEleemyIm82fuN1n8/M6n39DvzzuTTjjhBIeZOll74GybtNZcYKcbXsdSt57nRJqUo9Edy+54zrJ9oYapdqfQrCIZs/zKC33m0iP3gbjmI0BWIeg303BPByWlZVFUvIGsCakOa1Mgp5JJCncz8tqmLFJz7KzhSHx8PN1710raY84sKkiOoSnl0+juO24fdf9aoNRcoCOpXHkT9UhOmnyFIhwcBxCpgwpkBa3svIaMiJ5OsNnYQrV1DWKZJC0tXehePS0Mk3ZuqPSWq9CuNMf2bhUyOA5VPZL0Mm3ztCAvDAZneVPpHxrtC+yVjVuIGLyL4Ef5TF/uaBHFpliSdsf9IiEuhhZMtg3w6FDlCqyWyKzLgnEGx1orxZ+qbJq9Hc1mtUHPz2blqj7kmIBp25Rrt8fXemN7Ozc9a7IR+YNvlsq1TS3yUp1bfuH39sExiuy+qbSNY8gSYxUNKwr28gNk16FFnzcpnRYVp1D7Z8/Rtu3bKT4hwaGLjCzIc6ehgdRgumPnptq4OTlP5e/gdSyDY1+5Pvgb7Mdn/nGnqlmtrqzwmUuPXFmA924kyCpkpra4qJDiBrrI2t9NLUajw9oU2YAHGnd3Jm3azDFkQnLl0NUqxJ577knPv/gfWvnIs/Tyyy+PWfHEZBOTWdSgSFkbxiSZduGCPMZhQZ4jHao/QHAmizhwk7VnINZAg7JgZbjPq8Iw2QVqS4Mte4YLQzaW8FRW4UiOEWxk0CczpJEUHKOQQg6m3jpWyGVmZzf1QAKvZBkIv62Y1CNIcVfycYiSnUWhnStLt/U1Nm0dss3u3pScIa0UkY02dvXR+5uaxEoLKsEPm5knfEjlTV8GR1pUO0U/eLzixudIPysnCMXjdKrQczJwlY1WvY41wfHO5i61YYmwxYp2HlzjNdCuHJk6ZOjMw/EOXWTcaQAimaIURaMmw21ZhZPzSNsue6QjYXhkjrEfu9pbKTsnl0oLc71KxriUh3X2jdT3hMH46wxkZO9aeRsVl5WL5kTRGYUOa1O0ri7ujnOQBUHDPqwZN9xZ+UlPSaKZ5SWUn5miu+ojE2ayFkMmXbBy7KoVeKgQHlsZIcgL1t3WzL5CLuttqh8tkAebm3oodr8zRMFKWhx5VRgmdYgya4OMlaOLU2bNw01WoRbkKUUFrgi3wVneXL31OnbWHS9YyJvlx9ts0ghH/sZ6/GxGnrhpICNuX3Vtj7wBwM7IF6BJCYJfZL3f3dikbv9hM3PVQkO59KnndezPzLGcCOvZudUptnm+ymJO1thRuXK/0GshDU9orBjAM3muIlVxBorzSiflU2FhgUgWNDa3OUwWqG4VbpzvZTkGtbjQlU+6HEOdZ46V+gfzgEsnj1AD+7GgIJ9ShnsoO27Ipy49csUCE3y1CUiYjL/O2Guvvei5F14SzYnSj19CxVNn6T5P1ld4UuSICaO2fwLGPHcmfIb4WLXYXw9ZmLxesdCUq9ahujKsBwfHAURmSwN9wcqbtszsarOb6L4Tn1dOh/5xJb3z1pteFYZJr2OJs4yVoyYgoR4cy5ugzOy4GxyHy+AsB1RvM8dqlX0I2Lhpbdm0+lC9ttGOKMhIpBlKl74PtzjXHa9XqrLR/c8XxMZGq4H8a2tqRQU6XECOmlugVnrLJWQ9r2N/eBzbF5fBUk56mkuke4avZBXy+LlTfS8bgcjgElrHL5SCxn2mZInVEVfgObOKsuiUi64WyYKevl6HyQK1ANWNQAKZXsjJbHZuveOWJ8nMMbooqvZbYZI5li49U6dNo4H+fp+69BQoPs+4JiLByk3LnJJsKp5UKDo6/lCln2WXVoHuFuNJtE0/ECi743qSnhTnVB4qx9rNikuW2jo6TDyOQWScOWHCSNeewOqgZhem6jpW4GL6aqdNy/jz+ZOoeFKRV68PfTEC4hEbN8cB7oisYiisgmMsZWvlA66QjgHh0r5UdiTz1s5NThp8ISvwFaVZBlEVb+01U3RSisO20Xpg5WP/KVm0ud5E34oGOcMOV0PgiwukTtkXLCrNpB+q2umnalvWet8pWWpLbXt9pT0jRbG+v5Yw2UO1OZZJIROATlei6l99FKhpb/Ku2uHKzLE8D5GlRatt8LNZeR4Vch68/yJadfJSih4w03/uPJ2SEsdO+OQ44E7lvbRzg6wNjVzQLMFbtwrb7+JVCQk+ZzhljgGSL/9+aRX1dXVSTk62z4qRC9KS1NUDmQ0Nd82xVheP+zgCf3TLO3pu4ZjnVCsrN3J1x11suuNOt7rjucteSu2FLNztUDyOM5ND8/6uB2eOA8hIkUBgAyZ02rF3rMDNHk0OUFiCYP3I2TafT2/RLuU4C3DVgjw7WYUpxINjeVG7GxyrmYswaV8qrc8wgYKFGQILyAUQGH6xo2VMK1BHGS/pgxsKWFt3q1XxLatXkrm+wqO//5lyTcCSSE/bK1dAZBe+RUo3K1+weNroFu5HzM4bFQA5y/SPyCr8c+5JGZVWd4zxxB0/Yk/AZ5SWX9lJ0W4Fx8hQoYHHR1uNoiAI48mBdvvSVSB78PRciouLp+GkTDJ265/3MhPmjqxCG7BIDbQe2IdyfJHZYT1k4IcCP9l4J1wyx5KM5CQqKir0qUuPnEBh4iZlL5GSOQZ7KE47ctJnj0xsyLHcXbQTT1fd8dwFq2hRaufQ/rDzOAYcHAeQbkVKEOgLVlZLY0CXhSQo5vhkm60V7X5TssbdqUjeMF3dlGXWHP6l2i5U8mYT6pljbKc7dmfhJquQOlEMsMgIItBpMw+IJXoExvLzuG4dHRqyClS/v/7EvWpVPHU20M3LbvKoKn7R5AyRCYel20cOpBUb6jqErjUjKU5d2vcFuCZl4QqKWw6Ymj2qY5qULtR1OJFV+OncUwO95pHgGM4ZcsI73u54kpaq7erk5p6//N6p5Rd0kmjxPqyci58oOm2sFrijodSCYy6z1hUtY4NZSDY6PbByA1OVQkY9Czyt7A46c1eWiDI4lpIKjLfuyEZCCX80LIGeFfIj7WQ9koJjuTJl7x8skRNlTxuraCdWrlZo3AX7Xd5TNtR2qp09w8XjGHBwHIzMcQDdKmzvF6veuJEVFN8bu9RCoiPn5I97RieLTlwFx9rmANrscWeYZI4tw/BrdB4owtNRfrZwkVXIAdVRkxM9yzC9jFeoyCpQ/d7d0ap2ckrPyvG4Kj4pPlb17Pxsh1FMGHADQtEiJEmYREirt2n57jthuAOCHWmmf+SsvDHZIGeyCn9qjrUt6XdpAkeZNYa8arwNQAAmMbcsX0bRXQ0UG59ADTXO/dex7CyvUWRU5dh26Ixcr96/XKm2l+Ol/f7FOOBJgZGUUlQ66ZInJRVw+nEmvbMPnH05KQtncP3ZywICfa/1J9ImEoG//Qom7jnSqcXd7ngSWLe5u0LjCbJgb21N+0hBXhhpjjk4ngCyitGOFSZRMf3OxkaREYPWdHH5SHcbb4FdkbzADDGOM6uY2cuuXdqivFAPjhNiY1T9Gsz3nSErpcNpcJYtpHEckNHHsUFxEwKgnyqb6csNOx0GJsgqDyirAKHSBET6g8J1AP6glp4Or6riZTvnH3cZ6bO1O2jd7hbaUm8SOmMETmsVTbCvivG0LDlmJl398xl0zPyCMSsQMtsjs4daZKGcPzTHYKoS6Gm75Mmsla+WZTGJwWRm7tQS2nfGJCpww/JLZlSR5UcAAUvJI+e4rzfWMjUvVU0i2COX7BHAYlxwB2lt5czOTS3GS3HeZRJFgNrfhpukwp/Ya68jKXOM2h45KUbnRy3QWSNAxr1Ven67S1fdSFOWZ2+9wmdNWeYqYyJiDrUgjzPHjDNZhSEIAdOIY4VJZHlkJTf0eIU+sF7qb9ylXmAv33WVwwsMg35iXPQo9w4sU0qdZKgGx1p9obw5uirGixV+z+ERHCPjGxdlEZObPz37HV324hpa+toGuvnpt+nmK35HF/z2V3TiyafoHleZxcBxDWSDG2dAy3jbbbdSWn6J8AedMX2GV1XxR8zOp6HmStr87M209A9n0Yo/X0gVWzepv69SKsQ9KfZzl8LUeMqP7aO85LH7VN4ksVxprwc3+zlzXKbIKrTOCzJz7IuxBGASg8lMe2sL9Xab3bL8khnUN9bVi+9w/JiU4Z1cbKaS9dLrLKo2APHgRl+mBMeYcDrS74/YITrPBENeow0yfCVjiQTsJwrJITIe+QpZlCtXRiTSgjM/NcGjlvH2TVmMtbt91pRlT0Ujvb3JrN4zWXPMOPe+DcIFi+5QABXTX1e0UlVrj7iIfjG/cNx6NVxIzz10l3qBtdZXOb3ADHGxoxwrzANDI531Qjg4lpIBaVsWCQ1AJOvXryfzW3eKyU3jq7fTQPMuESx3f/k8DbXXEcXE0uat23SPq8x4hYqkYlRV/Iur6Io7/48+ePt1jy0KQa4hhga+fUGc24MUS7VVlfT0g3fQ4MAADVmsVNtqEhOK+QW24MdXYBJy8bm/oWWXnUN/PP/MMZMSTCJlox2tt28gMseyXTwkOPIalpZyvnKqkJZfmNQMDPS5Zfkls9ayeHLx1GyPAgUt05RkAsZJe2Tdhic3elizIdOMYU52DbNHXkfudHHUWr35ap9HAlq9LSbr3h7/UEV2x9xgV5RX66XHOFZiOttaVPmZo6Y33iATBihYlpNn1hwzuvQEsTHEHGWJA/3OP9jSpJ68Wnsob7FdYEb1AsvMdq7vtPc6lsUtuNmHcmFJtruZ4zALjhHsIuhN6Wuh0rwMyhhqpZKKN+nmIyZRQXw/pWZki+OakJKpe1xDrRhPy4EzC+isn+1JCQnebVtHR7to3Ypzu8MSR11koI07q+mmVd/S1Y+9QY2v3E4tr91Cf774HJ8tR8rjUbFzJ6WnJuu2MNbqK+0bgfhbc5xusFk3aoNHbxoQuAKTmVdffYVef/0Nt/zX7YPKo+cWjFuGhnNbrmpJZLcvTxre4HiVKLpxR22kZebYmVOFRNskJJ+DY92CsuQIyxqDhYruWNpH2jtVaAvj3QErMUWFBRTd10VRg71kam/xWVOW3NQEMYmHPF9252VZBaNbtCRlBMHQocqCEHgRS0kFilW03XHG1/WogKL6bP3f0R7U2QUmC3Zk0Vqot46WZCnBn6OitXDtjif1nfl5eZSdmUE52TnU0WakKIqirJxcVbfb0mLUPa7yph5KNm5a68DxZFDxWaeUFIl9MNDTRd2drWRJSKem3mGqfPefIqOcmpykG8CO93ggi5OblekwmyP1lfY2c/4OjrUNOqTuuF4pDPSVrEKCTHHJpCK35DDawjS473jSEVFP3ymzXPbBrMwce7pSIuUoSFDoIccVd3T72s8aTh7HgZRVhMv4601RHorv5HlImtUI6Vfv6QrN4kXzqDwrnmbM8E5+5mhCaO/pzbIKZgwoWEIBXLAuWmhBMYiiaK67vVW0iv75nHyfWOrIC6ysfCrFkYXmzJ7p9AIbaQRiCQuPY4m8aWkHJWeyCn9Zafkaqe9E8NttNlF7e6sIijNzcum8y5ZQfkmZ0O3GZxU57Rbmi4mWr8H5PZ4iQXzWe+9aSXNmzaRcQzRNnz6D/njN9fT7AyZRXmwvlRUX0vwpRT5djpTHAzrbzs5Oh3pbuYSq7ZIHqYecdPpLVgHKlOC4wtg9aht8ZQXlDbmaQqR9yzLHvQolLet2Npl1Ncee3ujLVTs3/cyx1I26cx1pm4T4qggyEoDFoTuF4eEK7pFyMvSjpihPtnPXdpV0F6zIvPSfVfTiy6961SHXGfYTVFhehgvhcfeOAGQgCAxBkg5k9tXT+tf+QZbudoopKKCOEwqIChf55LVxQX35wVtUWdtI86cWO515jpFVhElwLP1SXWeOw6t1qZzcIPNZWVNH5eXT6PK/Xk/TCjNodvF+VDrtWbro8U8pPTNDd+CUGuysEMwcyyzgeNh374X0wBPPUlNzK6WmZ1BcfLzQHBcWFggNcl9qArW2tAhdrC+WI7XHAwG3I72tlDA0aBqBaP2o/Zk5nqLIDmQWVOqeg+mcoJVVHDFnfE2NpAPP2ppO2mZn5yZtqTzNHE/NSx7TPEUC6YZs/+vOZE4bQLNbxQht1TZvbNzjLLl5tO7IbJ8Ge6HAzIJUsVq0prpd2LBq3WKKvVy5STUkUbxYofHtPXgPRSMtCfV7vJbwuHsT0W233UZvvfUWrV27VtwkOjpsFkrhgswmQlerNfMPFFju3fXOk2IZGPrJoY56un3FzWKm6KsuReludj1KUgvyRgfHoT6rzHazIM+saBTDRXMMcAPBuYDMJwI87TFEZio2JZPMgzYvVvvMlrS2ywlBzbGvKMxKpcHhkUktAmRk1VGcN2DucKtgzFfHQ90mJRCVGUetpCIxNpri/DjOyOXS3a09IrCT13IwM8dTc5MpIdpCqdRPi4rHX0sxQ3Gs2Gkng1BbR3sYHCPY1rNzQ5IALYE7unpExjM93vVqHnTJyJBG9ZspJXyGGb/f4+5deYt6j+s21ooJpi/vcaFSlPfpdiNtqDepks0GZXLqqcexBA2HfGjTriJ94uX9MBixj7dEh9OJf/rpp9Mf/vAHCkfUdsJBCphwkx3u7RCDRmpaOk0qdO0b6imoDHbHysvgQHMc6rNKeTN01UJaWvaFU3AMcAOBdtz+RgIZjMxO6fm+yuYFoeZW4UswIYiLjaaEuGixP3AO77HnnvTQk8/Tm2+6VzDmq+Nh3yVPK6uQwXGKHyUVoDTblgVFtlMWBCJTHUwrv9qKrZT77UNkeuM2uvDs34y7QBIZOrDbTnMsV448rbyXXsfoTipXzQaGrCIDuGXjBtr07M3CLWbFlRe63PbOuh0iQ9ry6q10+umn+awYNJzBvay5uYkSU7NEAXFyepbP73GhwCK1KM+kupzgPIoap62fPybT5bkpaqfPcHKqAGFz916+fLn4/vTTT7v9N/39/eJLYjLZTiar1Sq+AgHeBzM7WfGMm2qg3ltLRkYGzSgrpvZ1myk3IYU6WjuE+B6P+3J7kuOiXb5ekvQ57h8Uz5XLlKiAD8a+cZdMQ6yaKZXHVW971WOdEJxj7Q9QvY8gbGNdB+1fPlo60KJ0ZspKjgv7z+vouGYkxdLB05w3ywn0Z89LjVclDfK9Tb22aynFz+feZCVDhcIgKa2Ax2qwjj+SJ9dffz011uym9Mxs2r59u8garlq1SkwunF2v7vg5Dw1Z1PoM1cotybPzPT0xRhwXyK4qW8w0PS/FljE299Cj995Gfa21InlRs3vXqG3X+6yvPH4PRZkaKC8/b8xnnUhojyvuZdDmb65aR9b4VOrv7aH86fN8fo8LNnsWp6kNgNq7+6m2rVstiEYcGkqfNUq5juB1jOSXO9vmzbXqCe6+btgEx96wcuVKNajWYjQaqa9vdIW3v8CBQFFNfadtYE2IHhYFNsHgz3/+M9204jZqb2uh0tJSuvLKK4MiTxkest1cWjq6xL5obLNNWmKsA0HbN+4wrJwzuDnKYilcxNHRo2fcxnZbdjVqqD+kP48nTE6Npi/hv1tlpOaZoyuQW8y2/RI10E3NzeFdBCOvV73jGmrEDgyqMp/6hibRdKamyXY9J8WSX8897B9DXDT1DFrpk8214rFsQ0zQzne8b11dHWVmZFBKioHioqxUW1srAkcUS3pzXONFxzFbMfX6iloqSlfcapSVkuE+jF/6DT0cUZgWTzuMvbR2Zx21t8ZTV+8Q1dQ20vZKW2CclpZGWSmjt13vszY11NOs0gLKzEgnc1es0+dHMvbHFfe0tVfdRM3NRsosKg7aPc7f5KbEkdE8SJ+s3y2uQfFYcmxI3m/KM+NoW/0gRfe0ivPU1QTO32NwV9fY1c8JFxwvXbqUrrrqqlGZ45KSEsrNzRWDUCDAgYalSbxyAqcnJwZtAMP7PjxtPsUOdNPUEtfaYH+RnY4q22aKik0Q2zRIto5WRTkZIT24J6YiGNlEvYNWkZ3CccW5ZH8BW2MaxPf8rLSQ/jyesLB8gP69xkjVnUOjPhMGsM5eW4AwrTif8nxs5RVo5PWqd1xDjRzrMMVGbxAuOMNJaWLfx9TZAuas1CS/n3vwVN3WZKb1jbbJUVlu8M53ZAeLi4tFgJiQEE/t7e1iZQxfMnPszXFF0WN1Wy+ZhhNpr7xcZRXQdr5PLS6gPA811lPzakVwvLXNQrnZKdQfZ6F/bami4aQMos56Ki1KF8GcdtsdfdYt27aRITFhzGedSNgfV5x/f7z1EXr4vfX055MW0uGHz6JIZFZhOhl3tFCFyaq60pQG8fpzRkn0T0IC9ENUN/3pyym0YsUKpxI0f4/BiYmJoR8cL1myhO68806nz9myZQvNmuXdCQ7jfz3zf+zwQN74cKB7Bqyq5jiYN91J2emUnZwrtilYSN1135BV7ItORYYAa6RQDkjSDfFCV40e9h19QxQTFaV7Lkl9OXSfofx5PGHOJFvVcWVLjzh35PkDvbi0KMxJTYyIz4vPFugxwhuweXBogNwF8oaSrGQyK1pWOHT4e/uhO0ZwvLnBtvIzKdMQtH2GG57W4UP6tWpvhN4c1/KcFBEc7zR202Gz8sX5bkFXA+HOkuDx552KQsZNTbSrpYcOmDpMD39SQfVdQ1R05HmUtukVsvZ26m673mddct311Gpsdvn8SMf+uF7689mUlZ5MZ+9fGvLXsLfsMSmdPt/RQhvquqgkK0m1Hgy1zzswMEBf/edhShtooSmTi4Qf/E033eSySNKfY7C7rxnU4Pjqq6+m8847z+lzysvLKRLoVtqsBrtIKxS8aJPi7dwqesKjIA8XLIoKUACBorzc2MjokOcOU3NTCJJLfDZjVz/lKV6bcok5OT4mpLsbRirwPEVwLIvyAtEAxL6LnBIrBtWpwl2HD09BMPvJdiNtV+zcpN7Y4OX5Pj0vVdWJP/lFpbCJg4PRX848mopSf0lzcqKpMC/X5bbjs772yiuig6OvPmukgEzqcfMLg1ocGqhmINpOecVKB8ZQoq2tjYzNzcIAICszQySXZJEkio1DmaCePUib42siIK3cIvmC9aRrmZ6VG9rShjpwZLAFx4OUO9rCccyxjqTgGIEAKqFhG4Ybuhoce9ktjPENhRmJtKZmpIX0SHAcF5AJ06htGUelvK8dPnzFjPzUUc1O1AYgXk7kZWMR2U4XwcKfDpsmsvBwQpk8KcftVb3ExISQDzCCRXKE32cXlWaO6Y7prY2bP8lSGhpt2bZdrBhDE+0rP3h/E1o5eCdUV1cLj2N8t1gs4t/4Mpv1W3GGGjIQRLXyRGfEym0orKzctEGgMzu3cGsf7WkTg011tmX0cGgAEunYNwKRTimBmJiVKdZkkdyMQvo5yzbZ0lnHU49jezs3yYUHTqE5RWmimBLZwGDK3SKJSBt77cH5J5veyADZ2wYg/iReaWg0c8Z0YYLgaz94fxI2ZxB0Kv/617/UnxcsWCC+f/zxx3TYYYdRqCO9bw0RftG6g7Z9tK3AZShsgmPZttUWHOsfS9VrNsKO9cz8VPpsewttVfw1tQ1A0JSACTwyW1vXEXhZhcyCjmxL5AXHaCwCsFqEFSGsGGkbAnkK6ipykqKpydhKZxw0m/adkiW043uVZETceBFMpLduJIPxGBK3UM4cqxKgV1/1qdwpEITNGQR/YwRS9l/hEBhrl9qhzZzoaNtHI8sqC1zG2+Y3EGQpLaTblQxSKOvLfQ0yXNolYdCmZI5DQcs+EZEBaX3n6MxxIK4lTIgSFc9ynOuRmK1DMCsn7ZUt3arm2NvMMZp1JHx6P0W9fxd98dhS2rVtE82blC7eh2E8Yb5SJA1wjoayZDPeRUOjUCRsguNwpyfIHfJCUXOM4FhKKuJiotQbbTjIKqTW1h6rdThij/XswjQ1SMDEFLDmOLhIKQMKvLSSnkBkjiEBQBEQ2hhnRnWLyvRIRGbIdzab1UlxphfBLPYP3DSMtbspI8VAtVWVtOqxv1FGQuiPe0zosXByRkSv2gQbvioDhFnJJiaH8OwuGLIKU69tv6QlxYWF3i5b0dbKDJI9PYMWkm0wIi1zDL0kHCtw3KTOTbaOlnITJjiyCiz7w2LQFMCCPJBirhUeppv/dQOdeuqpEdnGuFzRCcMZQAbH3hSgYlkZlfrwok1OTaOC/DzqbGuJuPbGTGBYqBTlgeIQlVSEMxwcB4ieCC3S8ga5/NMzODRSjBcGkgptxgjBiDP5DDyQwyET7gkJsTGqrm1bQ9eo/eCtBpMZHyjKiYkiERjDVq9LuZ4CkTlGJnTrW0/QYHsdGZKShIcpMqORlkGerjhW7DR2qYW4sHT0tnK/pcVIQ33d1NXeKn4Oh8p9JvRAQgIto2VDHsa3RNbdO4SRy50GdqtQNcd9g1Y1OM4IAxs3bRDoSHM84lQRExaZcG/tuzYpjR+kz7HMqDOBBVZgMmsPr+MuaSMYgOAYGc/EwS7Kzs6l6SV5IiMqPUwjCWnnhgY4anDsxWRQVu6jYj/KOhhWlftMaNeB2NsqMuOH05gBdqtIZlmFKqtAtksuy4eDU4X2pujIyq07wlcIUCH9yTaj6lgh90N2MssqgkV+WqLokFff0UvmALpVIONZMqmQOrdso6He7rDyMPXGsaKmrYes1qRRhbmh0KiEmbhc9fMZVJadTKcsnBTsTYk4OHMccFkFu1XIgjwgmxeES3AsM8fIeFtlazANanASocHxXCVTgeIkFB92KN0NOXMcPGQxToXRrOrdA+FWITOhU6dNCzsPU0/AkjUy9P1DVqpq7RGPjcddIhwr95nQXdU4ZWFxSDtVhCu8RwMEZ45HiIuJFu4Ug5Zhte1tuATH8qZoHYZtloUKHMkqApC5C6Zjxe6WburoHVRt+Lyp3md8Q5Fi/r+jyWaxFxsdJVoSBwJkQl/8zyoa6umK2Ewoxqui9ESqae9Vz3fuCMmEArFkpd7OVhrIN0TktRdMOHMcAJBhhG1ZJC+3e5s9bjT1hlVwDHN56ULRrjhtTASPY21XNARfvYNWWl/boS7hTwTT/VClKMOWOUZbb3k8Aql3z041RHwm1L4bYLjUSDCRC5xh4BBz6XlnRKxTTDDhO1oAQOGZXO5kWYUNuQwkZRWwcgsXZNaoQyc4lrKKSA2OkUWTjhVfV7SK75xFCy4Fip3bLmN3QG3cJJFYeOqojbSc2CdqpGEME2ikZzYcYpINkesUE0w4OA4AyLKBKDu97URGFuWFm6wCZCbbthWyAnvMEdoARIusjP6qokV8Zxu30NAcD1isASvGm2igEFXijY0bw/gSrWd2enp6xDrFBBMOjgMAGkNIC7OJkGVxBzlJQEOJcAuOcxRnBr3MsXSriNTMsTZQ2FxvW8bn1tHBpSBtdHcsDo79mzn2tnU0w/gK6ZkNh5jOzk7xnT2zfQsHxwGgZ8CW0TFEcMDkrdexJD1SZBUTIDiWjhWyOCknlW3cgm3lpiXQsoqJQHluimiTbTG3U3oCJziY4KL1zI5kp5hgErl38BCiV8kcJ9sFhBMZKauQpIfRUmVWiuvgOJJlFbMUxwoJyyqCC4ohMWGTntOcOfY9NTu3UPsbd1C/qY2+/rqQ1u3/gHDqYJhgwZ7Z/oUzxwHMHEdywOQp9trrsMocK7ZlzmUVkTsRKss2CMcKCQfHwSc/bSR7HwiP44lY/GTtqKeo2Djqaqrm4icmJGDPbP/BwXEANcccHE8gWUUEF0XFxkTT5CyD+nOW0r6YCR6F6Unqsn9SjG0yzvi2+Ck9K5eiE5IpMzuHi58YJsKJ3Dt4CLpVRLIO1VOSNB19kIUMJxcPGRy3dg9Ss6mPcHjRPWtgyErNJls77OQI71g0NS+FdrXYrMNyuEAp6MS2V5PxtbvI0t1Oz/9UQscU38vL/j4ufmpt30Y5CakU1Wum/MkzIq5NNsMwI3DmOABIRwb7bOlERrsv4HEcTi4e2uB4Q52JtjV2iY5x9R291NU/OCEmQlprq2zOHAd92f/rVQ/RYHudWPZvqdvNy/5+KH6aM2smpccRzZw5g4ufGCbCiew7eIjQw5ljp8FxOEkqQHZygljC7mhrp8HBAYqPH5EV9PT0i6XthOjIXtqeO2mkKI+bgAR/2b+3s41iDOm2Zf/0FHXZH53rGN8VP22urKM5UyaxKwDDRDicOQ5o5pjnIhJth6mMMAuOays2k/G1lVT3nxV08xW/o4qtm8Tj27dsoJ0vLqfmV1bQX/5wXkS385yjOFbEREVxU4Qgg+X9goJ8svR0krW/m7ra29jz1E8Z5OllJRwYM8wEgIPjAGqOuXW0g8xxGNm4YQl75S3LaUhZwt64ZSstuf56uvSZL+mav15P/a22x6srKyJ6abs0O5nO2KeErjl6pijQY4IbtF1343KKy5xEw0ODVFY+lZf9/QQXVTPMxIBTmQGArdwiR1YhK9cN6Vk0EJ1ImPb0dLSSqaleFENhaTs7K5MK06Mjfmn7dwdPGdOAggkOhy/eh3JPXkrWXjM98tdjaW5JNh8KhmEYLwmblM/u3bvpwgsvpClTplBSUhJNnTqVli1bFhaZOdXKjQvydN0qwik4lpXrmVG9lB07QKnDvTSjrJhuPvMw2mN6KeXG9lNZKk2Idp5xUVZqa2kOi2twIjTVmVGYSZk5uVSWlx7szWEYhglrwiY43rp1K1mtVnrsscdo06ZNdN9999Gjjz5K1113HYU6vdwEZAxa67ZwCo7VyvXZM8kQbaGp06bRpdfeQOVFufS7K5dScVk59ff1R3w7T+ipLznvt3T6KSfTqaeeGtH66nDhXxfsQ6//6UBe+mcYhpkosopjjjlGfEnKy8tp27Zt9Mgjj9Df/vY3CmW6uSAvYmQVauX6yy/T6k++p7SCUtWtYuqsuXTTfU/SnJxoKszLjdjAWHYMq6yooLy8PNqxY4f4GdX8kfqZw4G0pHiyxA8HezMYhmHCnrAJjvXo7Ox0umzd398vviQmk0l8RwYaX4EA7yNlFUlx0QF731AnMXbE1zg1MTbs9ktsbCzl5KJjVjwlxEVTQmw0xcdEU3xsIk3KTaHo6Kiw+0zu0tLSQo2NjZSbm0tpaWk0PDwsfsbj4a6vxjHD5wnHYxcfTdRvDc9t9zfhfFwZx/BxjTysfr5W3X3dsA2Od+7cSQ8++KDTrPHKlStp+fLlYx43Go3U19dHgQAHoltpKTzYY6LmZh6cQa+5d2Qn9fcIjW44geNalGSljHQrRQtxkm0CBFpaNJ8tAhkaGqLMzEzatWsXDQ4OiqAYKzl4PNyOo95xxaQbg3O07cCGFRaMN2G43f4m3I8row8f18jD6udrtaurKzyC4yVLltCdd97p9DlbtmyhWbNmqT/X1dUJicXpp59OF110kcO/W7p0KV111VWjMsclJSVqxitQB7pvyLbUOSk/l/LyRjqLTWR6Y2yth8HkgmzKywuv6nocV3T1w7k0EW+2uGZvuukmkTGePXs2rVixgoqLiyncmejHNVLh4xqZ8HGNPKx+HoMTExPDIzi++uqr6bzzznP6HGSlJPX19XT44YfT4sWL6fHHH3f6dwkJCeLLHuzwQN74pM9xalIc33AVkhNHdMYZyQlhuV9wAQf6XAoVFixYIDTGsKqDtCmStMYT+bhGMnxcIxM+rpFHlB/HYHdfM+jBMWYH+HIHZIwRGC9atIieeuqpsLh5DVmsNGCxZY6TuUOeirZbYLgV5DE2EBCHu8aYYRiGYUIuOHYXBMaHHXYYlZaWCp0xdMOSUL5By9bRwJAw4tAw0THExVCeIYZ6ujooLX6kOI9hGIZhGCaYhE1w/P7774siPHzZaxsh3A5VugdsxXix0VGUEMvBsWTDhvWU8fUD1NfYRL/Z+rzwBIZFGsMwDMMwTDAJfV2CAnTJCIL1vkKZ7n7LGF/fiY70ya3aVUGpyUmqTy53WmMYhmEYJtiETXAcrsjMcXJC2CTp/Q6KuJqamigvL58y0jNEIwn8jMcZhmEYhmGCCQfHfoYzx2OBu0F+fj4Zjc3CXg/euPjZWUMXhmEYhmGYQMDBsZ/p4cyxrssBNMbTp0+n/v4+8R0/R5IdGMMwDMMw4Qmv9Qcoc5zCsopRoPguUn1yGYZhGIYJXzg49jOydXQyF+SNgX1yGYZhGIYJNVhWESCfYy7IYxiGYRiGCX04OPYzZiVzzFZuDMMwDMMwoQ8Hx36GM8cMwzAMwzDhAwfHgfI5Zs0xwzAMwzBMyMPBsZ8xdfeSxdxO8dFWf78VwzAMwzAMM07YrcKPrFu3jt685xpqbmqiJ9ZNpgNz7hEWZgzDMAzDMExowpljPzEwMEA33HADmZtrKT4hgZprd4uf8TjDMAzDMAwTmnDm2E+guUVTUxPNnVpMcQkJNNjfL37G4wUFBf56W4ZhGIZhGGYccObYT6DrW35+PjU3N5O5q0t8x894nGEYhmEYhglNODj2Y/e3W2+9lWbMmEH9/f3iO37mNskMwzAMwzChC8sq/AiK71atWkWbtmylubNnUWJioj/fjmEYhmEYhhknnDn2M8gUF+bnc8aYYRiGYRgmDODgOBA7OToqEG/DMAzDMAzDjBMOjhmGYRiGYRhGgYNjhmEYhmEYhlHg4JhhGIZhGIZhFDg4ZhiGYRiGYZhwDI5POOEEmjx5srBEKywspLPPPpvq6+uDvVkMwzAMwzBMhBBWwfHhhx9O//nPf2jbtm30yiuvUEVFBZ122mnB3iyGYRiGYRgmQgirJiB//vOf1X+XlpbSkiVL6KSTTqLBwUGKi4sL6rYxDMMwDMMw4U9YBcda2tra6Pnnn6fFixc7DIzRthlfks7OTvG9o6ODrFZrQLYT72MymUQTkOjosErUM07g4xqZ8HGNTPi4RiZ8XCMPq59jJrw2GB4edv7E4TDjL3/5y7DBYMCnGt5///2HW1paHD532bJl4nn8xfuAzwE+B/gc4HOAzwE+B/gc4HOAiIZramqcxppR+B8FEUgj7rzzTqfP2bJlC82aNUv8u6WlRWSNq6qqaPny5ZSenk7//e9/KSoqymXmGDMS/G12drbu8/0BZiklJSVUU1NDaWlpAXlPxv/wcY1M+LhGJnxcIxM+rpGHyc8xE0Lerq4uKioqcpqZDnpwbDQaqbW11elzysvLRYrdntraWrETv/rqKzrggAMoVA80AnhIOjg4jhz4uEYmfFwjEz6ukQkf18jDFCIxU9A1x7m5ueLLG6RuWJsdZhiGYRiGYZiwDY7d5dtvv6Xvv/+eDjroIMrMzBQ2bjfeeCNNnTo1ZLPGDMMwDMMwTHgRNvYJBoOBXn31VTriiCNo5syZdOGFF9Iee+xBn376KSUkJFCogm1btmxZSG8j4zl8XCMTPq6RCR/XyISPa+SRECIxU9A1xwzDMAzDMAwTKoRN5phhGIZhGIZh/A0HxwzDMAzDMAyjwMExwzAMwzAMwyhwcMwwDMMwDMMwChwcMwzDMAzDMIwCB8cMwzAMwzAMo8DBMcMwDMMwDMMocHDMMAzDMAzDMAocHDMMwzAMwzCMQixNIKxWK9XX11NqaipFRUUFe3MYhmEYhmGYAIGm0F1dXVRUVETR0Y7zwxMqOEZgXFJSEuzNYBiGYRiGYYJETU0NFRcXO/z9hAqOkTGWOyUtLS1g2Wqj0Ui5ublOZylMeMHHNTLh4xqZ8HGNTPi4Rh5WP8dMJpNJJEllPOiICRUcSykFAuNABsd9fX3i/Tg4jhz4uEYmfFwjEz6ukQkf18jDGqCYyZW0NqxSmStXrqR99tlHRPx5eXl00kkn0bZt24K9WQzDMAzDMEyEEFaZ408//ZT+9Kc/iQB5aGiIrrvuOjrqqKNo8+bNlJycHOzNYxiGYRiGEVgsFhocHOS94WHmGPsM2ePxZI7j4uIoJiZmYgTH77777qifn376aZFB/vHHH+mQQw4J2nYxDMMwDMNIzGYz1dbWCncExn2wvxAgw1FiPK5i+FsU3KWkpER+cGxPZ2en+J6VlaX7+/7+fvGlFWID7Hh8BQK8jzzYTOTAxzUy4eMamfBxjUxC9bgiY4zA2GAwUE5ODlvHeggyx8j8egvOiZaWFnEMpk6dOiqD7O65ErbBMT7glVdeSQceeCDNmzfPoUZ5+fLlYx5HJSRS9oHaTgTxOFhckBc58HGNTPi4RiZ8XCOTUD2uCO4g/czIyBhXkDcRGVYy7Qhox5M5xr5HQrSxsXHUMUBGOqKDY2iPN27cSF988YXD5yxdupSuuuqqMRYesAgJpFsFDjBbuUUWfFwjEz6ukQkf18gkVI8rkm8IwhCUxcaGbZgVVMY7qcDf45zIzs6mxMRE9XHtv50Rlkft0ksvpf/+97/02WefOTVxTkhIEF/2YIcF8kKyKrPaULp4mfGDQZmPa+TBxzUy4eMamYTiccW2YLvkF+NZ5ljus/FqjvXODXfPk9hw22mXXXYZvfbaa/TJJ5/QlClTKBywhJYcimEYhmEYhomE4BhSihdeeIFef/114XUMLQlIT0+npKQkClUsXK3KMAzDMAwTFoTOOoQbPPLII0J8f9hhh1FhYaH69dJLL1EoY7WylQvDMAzDMOHN6aefTl9//TWFAgcffDBVVlb65bXDKnMcrn6BFg6OGYZhGIYJY7777jtqa2ujAw44gEKBq6++mpYtW0bPPPPMxM4chysoyGMYhmEYZuKBxF7PwJBfv9xNHv7ud7+jJUuWiH9XV1fT7NmzRffhRYsWuWyY8dhjj9Fvf/tb9WcUvN1222203377UVlZGa1evVpY6O699940ffp0URsm+f777+lnP/uZ+N2CBQto1apV6u/OPPNM8fgee+xBv/zlL1XJrHyP22+/nfbdd19RZ/bUU0+pvzvuuOPonXfeUXteTNjMcbjCmWOGYRiGmZj0Dlpozk3v+fU9Nq84mgzxrkO6W265hfbcc0/69a9/Teeccw79/e9/p8WLF9P7779Pv/rVr5z+7SeffEJ//vOfRz2GgPrbb7+lDz/8kE488UT6xz/+QT/88IMIfq+99loRFHd0dNDFF19Mb7/9tpDCokHHwoULxftOmjSJ7r//fmHHBxBcYxsRiEvgOoas9datW2mfffahs88+W1jkwa5t/vz59Pnnn4ug2pdwcBwAQqx5D8MwDMMwExAEp5dccokITJ9//nk66qijnHYa1oKOc/n5+aMeQ5ANkPnt7u6mM844Q/yMTO+OHTvEv7/66ivatWsXHXvssaP+dtu2bSI4htHCs88+K/yh8QVvYi3ILINZs2aJoBiZZWnjW1BQILbL13BwHACGhjk6ZhiGYZiJSFJcjMjs+vs93AFZ2zfeeEM0Qps8ebJH72EwGMZ0F5ZNNWSLZu3P6BIIIPmYO3euCJLtQSO3Bx54QBT55eXlCTeym266Sfc97F8XYHv84VbGmuMAwPV4DMMwDDMxgW4Wkgd/frnTMAPa3F/84heie/Ddd98tCto8YY899hDZXk9BlhquEh988IH62Nq1a2lgYIDa29uFNS+yxfj58ccf9+i1t2zZImQivoaD4wBgYV0FwzAMwzBBoqenR+hyof2FFOKss84ik8kkiujc5bTTTqP33vNcO52ZmUlvvfWWKKxDIDtnzhxRFIj238cccwzNnDlTfMGazZNAd/fu3WSxWPwSHEcNh6s/mhfgREDDEMyesKQQCHDwv9tcSfvMLlOXHZjwB8e1ublZLAOFUttSZnzwcY1M+LhGJqF6XLHUj0wp3BW0koBQ5sgjj6Q1a9YIJ4n777+f5s2bN+Y5ZrNZZIEhgUhOTvbLdiAkhWwC2mJX2XAE2NOmTRMOHO4eA3fjQNYcB4gh6zBxbMwwDMMwTKihlTw4As4U9913nwg69YLnQFNUVEQXXHCBX16bg+MAwXZuDMMwDMOEM0cccQSFCpdffrnfXjt01iEinEELO1YwDMMwDMOEOhwcBwgrW1YwDMMwDMOEPBwcB1BzzDAMwzDMxGAC+R1E3L7n4DhADFn4ImEYhmGYSEc6U8G3lwkOct976xLGBXkBgrvkMQzDMEzkAxsydJMzGo0UFxcXUjZzoc6wB1Zuziz+sO9xDPA63sDBcYDgzDHDMAzDRD4I6goLC4XlWVVVVbA3J+yCY6vVKiYU3gbHAH+P9tjevgYHxwGCNccMwzAMMzGIj4+n6dOns7TCQxAYt7a2inbS48m4Y/+P5+85OA4Q7HPMMAzDMBMHBGfh0iEvlILjuLg4sd+CKUdhIUyAYJ9jhmEYhmGY0IeD4wDBPUAYhmEYhmFCHw6OAwRrjhmGYRiGYUIfDo4DxBCnjhmGYRiGYUIeDo4DBBfkMQzDMAzDhD4cHAeIQW4fzTAMwzAME/JwcBwgLFZroN6KYRiGYRiG8RIOjgMEYmMrZ48ZhmEYhmFCGg6OAwg7VjAMwzAMw4Q2HBwHkCGWVjAMwzAMw4Q0HBwHEM4cMwzDMAzDhDYcHAeQIctwIN+OYRiGYRiG8RAOjgMIyyoYhmEYhmFCGw6OAwg3AmEYhmEYhgltODgOICyrYBiGYZjQom/QEuxNYEIMDo4DCBfkMQzDMExo0dk7GOxNYEIMDo4DCHfJYxiGYZjQoqOHg2NmNBwcB5BBdqtgGIZhmJBh0GIlc/9QsDeDCTHCKjj+7LPP6Pjjj6eioiKKioqi1atXUzjBBXkMwzAMEzr0D1mpd4A1x0wYB8fd3d2055570kMPPUThCGuOGYZhGCZ06B+0iII8q5X7EDAjxFIYceyxx4ovd+nv7xdfEpPJJL5brVbxFQjwPsPDw4T/BocsAXtfJjDHlY9nZMHHNTLh4xqZ+OK49g8Oidcw9w9SSkJYhUQRidXP91Z3Xzeiz4SVK1fS8uXLxzxuNBqpr68vINuAAzHQ00WWqEHqGYqh5mYW/mvBRQCJTLiB49rZ2Sm2Pzo6rBZgGCfwcY1M+LhGJr44ri2mPrJ091F94wBlJMX7fBuZ0LpWu7q63HpeRAfHS5cupauuumpU5rikpIRyc3MpLS0tYAe6qrWH+qOSKTo+lvLysgPyvuHAwJBVZNQTYmMo3MBxRVCPc4mD48iBj2tkwsc1MvHFcV1jbKTPakw0Y0oR5WWn+HwbmdC6VhMTE916XkQHxwkJCeLLHuzwQAY0OND4snCWcRQDVgtFR0WFbXCJYxroc4nxP3xcIxM+rpHJeI/rgx9V0OYGE80uSqPy3MAkzZjgXavuvibf1QMIu1WMBkUQg0OswWYYhmGCQ6PJJrGsaDbzIWBUODgOIMPDHCBr6R+0Co9JhmEYhgk0cKjoVBqA1LT38gFgwlNWYTabaefOnerPlZWVtHbtWsrKyqLJkydTOIBgMCY6/DS2/qB30EJhWIvHMAzDRADtPQNC7ggaOntFsBwdzTclJsyC4x9++IEOP/xw9WdZbHfuuefS008/TeEASytGyyriYnjxgmEYhgk8jZ0jrlXNpn6RsElmOzcm3ILjww47TNh7hDND3EJapW/QSolxE1tWgQlCYhyvJDAMwwSa+o4RKUVb9wB19AxycMwIOG0XYIa4CciowBB2bhOZzt5BXk1gGIYJAg1KMR5A2q3CyEV5jA0OjgMMyyqU/WCx0n0fbKcbVm+c0G07MUHoGRgK9mYwDMNMOJo0sgqwq4WDYyYMZRWRwOAEDgTt7XPWVHeIfxvN/ZSf5p4xdyRKS7r7LZSaGBfsTWEYhplQNHf1j/oZDbsYBnDmOMBYWHMs2K0ZhFAxPFHhzDHDMExwg+PEOFsoVNPGwTFjg4PjENQcN5n6It7/t1ozCKEQYqLSP2SlngFLsDeDmYB09Q3SUISPMwzjjBazLTiekZ8qvtd39E1omR8zAssqAsyQiwsPF+bGuk7h/5tpiKe8tETKS02IOMuzunZNcGye2JnjcHdgYcIT2FZB1pObmhDsTWGYoCATM3uWZND62k5q7upjOzdGEFkRVwRYuSGTiFgJCeZW8wBtqTfR5zuMtKa6PaKK+eo6RgohoDn2B6GeAcD2wa2DM8dMsDpUTmRJE8PI83//KVnie2v3gHAQYhgOjgOMqwAXmUR7ZKBs7huKuH722qUtX7PTaKZaTYY61MCx/nS7kXY0deked4bx9/k3kSVNzMSmu39IrJzIzHFCbLRITO0ydgd705gQgIPjADPoQnOMpU5HRNKMtlkTHPvrBo39tbWhK2S9K3+qbqdnv6miJ7+o5OwxE3CwSoUJ90T3GmcmJvIehKA4JyVeyBdBBdu5MRwch0fmWGLqi5zguEWjM/ZHcAzJAgqOQKWxm7Y0mEJO21vZ0q1WTLf6KXvOMK7Gmg6WVoQloTaehRv1nbbueKjtSYyLpfx0m51olTIuMxMbzhwHGFcuFM4yx6YIyRyb+wZHZcHb/RAcmweGhBxFUtfeKwouQkmHjG0C2KIdzaGZ3WYiO3MM2iIoOA6l69vftPdExv0gWMCZAmQlx4vvkzKSxPcaZVxmJvbEjIPjkMscOw6eUbgVCRZvVXZeku1uBv2e2E516tw4jF39tKamPWT2Yb1GWhJo6Ye5P3L064x39A/ZJuKRpDtGgVUkFS47A6tNoTKWYZ/D6cHdCcy2xi6PJjL+WDWFZSqApAKUZBnE94aOXqfbhsDQF5OwcJYztXYPRPxElIPjELNy63dRmBUJ2ePdrd1efSZkSty9GTgaTNu7B+n73W0hERxqW5fubukJ2IwdNzG4n4Tz4MyMj96BIXrum2pRENrTb4mYglBT3xB1T5B27PisOHahQGWLmdbXdNLmepPTyQnOsx+q2kWzjS4PxmCsssnJnK9oNNmkbNLKsDzHFhw3dfVTn5P3QmDoC4clTBDC1Wfc1DtIXRFkEKAHB8dB6JDnKMDB4z9Wt9Pra+uE17HeDQsDYrhT22ZbtspPS/Co0BCDo7vWU6Zex/sJN5TvK9uoQdGcBQtksiVw1XAn41U7ziU/zPZ3NJmFjdfWRtO4XosJX36q7qCPtjbTv7+rFpOkSLF0w007VAJG4M8sNmoqPJkIYFv8sRyORINs6lTf0Uvf7mrVTU7AlejbyjY1GeJJogfPhWOTLzEqme68VJvWuDw3Vc3IO9s2fMYGTWLDG3BvR5JCW3sTTpj7hyKqBkoPbgISpOxxXEyUrgbw8c92qTOy6Ciisuxk0b1nVkEqTc9PiYjMcV2HLcCblpdCTaZ+ISXBYJEYF+NWNzk5mDkCs/EeFzcN3Cg21Zmoo2eQZuanUjR2doBBBkJrbYdtTk2Mc7nvslPiyRAf67WkpVfpyNds6hcDfZGitWMmDtLiEGMRJD2lOQYqTA//8wBjZ3LCUEjt59LsZJ+/Lq5heOa7Gue07DKaqaa9R4wdhvgY8T05IYYykuIpKd752OuMbY2mUfUdGKN/2N1GU3NTxGdHQL6rpZt2t3QLqzSJu8EVJvQIxiD/8eVYJQPT/HRbkmZyZhLFx0aLySLs3Ap0rgckaBDk43Pg3wmx3u03JDnwGgiQC5RCwHDC3DdE0VFRVEKRC2eOQyibgJmsDIyzk+MJT8Og8u6mRrr/wx108xubqa0n/F0NZMYWg2eMEpS6k7lCttMdfST2IZbh7nx3K31Z0eL0uXgeZBYyYAwUuKlpM+aNnX3Cd9MZkJTgOQhqvQETENygtGxr6gr4Z2dCpxgUbGk0CblRuIPrA+e4q+sokNtTo6yS+RrpxNPtQZYcMgYEsQhsMIZgLECCYGN957jGcr1zB++DFSrYVa6p6RCOQfZJa2ere6O2u29I/C2SCb7MfEuHoEIlODUkxKp2bo68jhtEe2ms8kIW5904jGAfSQnbNoSGRh4Bv7sTLYt1WBgHREKizhkcHAcBR7rZamUgTY6PoTtP3YPuPGU+XXBgGR04NZtio6OEzqmyuSfs9YHIFoOS/2/vTODjuqrDfbXviy1blhd5t2M7ThwnZCcbCUkgUEgoW6EQoKSkoQRISwMtpEAhoVBKoZStJeRfKFBKAiQQIGQlZF9JvMT7vsi2LEuWrMXS/H/ffe+M7jy9mXmSZkYzyvn4iVjSaOa9d+8999yzTqk29ZWeBTSK0stJPUpdViwSD286aCtA3PqHbeauP+5JKVQRvo9vPRRP0MgFxNwB48r5AKv49kOp446xcnMbY41329R2dIQgJsxnzZ4jL4vsY2UY1y1MLXBkSj4ekkaT/CSbdb4ox1hQea7ZKJUn4XWjuddkryV5eSzXyD6GApyK9qP99isMlLEoiqFYmAeOD0VWqKMge86sBi/WGM/ljHpPUd4ayIsRRKmFsYblIb9lD+P+D3VPrMGLcSCMM+qzPdrnHVaY35M5b0WV4wkgmUCQuC0pLdNUW2HOWTTNvOfcBTakQhZtocf6SKztnKlVpqHKCyOIYrmS0lPpBDkWWakhDD97bo/5nyd2pNxkcVG+sOuItXSMxlU5Vtyxnl5bEVdeU3HkWH98MxvtAYlnhnU6/HcDZlsaxVyZXLgHQRJkUYzzsaQbB0Y3/CgVkmSLVSsfMunlsDHe+NRUluOo94oSg+ctGekO5mEQjjMe5QgFS+4jFa6HLVOKJIq9eGndsIZZjd6/dwUqKokyjUIo8PdjSewOdm0dqycwU7oIJU7Z/6LqFUedey50XSQVqhznUcUKcXU21XjKksuCaV7cGkpfJk/PuWZwcCieWDFvarVprPYOAlGaYIhynK6+J4q2lIu7eFmzIXDj/pcOmG/9fkvaahdYOR7bcijUyppJJLFuWm1FvPj8ljSdmVBiw5L5oljf1u/rSpttnm1BV6iZ2ZMRGs8ITPONbV1ZqTc+HlCKWBNyKEyHKDsoXflQsUKugWedaWUdJfE/HtjkVRuJcFBOZ2FGnozGKICscENzxkqUvcyVS1EPSulkDXsQI4LXjhBGgT1JGoQEvWmu1VjYN0rrMYpl0BBESMNEHeZojoU3FqKGSRx1igJMpq69QVQ5ngA4pYUhbhqxHLssaBpWjgt5Qu7t7DX9g0NWYZ07tdpMqfYsx+lCBRAelJ9CYU0VgkHoBYoeFg3agr71Fa3mmvMX2vCFp7cfNv/6uw1pNwFiyojHe3Tzoci1O8ealIjVYpavHEtYTfg1JZ7sRxNawWe5Ao33ClqeuWdca9kU0ljQcu26Z0NzW5XnI8zHDftTH14yDRuy2/hg3d6uvKp3jHKzxs7H6M0uyNn4/K/Wmf/36LZRxeJmC6maQThAJq3yyLgntx62FUfufH6P6YlgvYxi4YxqPbaH7b1dCTHElCB1ZUwqhmIxmwuCYpZuL2Me8L4PbThgFXgUuHQGDmQYuTqpEEW3sbosIRl7vm+EwprrNuRiPwnbC5BpowlJcw8Ux4eG7N+iD0xEtZgdh3oSvIlebHf6eznU3Wu+cu8GG65YyLpIOlQ5ngBYFGFQsQCm1JQltRxzoj2YJYUtF4j7nnCK2sqy+EEgneUYS+tHfvy8+a+Ht1orSDJ3HpYICamg0geC7/T5U831Fy8xlWXFZsP+o+aff/NSJEUABZLanX/c1ZHxYvskdkBLQ4WZ6x98ENjJwiUQQu60IUwiyjXxms2B5JL/fHir+fCPn7ObU3AzF6UpW5a0oEsxm3Av3GM+hgu4ijGHNjaqXLUQ54Ap1qtzFjXZ/1LWjzWVi/rfjEm6sCASRcWFjUKUzouDEoV7GKXo95sO5oWi7x7Ck4U0jQWUGAnL4uAQ5aAcpSYtxpkoYRLIYtfKyN987u515oafPG9++cLelAdsFN2v3rfR5oJ8/YFNaZVCYquf2nbY/L/Htpvv/mGrVcjTje3+rt60oQp7ndbRLiSJSyULN+SD8fMS8WK2ohT3wD4eNUkcmMPyudsPdZsP/fA58+Ondo7w5OQCvER4i4LXF2X9P7mtw7y4u9OOdfsEx0tnE1WO86paRV/SsArCD7CyIhxQdvIl6WS07PSV42l1nlAS5bg9jXXomR3t9iT/1Pb2lEkuWFdFOZYDBSyfWW8+dukymwCIcP/sL9fagvVRQNA+sbU9o6dksULMrK8yC/3rJA7UjWlzYRPh97fcvd684FvUotT9JOsay5WAdfiJbe02tIeDRlAYRnVbjgXmLFbsXGRnMw94TqyXfK3EwPNg45dYUBTCXLhX9xzpMYOxmCkqMubMBVPjLXNRBrIdWjHkKwh2PSVZ88xzOTwCY5guz8CttcvrN+bYEh+GG+6AApupeW+VY8fKSzOJdERRepAplHpL/dkDZlOgm+fdL+61rZiZU3c8u9t86Z5w4wPeOOQuihVQwnNzW+q4ZZRwycXgc7mPdAd4ng17RKqmIXJYIazNBW8mZVa5l60Hhp/Frg7v3yR5Iz85iMn+ETWmHOOXeI1/s2a/9aD+fuNBe//s/blKiubZiGwcbR+F3oFBs93fXwcGY2b7wZ6c5OhMBKocTwBMqiAsEFF2wsIqxBIajzue4EB4hMumti4rIJ7f2WHrWj6y6WDaig8iZKRWsRwE0p2+Eb7D8ZFHk1oDUWDFOu0qxzC3qdp8/DXLTeuUKrvBEGJx5x/3WDdfOggHeHp7e8KmlJGkxCnVto41MP7tSQR/x7EB88CGA3aD+Nlzu+3P0oV8sJG5llqsaz960rNU4EnkPb//2PYEoZxN5QhXN5uDeEiyBWP13I4OW4nD+9z0FU5cS3syz04mYZPHYuxeF5Z7UfCyyY5Dvku5qsweuiW0AuU82xbXo/1eOTHu++kd7SMsqmy+QY8GpAutwGPkhgUgIyYS7uPHT+w0H7/jBftMmYuZ8sp0Hus3O5x1jYKZjh3t3eZbD20233tkm/n1i/vMczs77LMPznUMB8mUeO6Jv5N1Bcj7u1/cZ/99/pJpNpQN79w/3rnGzm9AvhAbfcuv19vDNx3pJJSMBPNUSXnW2OFXjkBMWU9QijnKIUqs5KmMGSKDgspxjS3nlpgDwntKiMxDGw/EX/vI5kNxWR6pgZO/trkumn1JHg3VglgPbk5JNlmzx/MShZEu7vhoH96/4dAQPDWTNbRCleMJIGwh2UD9ntTKsSh7ZJdPZFIeAosFTctjQgEQDixsrJ7pEsVEyZXakmJBTqeUuQoVlpJkAvJgV19cIZzf5CVXuCCYUZDPWzzNJmT8/Lk95qv3boyUNc0+Qmwoh4HxhllIAfrWqVVmdmOlLcofS7Kps7kggMQahhLA/afrb89zcvX++15qs8+xrrLUfPjipVZBppXrY1vb469hDLMRF8zzEoEsZeyyAZ8R1ho7akwfCZnZzh5nrgUVY4GDb7ZLNcr6mFZXYcpKi22DISCOlOeUTQuWu/lKnDtVD4DPRa6E5WSksxwjk9yDBW7riaxYwRp6dMshKw9/7ytUmQqtINnYDZNIV2kGy95969rMk9sO2xKX//fMLvPv928y//DzF811P3jW3PSLNXFvG16msMQz1u+zOzoSKl4wXlQBwgt14sx68+dnzTOfet0KK3eRI994cLON//7uH7aZ/35su33dKa2N5pNXLDcnz2n0rt0aeo6nXI+uvGC+cA3J5LU7B1LtkbJPSetowSvn5v1s68GehPwQDtmi8AMHBSlHl85QgZdExuwPmw4m6ADEjttrykFYFeMYttcSOohXNq1y3JsYGlfoOVCpUOV4AgizTO3p6LFWURSWVa2NNlELJUaaZIyoWDGBluMNAaXLJV2hdom5km5ccnJPd2p2LdLER3KSD7rNEFSEEfAcCZ9IdsigC9K7z5lv3nPOfFNeUmxe3NNpPnvXOttBKgoI1ie2Hh6zgtx1bCDu5qSDVE1lmWnx62uKouDC5tHtxBkCCiAWnGRhEGzE7jNFgN35/F777zetnmNWzKo3r181y37/P4/vSIh3zUaMrhsGhIDNRu1XNhxvwxqpXEZVjg92942qIP5oYd2ywbqhLsF7yHZynhxQm2srzNTq8mHleF+XVUxpFpEtwhQWGkRQRpFwsWQhMDy3VMou8sGN20ShmciKFShLojTghkcmUmFivIdq/n7DvkQZQR5KqgOVa+07aXaDOX3+FOs9Qw4SPsCz+ukzu+KvRxl1ZTjPHeUpGMqH9RMrJMnOf3bmXFNUVGTrBN94+TLzmpUtNun6oY0H7SGBEJ43nTrbXHfhItuZb/606rhin0whQ77jKXOrOyGr7bMMCSk7FjDOpNoj5XWiCLtIFz6eA89bDstUMcLri6eFkm9cF8YFd02l85jyLPEAwisXT7P/fX5Xh9UJclHSLUyRJcTia/dtMt96cIsNq0m1ztq7+xMMVVsKvHpWKlQ5ngDCLCPiEiRBYOmMWrNydoM5c2GTufCE6eacxU3m5NaGeGwqVsfdKNMTYBkJKl1B0hVqlw1szpSqhISIjjTlmlyhJy2Qg9fhJuNxkKhM0xL13MXTzCdeu8zMqKuwCuEXfvOSjZlLFasm2E5cY9x8RcnFBTmNVtBlJfFam1jjw6wOovQLdJ2CMEs94RPBZAvui5htrDrMJ3jtypl2TvHz//rD1vh8Sla0fzx0BxTWTHcOkw082UYbJVzAU2C8xMdNbamz3cdzsExWrUZgk8xmcp4cUJvrK23y7wktdVZ5YdPjEBG0LDGfOMzwd+OVOckUFpTbYPdGwp0IAyD8CWthMgsVB4pg3O0e23Fy4ipWuB4gmh4hs5hX4028cpPxpNIPMa+pclA8a5835iitf3n+InPT6080//721eam16+wBhkORljbwXoAnfm3du/IDoo2bMQP0eI9pXkGlJYUmzedOsfccOlSe/gi+fqGVy81r1k50yrQbvUlqjckCzdBnsucYE/EkMEc2NVxLLTeMYpdQnvqFBZN8dyJBzMYdyyHDvY75heyAUVfwkfOXujJUCoaAesj2QGFn4tx54U9R6wswlP49tNbrQGM58385XXZtsIG90wOcd/5/RbrteRrcxthLsnnEvMEEcDBCng+bZ3jlwv5iCrHeVLn2K17KwIE+DcnbeKgqIcrFkaSBYjfyyUIiaDSlcz6lvR3/uYgAkisuwjCVBZnV4DahJu2kaEVbLyEnIhyzJfE8yaDmN9/uGKFecW8Kfb+yMD95M/X2GYg6dzLvWMMP5DNjfqajC8VNeSwgIAPht2gsMhzX+xnU2NdZNNjEwteJwcE1/3J97jy4O1nzDXF/vzCK/EX5y2Ixwn+du1++3M2nky71oObN0I5lbULYUsiThRLG6/F+pEqQTHM0xCEjUksuhw6Mh1/zfyMGlfIZpmtDUfc+8R9sv6QL1Lflc0PZQ4vCocN5s0DLx2wiYO0GqbV+lit6szr0SQS37N2vw0DwDpJJ7Zk1n/Wgax7CaWifN9ElMcSgu2HH/dDl8YbWsG9ivygCg8c6PRKnCWDQ494g0TOAHKALqXyPrL+XWMNeSVh1/yL5/fYOHAaGKH0hrGspd7cctVJ5gtvOsn+24V5h2KI5Zp1HiYLPHnuXceS5jp7iJPQCtaqW8uYf0v4w/DPks83eR7iwXSROWQPbP68Qoby/iTrnbWwyX4V+YcgL5kucWyRNYQfsI88svlgvNIQa0msxhVlJWZ1a2NiaEWWK1G5NcMpv/f1+zcneNpSeaWHrEzuih9uMOwAHp8o1VAKDVWOJ4CwAuUS59Uc4uYR6qvKAs1AkgtEEuV+t3a/uXed93Xf+v3m/vVt5vEt3kl3LCAoUnVZEpIpKSSSSHyZ1JOc4ivHZO66dSWDtPuWC7GeozwENz+eh1vGDYsFSXhY4YtTzPSq8hLzl+cvtC4/hDZK9388sNn8270bUyYYjjU2FMtHMN5Nki29ihWJgobEObFEnb2oyW5w6E3P7+6wypyrcLlZ+2J9++ETO6xVAGuHlCoSOHS99fRW++87ntttXYlet6TMCjuSWyj1dLvvvmUzcRM7XFDMUXaxGhGCkOo589oX9xxJGutOIpAX75g+4SVoweIAkslDQrJkTq6dNereJxuWNLLJNGK9xH2MYlxRVhxXXtbv7bTrCOXO1noNHABtq/Ut7SMUkSgQJxr1cWLFvP1ZL/EUNtCkJMn4dfUNxD0RxLJWlZXY9SEb+UQgFk+x7j65td0qF6ksjFGwsdX+PFo1p9EebFEwUyUgMqaAFZfxDnLZihbvGre1xz0WeKvYQ8I8WSh9v1vnKdKEU4gVMQwO/qUhwhejgMg8L+545NgmyvNqs3KWN0c5LKFsuuFfHAAkUZDYWUpVEr8eZollTcvBV0IoXBY2D5dzG07E84wLp82bYpP28HhSAUnCLcTSjPwkcfvhjQdtDD9eOFGMWeco9nDB0un2v6fOnRIPk2N+ZDO0wtbK9726PAPK47GOCUF8gx9ixx6fzHrd3X/cVrUB9qCF02ojxx0XomVZleM8SciTOB6xDIeBsien2lQTEkVblG02I75YoHwum9tY4pVtCZck/ebDhFqYlW67v4Eh0AllgJryEhuzlsr1zWdLjC4ndlhPHdS+wfhGw2LHvSgb/6LmWlNb4W0EhCywkZSUDFvkw4T16rlTzGffcKK54qSZ9pqIbyNZ5WfP7g490ByLcFAIY/ggNDzW0h6ceeBaO/j3sb7j8VjkJc21cWsDCTLgukCDSXgoMsSF8cyJ+QuD5MRT5jTa+fGdh7fYe8101YLHNnul8H6zdn983iKYg0LTS8rqjCu7WMqwWoaVorKK8e7OpBuKKMb8l9elsySKq1VgreCezwSsh7CkHRSNz9+9zvzwyZ3mB4/vSPjdtiwl58khAKsheBu9Z5VbZ+dP6o2MebJuT6fd6EfT9VDCnv7v6V0pN1MsWt/+/Rb7OVgX5aCCXAnbZG2linZPNs1rqo63AMbaPBHw/OTwcP7S6daFzgEXBZ9HOx4FiPcVpZC4XQnHCpZXE3iGUufctRq7YEBY3lJnDxS/W98W/3lYYh6H7e8/tsO+9rS5U2wM81gZTjAn7njk+kYGoHDKazFyAAcB1oUYYXjecjhifvz06d1WXlBNImyvs1Znfx4FE/IApR35Lw2n+CwODnD+Ek+pFUMFPLLlkL0G9iNrtOkOPwRS6YIfr5hZHw9DId6f+YExgjHkUJytWuPIM9E97sVQtrXdlBQVmQ9csMgmSorHIFmI41Ebu94Tn0syfjbuOIVOIcaOQkOV4zwJqxCBGRYDJdRXDluO7QkvxJKCdSZd3cuxuPbYnEZT4SpMudrhK9dNteWmpKQ4rpSi9EOyZBzZaIg5Wz3XW8RYR7GwijWQhSsljZrrKuxzdMNTmmor7Kk/lZUDKkpLzJWrZ5t//JMTbQY2Y3XXC3ttGaKgdZJqA2M5Ecvzdw9CWHS5XGp/upZfNlUsiCSCoOxzXyjxgGUHpUuuC6uzGwqAUCczHVD4pVV3EJ7Tu8+ZZ9+fxBJiDDOpHCOQxdrFv+l2BVi9Kdjvgls/rLwXpQLdexMlOplln8S87z++Pf59ujJl9gAWYi1nTmWi7TVW8uD6YZy/9NsNcZckiUtuMh7PSmq8Zgrmq6yz1iZPWcJbQrgOYTY8o6hZ84wTG2zUOEk20P99aqf59Zp95nO/Wpe0IQyNEQjtwOr6wYsW259hyWaMwty3B4/2xmvNLpheE3eVUwJsIixWeMDE2DGnsSpuHaS2M4y1lKEXW90Zl3GEhMl+QVJjumS82UmUY7jsRM96zNpMFTbzyKZDVomz3Ud9j9NYcQ09QeUKjwVrDyVTSg5yz4Rx8ByQE7Kej/R6lZIkuU3mrzUgheyR+/25gmGG6hRBkIN8FnCgZY5Tcg15jXFCOLXVs9wjf9N15BvwaxoDeURufDaGGyAEQ+KwseCz72EUwQLO77AujyehU9Yp+gHrEN78ijk29BALOvsrc5dD+fGQz3Fj1zlQLZw+7MVOlWCNgYFnlKyueb6iynEeVKtgwgfbuSZz/y9gEysqspsE8anuJOZ9yPpOV3MRhWI07mKUkqC1A6FLgg6bOQsX6xzxuvetb7PWhbDQCjndB0/rDb7rMZllT1pu0uoTKxdWZy6fONm4gDyWGG9MCErY4eIV86fYk3o6EIQfvmSJ+cAFC60QxbrxmbvWJpTy4RrGEvctCp1YuID7ksodrkLEsxeFCcGMIkumOfFehKKgIHrJicOvE+764177XHjer14xI/5zlPCpfryYUFdZZk71Dx4ox8SmZappgcwVgWxtmbduYh7X77ZXdSHU49mdh+Nzl/tOdshjQ6GLFeMjljU2hFRxx3LAYA25GxAHoHSlstKBgha8L+bql377kn02KAnSjAPrsSsfuMeomwrPNN3miSVOGoCguIlyTPyjhCzhDo4Kcy9q+AJzWWJZWbc3373eKjMuyBJc2Bxr33vuAntNHJ45pLIJB2UEz1a8JbiHFzbVxC2kHPTcRhxhEJvMekMZydh87z0eX+NYCGVsqWzAGGEBH0vcNu8rz4+cDcZtdqOnYKK0hI19grUvxd5y4qx6u/egBD60wVPigvD8/+dJz7vxJ6tmJVQDwuiAJduxRySF8oEYOfDuyWFhnyMfgvWNCcFDXiH7Vs72QhnwWjD38KxJHgvc44d7AF5ExiF4QBJvkIT0BUFhFq8e+56U4jtvyTQ/RwSltsiuGQwubs3jZDyz3fN+ceATZVj2IZG7xB17VvAe6xXEO8Ohh4Y4hGewp7L/REkYD8Mm2/b0m28+tNla/pmXFy9rtr/jYCx5QOQzdYYcQqmtjd7BEJ88u8Hus/yd1UXaw7srMt/FaBU0hOQ7qhxPAOx97oLFIiJKXqs/QZOBUjRnqm8ZCQTCY0lM1mHNZTQtL1msWN1ciBslpovENVoxE5+L+5qKCNS9pA4wyn5QARcLcItfZF3AMgDJMvR3+8IdJY/4SEnMYFOUE2uwbTSKcBjE3J2+YKq1XqcDQfiKeVNt7c5F072qDtTu/MHj2+Mb0Vg6FboNQOLXVVFiZvoC2U3msfWNfeFC6AWhIVzXKYHQCtxWbjw4SpVsFG99Rasp8y31YkFCuAUPCbj7RDlmjmaq3BqKgFj2ONhxT5KAgqKA8odCm67BitTFZYNIphjzc8oScXBgI/3oJUvtz9lwGKtkccfMV9z5//CzF80/3bvL/tttoDCe8AY2BXfjINntX367wa5V5tVHX73UvP30ufYQxhq5f/1wowGIkgQLHBbThY6IV4I1V1ZaElcGmAtuSbfRwDNN12SF9YLFkXGhjTufhSL27/dtMr9du8/KCmTSbY9si1syielkrou1jsNT8P6Ig5S4WKxZDdXlcaVrL+Xc0qxPDj5YylhHD26gFnC7VfbHk4zJQQgPUJEvs06YUWcVfMZ7zd7RdVVLVssZRYaQk4XTPRnC4VPiY12O9g7E5a4rb4LwnC/1D9D3rt8/wnKIzKJlMuOMR+3i5Z5SJSCbFjfXWWUxzBorYOBAKcOThzJOUrLxqyS4Bwbkgowrh0cs5BiHTpzlhVaQZ8CcIZzmaK9338gP1gAyhoOSyNKgt0GevXx2GBKLTLk65ghKoLRaJ09DGoVI1QrmTaqDqZRvO2/J9Hh5VuY3hwruif8y/91GNskOSE9vS52HkQzkLtVfeB4YWN519rwE76qU1+NQ0hniDZJDM3lR0+oq7R7K+6QK8+TZiWwYrVFuolHlOA9CK3BzSqkrBHwqbFJeSKc8BHy6BhwuUYUzgtV1NyP4cYsCiS+4n7DurJrTEF8oz+/yCvkHF0u8xrFjMXVP8MncuXudbkZYWOPKMXHH/V7cMZZOt4xbfdXIxBMBRZHQBDbRKJYOBPnfXnaCudx3Pd7/ktftaf/R/jEpxwf9jVdO6hLOIc9FNkBbLq7veNySTMa2VBUQV63UyAwrzo8ljJhAxkbA4kEiBe48hLJ7/yRlFfkWNxTjTIVWIBQJD4FX+ZsqG7CAYp/MLRzEayUcruAy375y74a4NfYD53sJlngBpMFK2D3xnFC6bDhJz4DZf3TA/NrJ3EcpH0/8qqv0o+h++Xcb7EELpe8jlyy1B7baylJz1alz4pUA3IMJ95uu8yQHS2JE0xXxl4YKwc5grEFJMFq3z6slGxVemi4Uw1N2/LjgqTXWK0NSEp/yv0/tMrc9ut189w9brRwkbviNp3gJQiAVZ1jvzCP32rBwSeIi74vCKMo0oRmpDgusrWBTEg5qKGUcwLyGJKN3Y2/0439RHqorSm1SGrWFJQdgrKFtbhk3nhHeHkmwxfp6tG/k2HvhKEOeZXBalVUwk8m8MxZMtUo8iY80DBGQ/6wrUaqIUXWT7CgHKKEshD+cuXBqQmk3gb0NuSXKM3vZ/CSNrVzLsZXnlWX2eXKoIh6Y/ID9XX1mb8dIqzEKOnXc7f2HKG37OocrQyVjrm+AkoMieR48b1GcxevHwQdrMPsQLaXDwHKP7EEnxvoMNqmvxvMWohhL7LaEVqSCzyIPYzR7DwcP5joyDq45f6Hdc1wWpEiQ7DvuhVvIIaumosTOleG446MjnjP7F4aF+HsM5K4LYN4px48//ngm325S47pOZQKhbKZasICQEIHinfCO2w0/rHlEKg5EcCOyMbhWTDalHz7pJWPgFvva21ebz195kvnEa5ebv37VEvOnp3mbO9Y9XhtMcGKzAnEFCmRRp6pyIRsJBdsRKAgk2ehRhLD68W82SgQQSm9YVnYQFjZKcro4ZGAz4P6uv3iJjUnb0X7M/PMDu0edsMVmfSzJQYjNHVByECwIEv6NMCS2DWVamsMQI8p18Lug4oZVFiHIJvK201sTrANspnK/hLPIXAIUNLkm/j5Zg5HRIk0L2EQ4YLBRkyQkCZ6ZSDrjPaguwpzDWvehVy2Jb8KupyFMWWL9sBzdze23a/YlKNIop2EJSulw29miAHzldxutssIc/vDFw9coiZEo9cecWHGBA1Ky+FnW6TrfqpNu84k3AAmENnGIYD0Qd5gsETFVW+10B3PWptvWnfX0zjPn+vPT2JJtKCLM8/eft9Ae3gRZ78wZLPpuk5KuEGsqzxDrtJQJS4Yb6hP6+w4v3nS0HhQ56HEok8Msiic8t4suc14XytG+LyEgIkOXttTZdcSBuTgkV0EgcRmwvC6eXmdru190QrM5a1GTOXlOg5WVEtaG0UDc7L/xrflY/eimx+cip5F/KNgCOvIJgTJtvM9JcxrM8ln19hrxdvE9hxwOCgl7mS9vOJCIQsbnSpyqVI/As8EcZb3I4UcqPwCKGc1W4JIVzQmVFIKKnjzDsGS8oKIoSCKeXAeHAJ4D93NWoOZxEEIOYXXrlHhdfwn9kSYkJDeKpTrKwRR5xwEuSmdXkQvs5bw1FvPQEnb+XsA8ag/sxW68MddeV1FmDzepnrMnsxI/Y6zx9gWvHL/5zW82ueDrX/+6mT9/vqmsrDRnnnmmeeKJJ0whW46JHY7H/qVR1NzTGi4YLEaeMjq6z6fsTboNDYuM6y4lyYkNDKXrLaeNTMZA+KF4Yd1hIQXDJOTzaJnsIrFryZQxqUCBNQIFC8GEkmitgfu77GKWVp+caqOETLifzcaFuy8KnPApnM/fdfcP2WcyGmQDQ7CKoBRIJhIBgtJr6xv7ii/JD/yNrXldX2mFcjC0Qk74JDQBiqhrwUH5DWasLwzEZ7uhFQjEsca3uUhMKmPG/KWmtGRMJ8PGz9tQkfSfLxs4z9Zrjb0k4Z5EubKehpC4YwkB+qO/2dZVlJj+wVhC1zDpzDjaSi+uwuI1mBmy1q8PXbzYxiy6MKbvOHOetd4/tqU9IYYcZUrkRBDCFeSAgWKbKgnNbQDiwvxHqVnsKx6UHsOK9fPndpuv3bfRfOz//miu/f4zNgwibENu7+5LaWVNKMvlu285tF2yfIZ/kPHkHuElwYo9eFQIOWGcscJ3OIm7HGAkbADXPtaw2soyM8vf/JNZ/KW6TTp47ighqQ4nQaRyxszGKhvChAKJsoUyxj2gIEfpqubCZ6/f71n9kIFSaQTFVpQ8QgpcmOfb/WdOCAPWSplnNumsvtLuJcQby/kZaz57EPKbuH6aAzG/MNxcf8mSEUm9XIdUBQrCZ2JFPmN+uCUZ7168NKnjykf2bXGSq6nHzVxBOedZStUKQivcsAWMPYQpobDFQwRCksUOpuiOJyxsrkkIZVzmV3NxS79JPoOEViCv3LWBwo5iLPHIkojHYUESKdkD8Oaxr7CvorhHNbgwl5ibUWQSyrFUNJE17sI8ZSxQ/tFNNhMC5ez9NNSR2HW8FuxFtkDA9GFdBBkQv/eegVDvCHt5oYRWjFo5fstb3hL6hWLc3u6d3LLJj3/8Y/PRj37U3HTTTeaZZ54xq1atMpdddplpa0u+0eYjUpMRdidpABIGyicKDQKMjZZJGYz3Q7EgOQ43JTFGxPERE0ysLF2NZJKnOsVZl4jjDuY9cX/CpSfOCD11s7lK3KInKIaVq8HBoXhXo6DFVJTZZHF+olQjJKUua1DhcethSvWLqGCNwBXHQk9VD1lAoIn1AotHunhLl53+M50WEu8m7mMs6AgaBJrEGy9txn3n/Y08e6ncQaKaCJxfveBZPFHeX3NSy4j3D84vSXKRODhRjrFEevVAx+cGY1MXt7coLK/yrVNk74cpWjxPLKxYgulamKoaAvMSxVisjihawY2Y7lqp4o5RjlFi+Rze49qzvNa3WA3dluLWurzzSOTxZg3J3MXqjLLB+7777PkjXJoCGxTlv8KS85jjwc9mzexykhptucYU7tb9SaricD0oT7J+qdBCLsGdf9xrw6QoH8YMQ7H7xzvXmnW+e9Z9Nqk8DTxjkXNBqxyKwWf+ZKX5u8tOMK/03c4C8xKZ54ZWiPWf+UnHQe6ZTV0ULanqItb6MKWWNRKlZrv3OZ6rOUoDFK5lz+HeuCUbmTi1xpPrZ/rNNqQhCJUQoircCbHVvoV8+F4l7vNoSmtfMiUWmSoeS+aAuP5J3EL5Qmm77qJFI5LFkZsLA3XTw95blPKw39kqPXLIOXzMjqkNqQjUqwe8CQ1V5WalH3eMR4r1gAx40G+u8erlM+JKO9ctdd/ddSPJ7zPqkyco4sWTEqPECdMwhb3BDQmUOYbCzL6Dp4IDPzWgv/Dr9eZvfvK83XfZpwlHkbXF4U88IxxUePYomyJ7o4RWCIQvRqloQ3k2eZ00khI4YNm4eDyJElpxyJOHwuGeYaV9mb8WGX/CT0ShZn5KqAdlC8OgQlGmy4TmjXL8u9/9zrz73e8211133YivmppEoZcNvvzlL5v3v//95j3veY9ZsWKF+eY3v2mqq6vNd7/7XZOvUL0hKAQHnE1PLBipTrIunN45vYHEZbnQ9AErFSdW3JW/33TQnmCJlSUuC4UZsOwm2+hxwbhhF3SrIhSDRB7aDifjJF9wSV1DCZUgS55yZIibuVMS5wnleSBZfKC8xyynLqsIGilblxBvnCQZLxVsXghqXGTBSg5hyEaBQB9NXUo5mIQdLuY0VloLTcxPfiCZRpKxsIqJdZtNrtoXpihzxAgizHD9/8aPBycJz1XASKJws8uDm5RYE/ivtGnFshXWplWIYgFgUxcLmWwmHO7YTBCoUlxfwPr4Hw9uiieBsrHdfPe6UCsEm+LX799krdw8ByzGoiC5WE9DkrhjlHOUJAmpIO52YVNlvIbpj57cmXCfKLySDJQOlHF5mVjJV7U2pnTnwpWnzLZjjEWU6i/Dz8ar2JBQbzigpEKquGNc88mq4jA/pNyhZK/TyYs2tx+77ATz8dcss2PI3PjyPRtsYq6rvCfzRPHMyFhHeUCpC5uH/GxJSDdL5mNTTUW8DjiWYIlfJz5ZngfhC+ItYNOe44czsD7DKlaMJSGOw346RQTleZ+flb/At16KJVxCK+g0iOLKeEYtm+fGG3vK8fC9YjQAjBnuPoNcEqu6DZlJ4ZWU/QSw5ktZSXjPufNHdLiTQ6ccqseK7frqXz/WSq7Zto32jQhYgF15jhWXeF+s5yR3sp6f2HnUHgiZQ1LmkkOJJLcHXf5yiHOrBQVhLrEWCEFgDXifXZEgU5GbIpPFekyFIGQG18VIIOeuWj3bJt2KYSLovZPGX6f6HjUqW4wGQiBShVcgJ7uODdfKX+yvJZB4Z5R0L2Qz/Jlt2H/Uyhs8PGItFtkat/4f8OK7gxV28Hj90y/X2uYshRRakT4wM8CFF15o6urqzPnnnz/idyeffLLJJv39/ebpp582H//4x+M/Ky4uNpdccol59NFHR7y+r6/Pfgmdnd5GMjREfdrx1y6NAqfHu1/cZ669YFE84QWOHx+MX4Mk27TUV0S6rrrKYmt9YcJiLTjX38gBhVhKIdHzHqUhFlfQjbn7xb1W8GDJYqPbd6RnRBYzAmpPx/DGjlsKSzTQSMK+ZxLlABcdsBC7+wbMwa5ee19b/YWJFaC6vDjhPqfWDJdyC96/ZLHDrAbv+TRWl5qlvjJHxx467w23j60xtRWJ7z8aKkuLzSlzGsyBzl6zoS15lYLZvmCl293R3n7TmCIB0EU2KxSk4DViPbDP6lCPWbvniB0XFF82IMa7vrIk/jfTasvsKZ2uUU/v6LDWBhRvFE6U5tWtDfEx4u8XT69J+Uy4H1qXchBBEcHKSULSgunVoX/HoYoDEIeUZJYh6O4diLvy2azkmoh7vPWRbeaBl9rMZStm2GtE+NL8gYYdKOh/ftZca7nEFYeCTM1bUeIR+N94cItt1FJeUmT++lXe78LmJe/NRo5QJjTi7EVT4/fEPduQCt/VffLsevv9G1fNtFYzEnqw9Ek5LjjU1Wc2tXWaRdOTtybnXhgP3otxknhEYjrTKdYku1y5epb578d22OS80+cNh/3sbO+264BnTrhKWFJOR09ffH4GEasZClVwXBurvATbr7xllZUfbtyv8PevXW69Txy4f/XiPts05P2vXGDnM5bQ48drE+JK4UjPcB1YiTGNcrjgPbmPWGzIek6Aw2KvVaD6TbdT2oy5VevIlQX+5yDnuo/1m8qScvuZ/J4DGIeEsbh3ccn3DxwPfTZyr3JIwMXP5zXVlNm4YOQtihHWXLqo4SHg+qZHOIxzv65yXOPcqyi2KPwk5YmF+NDR3vjewvxPtf6p7kCYA0oNCiHKHnsJ8p6wiOCzwtuHojrefZQQJuYE1+4lz/XbL0n+8uT5sNwTOcs+8/CmQ1YGrffDK151AhZeb27hXWQOoORh6GFNTJWSof5+0hIigwWifK45f4H18KLU8p4zQ/bnGfXl9v1owc1aJSQEOUR5NhR1tyIG78E6JkTIfZ8pVd78oIIQ/2VPY9w4ACD/eX88NxymeN8webv90FGzYmZ4Q5bDR/usLMKCXVVWbGZhKPDLOZ40q87KT66nrrLEzJ/q9lHotz+3HhrfWEE5QHc82JNQjtkvSMpr76bW/vH4fOG///3odqtz/OzZPbY2NGvvhOaRckKQz8yWjhb1fSMrx11dXVYpvv3225O+5p577jHZ5ODBg2ZwcNDMmDFcsxX4fv369SNef/PNN5tPf/rTI35+4MAB09ubm9PLkaM9tpPapj0HzdL64UE5dLDPFPex2GLmwBG/1WjZ8UjhIcd7B8xcf1/e2tZpBru9jX1XR5/5/mNey9XXLZ9irlg60oq2/UC1eWFfj3nspT3mT06carbv6jLlA4mbPK7k407m8E+f2m8X1oKpFea05uL454UxtRihU2b2dQ2YF7fuM9WDtWZ6aa9Zv8NzezVVl4y4x1ifJ/Q7qKcc+B0WEywEUDZw1LS19ZjBgSFTM9RtZtaVmb1dA+aBNbvs9VWUFJnWyn5zpH3sLbJdFtXGrJDCuhNcTzMrvJMxv9+5Z58pH0jtXhR2HfQE+dTyoRH3ylyYUVNsth4yZteBDtNz1DtQzGssN+UDnabnSJE51ukJlJK+42aw+6hZNaPcPL3DmPvX7ze9x2OGJoBvWdlghnqG4/GmNVSYzsMxM9LGmMj00iFz6FinWdZUZtbsMWbNrnbzqnkVZsfugYTEMQ4MbGT9A0Nmy0BXaDyhQNKdWP6XNAyZkgHqMg+ZU6cXm/+r8KzeT2/abVbPqjG3Pd1mntlx1GDguvbsGWZ5c4lZdv5M8/VH9ppth/ustfJ9Z8wwK1uqzXce32de2NtjyoqLzF+d3WIW1w6GzkvcoFzvksZi8xCehj0dpqv9kNldNWCtS7tx0x/pswcSWDHFmKG+bkOlpsuWNppfrG03P316pzm5yWtCI2zu7jCD3UdGxGBaZbj/uL3nPj8k5aENh+0cnt1QbhbXHh9xnSjDPEM3+fXsmaXm91Mq7H3f8dRW867ThktnvbDpqLU2bWvzEmwEPsNWjugvNW2lIy2SQ85Bs9YcGzH/sAIP9XSaYv89B5NsGO84ucEsm1pivv/sAat8UP/7r8+daRY1VZotO/tH1BinpNrW/Z41bG5diYkd60jbUKistMg0NdaZtrY+M9h/3Myq6LMHV2Tp9r1tZlZlv73f7Qe9Wd1aEzN9XR2m7Zg3Rq3Vx4fX5959ZhCL9xHP4m9Lz3V5LvyNB3utojmzvty6ztPBM9m8oy9pjdwXdnp15pmXDabHtLV5TxF5RYjS6bM95fjxzW3m3Nllpq3HmN0lxxJKLYaxZ++ReELo/JpBc/jQsMdldpX3GRg09uzdF5+TL26h5rwx1WXFpql45HgHqY8RzuWtgz87qcG8ZlGNmV5bNmK+El7QVF+fkVDGwWP9Zm5dscG0tXX/EXv9Ww8ds94BRmNe9YDpPHwoQXYV9x0xy5tKzcObjHl44wHTNxizsv/sWd61cn3TK6vNvDpvPLe2HTH797eZ2qEe03t8KF4Zqri/y7S1JU/KLO7tNAO+9RwL6/HumGnrCYSlocgd6zTVQ8Z8+tWt1hCFwu/RYwb95ynUVFaZtraRVt7qQcocHjdLplWZlw4cM5+5a43pOz7y8HbPmj3m+lfOGmGM2XPMmAYTPo9Yfxt2efvvgikVJnbsiJ3Htq710Q4jzhD2n3m13rrZ03HM7N2338yq6LcJwjv89TurtsT0s876j8Z1kXm13nVuaesyu/fsT5BJT+7sih+MMU7s2Ntm5jRUmE078UKXJ1VeZa1i/Mw06LIZVY7PO+888+tf/9q0tCTGMeYzWJiJT3Ytx62trWb69Ommvn6kmygbnLXkqLl3Y4fZdmTIlNR4MaJQ01hjmptqrOWnvdebTYtmTzfNzYn1I8NoGoqZxW0s2v1m95F+M1RZby1p33pylxkYillr4utOWxAq7M9aPGRe2LfVPLG727zx9AWmt6jI1DZOjVd3QEHtPmRMia9Xs2E/tsNbCG8/c4Epq00fOnPSnC6zb12bWXvouDnjhEZTWddoDg96AnYG9x24x4FyBNQ609U3aMfGjYs94FsFOG3PnTU893YcKzPLZnWavS8dMPdv9kTnXJJeZjSb5uaxtzQNwnTHZYU1060h3VTFKXyX3ax395WbsyOMGxzq3WT/u2Dm1NCxbp3eZp83MvtwvyeYl8xsNE3Tm82MGcPzB3b1HjSrympNyVNtVjEGmn3Mbhl+X5TalQunRnZ/dsSqzMrecvPTFw5ZxYG5VVxdb5p970L70T6zdU+nGSyvNyXlxhwrKTXNzcNW1SCP7tltNwysDUvneeW51u3pMmwf5y3psdbHB7Z2mw2HB83jO7xyR395/iKz0k82bKwx5m8uazTf/v1WmzD3rcf3WcsZFsOykiJrTZZYvSCzp1RadzCW62U95cY82WZ2Hek3vaW1prS60TTWlJu+dmPWHu6Lu+anNk2zG2xJdaO5bFWDeXhbly3vdu+2PvO6kxPDifb0F5nZM72mMrZRzlGshv2m/zjPusyuIRSlB7Z6CZKXrJhpSms916mAkkWpPcanr+yI2XfEuxaez9vOLDO3/Pol8+j2LnPxyjnx0n9sNbt7i02xk0TKAYCmGrjr/+mNK03D1KYRcc1Yj0h1sBajRbNNeUjc8+7eirTl4IB1jbxiXNj87t7YZa6f22IGyitNc3PieOzu6zDbO7xNd+HMJnPq0rlmCzGNKSprrGptMFOdyj3beg6YJTMOmhd2dxqW+1mV9eb4wKCVf7C4tdnMceTDipJqU1G61R6a9/dXmFOam61cQb7s2XXElNRU2Jj37zy8x76e+UnlByysxDdjIUtm2eorq0gqY/Zt9pQhkt3mzJoZt+IWV/WZzl1HzJlLq80dL7bbtXXEVNsks6GKWtOcor49SsK2TT1W0eU6F8+daZqbh2XBSQMoGdvNkd5BM1BeZ6/N/s2TnpGAEJOZLTNMc0iFApfpVBgabLdJiMwMP3JtBNRWbvWrFIyX+oFBs3DmgDHPHzTbO/pNV1GN2X50IB7La6/buVc4NFhpVhbVmOIn9lvFGM5eNM3UT2mKJ3xjTV/EHvlUm9nR0W96ir19R0oZIjsWtc5MmeOzt78inrw3b3q1mZHkng8NVtlmIQ016ZufLJ3XFDqvYhX1pmtPpzl7yXHz0gHilGPx6ySMEAs0Mb8Yg770+722fnswPKuvrNrMDrnGnccOmy1HPM/vkplTrB7S0lARrxntMr+33DRU7bHhEdt7ysxFU5pMrGfA7D66xf6+tbnRtM5qiXtOrC7Szv3ssyUwj5XUxi3beBfvWOM1jZEcqWf2HzfzZs0wAynWEMqxrNVsKMcUcohC5E9evXq1rQwRtNA+99xz5rWvfa3JBdOmTTMlJSVm//7hGqTA92FKe0VFhVWC3S/ggefqS+rRyumJQecLQcfvOcmKmwflLsp7Ury/1a/piWzADfO9R7Zbdx5xV3/xyoWmpLg4/lnu1ylzvZaXlLzacrDH/qytqz/+3pv8n1lXEjGXfuUDCqCTfBH2nvLFoufrpNmeMMPlzXsc6jluyyIBySPB+5lW601WQgKOHfdOi/K1x1cWcOO5P7cl3XzpLQlIuHewmmR6DBuqK8yZC5ts9vnwvRab2fXeydfWsIz4XiJsW6eEj7XEb3HKjifjUUuzpmLEa9mAayrK4vGAuOFed/KshDGh5BPzJer1UdydcA7crFjmmLftPcft73Z39Jrnd3caDPny/kdt9YfEMXO/Nh/oiY97bQX1UKvtJsHfXnhCs1WGuc8HN3ihQMxd3JHuPVSWl5rrLlpszl8yzVolUIxtktCFi/1azSPnIs9m+Uxi6UiIqrTzxY077ug9bpVeY4qswgWUtnLfg2oSb/LLE1Lbmw3D/T3Wz+d2HTG/33TIPLer0+zp6PPi6p3X2GS27n6rJBHP7v6uqa7C3quMz9KW+viz4YumClT24Jp/8rSXDCu/C37O7c/utq5p1gIhTRw0g2PB+AF5A5XlZaHjxTpLtcbdL+bK1efMt+9JQiQxqoe6vWfkvieKg7j3bQxxXaVtruOuJ/eLklLT6hPlBEltkpS3gfE7Rvxvt60qgjwjXtl9fW2l10Lers8D3fZnvDev7+g5bv8t8e7MO+bxszs7zI+f2mU++8t15iN+OBzzLXh9uLiRu2HPb9tBv9FRQ6Wd7+66YmyJW0UBZ0wpPcb77evsS7km244SZjAcPkKjE/f3LQ3DScgb9nv3ymE5nozXWG3qqtLLRfbWeU01Kcd8en2lWTg98VmP56u6oszGwNK4g3A+Dpfb/GofyMLgvcqzRO5JGTG4ZLl3+GH/YR+tKvfKVEqy2Pb2Y3av5Vl7srLc3m+qa0PJk/ecnURe85VsHge/sNSWJpHFPFeqWJy7aJqN7f/kFcvNv75llfmPPzvVlku94VIv5h+FmL2b5lusd/f9d9uaz4lrj++RCfFkvOZaU1dVZlbMagy9DpLy4vWOD3XbddHNIdT3WticlLLS+OuRXdy/KOokX8v1kN+EjOUA+GdnzLW/l/rZB7sHDBlIyZ5pUIZk+iujyvGtt95qrr76avPKV77SPPzww2bDhg22SsVpp51mJ1kuKC8vt5937733Jpwy+P7ss882+QjFyCVr1k2+kFJuuC/4d1GaDkZBbCC8P4m//9h2K9j5HGKbKdmVDKxJorA/tsWzLEiyExuYazXi97hN2Xze5DcoECgtdnJrg23HfM7iJnPBCdPNxctn2NO+V1LJS+oik544RwnCD4uFJNZWStgFK1aIK5FGHC4cAqRihTDWZLwocFKmhJDU7gTc5LDz0LF47eJUYM05FNIAxEW6eyGMeGZFfnYxim8QqVV7+coWG0OKouKGP6AQpgp5CINNA8Ek8fEkuxELTqyutOkNQqxpsvuVWHAUFTYbnp0kgzGGMheBjk2StBSEv/vzs+bZ5BbuFWVZSjoFQcDzO7EKMb94Lm7zGO6J0AfiT6Uk1MlzGq37FJe+QLwlCYRYPX76jBey5EIyH7GAySBzXUpkuS5PlNBT5jQmWPRZm+6GD6w71jXKp5SaC8K4kGwr4O0Js/5KzGqqWurB8oLpYL1z6ECGEf+JtcjNcidBDWWdJ2TbHU+piiscjBFyxIUDvzS2CF6XKMck5dnQHj8MhbUkXTYFDiNSdos5KDGQIodIRpakTyztKB7MLSsLWrUAADgkSURBVLxuJB3hJeLA8cXfvjQi0ZBDUbLkw52HvWvis10LIf+WrmpuXVyui9CxZEm9fA6dT+PNP6xRJPFeUQDlICBJV17baF85nlplaiLUfZfrprRYGITLkLyVrqLSaGE+Mi+AWGO3M16YPGcecQl4F+Dkluq4nOO9xAtKZQs3WYxEP9lPkoXFuJAcLXtPqq5/02oq7MEnHan2d/YXkb3Mfw4pjLP7rLk3KrqQSEjYCQqyyFepBCENswTm1gHbDGfAGiKQZay7ZJ5ENylvm197mr2IvwdJhHfhYCat58UISJ4Sh0sgbp1DPrIVHYj4Y2K5Jf8hXxmVzZr4XcIUXv3qV5uVK1fa2A0S4e68806TK/j873znO+a2224z69atM9dee63p7u621SvyETY8YnXBjSmUDRWrLxCoL+V5ouDWiJT3oKB+WLZ+kLMWegoIpYlQDtgImMxuJrZ1iTzrxy+fPDOhPBobO1ZkhD1KOsJINn5+x7+X+9bMP+7usK5esRxJ6+sgcu/BMi/xuqwBFxKCBOHhZt2z0Y7mGY4FPo8DAe2exXK8q6PHdIV0pwpi41D96iDJlOPFzVhuSDiLxTeruqrS0E1CamSiyH7mDSsT3GQcjsMEWTrYBFBi4/WOCaEYjCWUC0tWhzoIsWqyGWHxkjnCJiEy/09WzbLPAsWXkkmpYKN47Ukz7b1KR6kgjMuqgNIpXbzi5f/2eeX/EM4ktTImWMpxxZJk5JY54zPfSqMKlJkth8wfNiVW10gF8dZYqbGKXeTXOIVpdRX2GsPcq7iE3cMtFhlp1Yv1ONiIg1KJ33vUqz4jBygUpLBmIFI1JFW1DM/zYkaFlBSUElTufHDbutuk0oASixyhQYRtFuErzGHPhQMPYS9ssCh+WM2knrBbvUHgQCRVAWzFCv/wKh4sxhJYIyhWKCTMrQ9fstT821tX+wfNYjt+n75rjR13NyktrGMhMlPe363+IEhVBhQFDjy4yUXp3RfSkARDwQu7O+yBNNjoxKWmPLF0nShFcWvf9OTJT0EYgzAljueJMjre6hRJu76KEoty7HbGC0l0Ro6wH1FV411nzUuIx5cKFUGljapOtpJCvNtqeuWYQ0e6qhbAsw3W5g7Cvug2TwkjWHs82fr82KXL7MGBdUAberceult+NV7CzT8wMXfqq8uSlvQLjsU2/5lJRSieWdg1Joyfr+P87Lk9Vq7y/DF44IXDGADSrCVd18+JJrIYJHTh+uuvN//0T/9kS6iVlZVZS/IZZ5xhcslb3/pW86Uvfcl86lOfMqeccooN6yAWOpikl08snuYJabeLnViOpfan1wAkugXenZBAdjHWqSiguCI4SEwg9AGw+rjWT9r7clrkuhBCAhunWHDCkELtbHhArC5It7xgGTdBgvNxWYbVZRWri4Cg4UusgWwYtrZlmsSWTMBGjEVx/tTK+BhSJD0dspkjnHBthTG1usJaIgRcsIxV2OYmNTLD4FmkqiKRTpBL+1VCGNKVqiN2NKyqh6164nsl3HqojJtcN8r/p163IvLcTQUZ6liiw0pWuW3HsahxbcQDc3gTqzEx+mwAuPBdJQ7F6fWrvHhp6pZKZ790/G6dl7BESShJkuLZ2qz0JEoGynjwUHPFSV7sKh6ehzYkKuccYLEuohhfc95C+zOb9d8zMKJ8pChgqbwJKD+j9b6IcowMIffBtapieUpWlkvgeihjxSEv2Zzl8FJRXmIW+TKP+sZxhdG2Uh75d2KF51DQ04d1dsAqySi5Uj1ESvYFnwHlu2563Ym2njnhIlRW+Y8HN8dLZnGID5bBxEou8kqUMhfGiDmKMUGemSjpKPuu8o1SQk1pzkJe5RNv7BY114ywYtpQAl8pRDnv9Q+lYsF3qyRFgQOae0DiAE7DodHsT6OBsRUv6FPbD9sx4vCAFy3ZZ7IvoSRTk5k4bKgNlAl0DUisCeZivDueH8qXCqmpL6VGUyEHn2SIZTwVfE4Uozz3ecOrT7B7AwYIasLLgYIcJrf5lm3+4YRUpOsBQG4PHQnlkMt8EqMeh6a6kPUZtByzLsWI8JZXDHdolRbqT21rt8nB4rnLVyJrEgsWLDAPPfSQ+clPfmLLqf30pz8111xzjfniF79ocs0HP/hBs337dlumjZbVxELnM0unVyW4HEAmhVjW0tU+DcIkXdJSa4UBE/OdZ82N7O5CmKLcuaEVbkF8NgCaScCVq2cnuIPnpFG6hgu1+yXdDh5NaKEbZlEBKVUlMbkC8YphTQvkbyhtAxSGlzaoucC2bvXHlUPEvgjdrnb61tdUVgsUxxkNw3OBJCGeZzLC5o0tYxTBg5AM5hTKJM+c7VosB6kIczOjoOHScxtxhFl4MoFs4Mncn9wPQtztrIgyQkwweLU+uXfveS51OmSJ94SYZA61X39gWElKBooJnhmJhxS82NjU61Q6QLqb9Bt85dwrF3U8XtbsXl8Bp7EISjzWTiw2Ow7jzUg81OxLsZYSnpWjYFhluarMHmJsvGHIwYNyWyh+fC5hOByy5fkQ3uGW5QqzBIKMTTKQbYROEEMPhETIevI6e418X6mNjIXqSC8lsQbicnh/V58N5ZK2vcnW1t9eeoINt+A50Inypl+ssTIbPTYYTkTIlBzupUlQ8B7kYCJ1cSkTiDcA+Suuaw5udN6URlFYO4n/53rDupu5h0+UbBQkwqDsPdRWWE/FaEAhbfEbZLAmWFdjPWhHgfklrnw37CxZXfawMDv5m6ARQ8J2OFju7zwWr/Md9ESGwVrCUxhlX7UlSuNVKswIr1UUBZu1Fax+k2qf+PDFS62Hj7lBfWVBmi4B4Rdu849kFSIE7pWwten+88Ggl9BIJuQQikI9f7rXNIW5+58Pb7EyFmXYna94hQhVYZ7buudDhFb0F75yTJONZ5991lxxxRX2+8svv9zcf//95l//9V9tAxAlOZRnAVzT0jFOLMfi5hltbKhNOqqrNLdceZK58fJlI07YCHMWK64hviTuUmKjJLTi+V0dI7o+UdOYEyldfdz6rvxtFKUL5Q/hxSJjE6ERCSDckwkl2ZCDi0XiktzORALCk2S0z77hRPPOM+eOujPeeOHzRYCv3RceDxrWACRVzKct6u+EirDBh8UbC2QxB93gKNTjsaCjSPKebivpIMwZmsnQXjhZ3PFGv/EDmwwucReeW+pDVpFVRtO5IuW1WB6DrnWXeNyx02kNKxJKPWuFuqlsTOI2JhHIXZNYlf/ilQvs/MVq+O2HtiQ0yQlC0x3WOAdXUVxoLpPKpenCuLuxn9TERXlk82F9YrXk+cf8ZFkJRxALXFjcsYyRO7/CQHnm/c5a1GRb3uIWxZNAghPtgINNcng2q1unJLQylzaxuPZF4cHqGabERsXGHfv1jpFbyCiy+ZOFD0njC8Zh4/7hNsLSzhcvQ6pYUntvxV4oz9+/Zrl9Lp29x+OxlGKFFDb7DXtQFpI9Y5lTPE+s3RgNCF0ClG4OFs/uOGzjRwU3pCLZQVmUceYzlsPNbd1pO+OlAiMGOiGhWlEVtrGC8YWDnXvwsgepFOsZWe/G+fK3wdAG1jKJwGKM2NLWE4/JdQ0QqfbYZOFvYUinQp4bhhs8rHR8PG3e1MiGqyhKu3vPbz+j1f77+Z0d8TAFmoIgJ5DRnT0DthZ/3HIcwYBk20I3DXfKk32LZyFx2C42ubimIm7wwFODovyngTwlxlk8JhJaQdnLfCXyDvq2t71txM9OPfVU88gjj5j77rsv09c1qWiqLrWLGUVBitazsdoax77FLV3MUrJJLBUiXFiHKBbnLJpmzlnsfZ27eJpdqKLsMtER9sS2PuNvaMD1SHLPm09rTSgHx+JKV4/TVf4kLlRcwfy8JMnfi5LpuoTs9/7GSsZ1suQhhBIxTcF4xmzDxioxzygj6VrB0iUwykGIpBvwXPyexTMZKMFi7RQrRToXXzrYVPhMCa2QzdudI7fcvd4eemjSwQEG950c/ASxWNhKFSEbXbBTVPzzS4psFQfi24jvThVHXuq/NkooQDDuWEIq+BljGbTuoKC6Bw8UOypksCnR/EJi8oMQWkBzE3BDkgh1iQqHXTcxjTF5i185A2vxbY9us8oZ40Q3REH+BotPsO32wa7+SNfBfXrVFrxs/eB1oVQGn41setbi6cs1NmgsRCLfWtKUEksHCgeWQDZeicnHk5VMeeOwJFbyNXupP+yNjVj0OVREhdANEkblHnkflG13zlM9Q9Z3skOA1wSpxJQWF8dlsSjrJCsRtx1say1xpCgfhCAkuz6MD+wxVF+ReGPc+WPJw+DgyjiP1mgzVjCOuAdoG4KTRp67DTYo2xjmkeE9JLzGNqnwjS+iyKZjNEYG5tqymZ5C/Ir5U+2YpDt8BRmtB5n7YJ9lNYgXSeYMMpl7xkAlBqtk8yeZJX/zgaPxXAXC0pIp+cxr13B26YoZCdZ9OcjQLEXCZ1IZF/KBcQdozp8/3yrISnK8DNRhiw4gXHFDSgJalJikIMmUJiw8YW4nYLGiJHBNIpwf90Mr4PZnd9lJiyVNlCNAwEqb0iiCFUudVBMQV2OqhS+CTpRh4DrE2hOmSHEvYllko64dh1VqLFSWlth6qIDrKd0peP+R5FZwF6x1hCFQlg0FJZ2AlueK3EoVDz4aULhRGkkmY9OWQxzhCJ/71bp4LDGwodvmE4HQCknE8ipVlETKjEcJXN3aGJ/bKGPE7Ia19LZKdOuUyB6DYNyxxJ1ykAyz6DO/5voHFYF1evXZ8+Pl3eiiB7jGOURQOebG21+wFkYs/qfO85RGFKLRbnxBNyab4PKWOmsJxR0PJDK6FnhxIweVYw5usg6JKR0vZNNjEZOkJeYdFlMUYg5FXhKul5meqUoy/D1j4m7CYQlqCRUrfCVo92FvvhJGQ0zrVGcuRIWDB2OKxfrF3TQpGA77ArlXDhZ4S1K1THZDK1C2sfIRRhFW9Wa4UsXIxEP3Xt2KFWLtmzcGBU2IUtEhU9gqCb61cthynFqeE78vsj+sHTogG9zqC9J6PF1o0ViwbcunVI8rNpv3GG144Kv9A/gfNh+Md8zcRwiJ7eQ5HG9MSFMUC7ZrOV67p9OGbWAQCFbSSfibqlIbtuH9fan1tgiMD4dnPnr5TE9O4DFxEwnzkYxkL02ZkjxuS/GQgHVicEXxQ8iKMphscaciLH4PJSIsGcRFLDhnLvCEM2WiKG3FKZM6hCyfoEsk1akxmeDC1Scl2iCVFUIEnSjDEn/M4ZKPTaZYiPWYTSNqRnamILa3tUmU4/SJa+LWTjfWKI0fu2yZTQqKskFhFeAZYVlKFVowGlAeENSibBFagTL5L/dssPeJUkJ7chAF0a1SQFKQJJtyv2EbBoqw635GiKKoBi2BHA5QmN1DhacYN45qIxErvMQdS5UXPlMOdEHICg/G2RJmgGUEvvuHrTbG7qP/+7z58u82mAc2HLBKKe5HantiIRxrjLWtU+0cdvjeJrj433O4JR7URTYwGzLS2Re3bO7tPGZljlcycvzKMfAseRbEtDKWq/xreXanNx9ouDAcb4wlcHyHV9Y3Vi23hGNYpYqEmFH/XqXqjVhpz1o0NVJHvITPLyqyFkG3Xqu4sgkhEYXUq8aS/L3FS8i1UwmBww6WtDB4X1GOF0ynfm+44sX8FWso4Rli7cvUYTnbMDdEiWXcFjbXpDUKiLcRj0IyhdS1HLP3Six8utCiiYRDEFZnvDMktmNtxRqN91cOoy4onLbb3fEh89BGz+tLIif7p9TKR3FNlbviwhxb1ExPg+HwT95f8oKSyQKMGG88ZZb50KuWJBzIMDCgcLOXIQ95HdCEJ5/Jfmq/YpG4QyzHCDysDnQbk0S1sWyeuO5cy5vthuY3RUgX12RbbNZVWAXWFqTf2m7+z280QAa3ez0otaONOyMGCeHmdi9LdVoXl7YkpcBOf7MhESeZoBQBma36xumQGEg2o640ncUocG8iKCeuAAzWbw2DjYGxHE8SXthmxdwS7wGxxf/1h61WWJIESb3NVy3zEs02H/DiOSk9hUcEsGCIQiJekzDkWTBl8TQk83gwp4l/xCsi1uXRzknxNLjKFYoysfvJkiSZd1J7Olh/mFhXNqTHtrRbayQWTBqVfPjiJbaAP+EeosiP1VLF/HYTqliXV5062yr0bz/dK6zvHtaa6oiV9ktHHhy2Hotrng0urDPeWOH5yAGKMQHCtJBxJB1TQgsYt0ysUSy3kmgHzHksUcnmjBgK8HRgzV/j17Q+Z+G0+PPkWfJfrPTp9GXJuCfmmYMHrmsOglS0kHrxHARSgSLLXOH6xHosXowgv9900BpRCCU5IZDU6kK4mxwE/rjriLX2EY+dLIEv3+CAwzigxF22oiVt4pjIPZ5jqmQ35gaHCjxg7LXW2BIIycg3CCfjUIN3hr0XA4DIrtPmTxmRFMc8ojMq3Le+LV7ukcOweO+YB6mU2yDT68gZGt6n8JCmil1nLJjXeDtZ6wKGBVkPciiU0Iqnia2fDNUqlPGBlYAFymYloRTihmMCyYY2WiQuS8qnhWWThwlScSFLaAVJPtR8RQi/8ZTZiVUZUgjlVJu6vSanHm2q0BFRilzLsVvmLhmy4MdrlRorS2Z4gpcNbEuKEl9eAxDPspouycNVjqNaRlEco8SDRwWBy3OXww2KBbx2ZYv5wAWLbIw3VntRPjyFaDi0gvq2kmxKp7dUBzyUP64/WK4vDIQ8h7exJgkxX9wELsqqpUuSJJwo6LpnXfzl+Qvt+qEaxccuO8H8y5+uMu86e75V8t3DnO2MNY6x4QDrKm2vWTnTWmeCmyQluxgTiTt2k/LESp7s8JGJcAfGEPmDfCNjnv+ikLA+GLexuvdduD8UKMYDa1U6j5ZYTlFcacuOcsSclbh8DmcoI7wPzTlIfMQC7jUrGfl+uJs5SHEoesGvdEJohVfGrTeeeJiOmY73jo/BwhcMS6LkFaUD4fITW2yXzFQs9C2vUhUJ6+hEGQ1GC+tpel2lufE1y2zZxKihUoutNT257LedHJ0mI8B756LkZzaQMLPgvoAcIpwB45J48jAuMU/xYnH/o0lYrw/EECerVOES9v4YFuRZo3CjE2Cc4FoxKDyTxGOSDxTmDClACC+QBhhY2oByS4ASUlU2NuVOhJ9X8iv65B8uSD/VCiYpkk8CkauMjiWpAHhPFBi3ixnVL9IpuW6cpCSwITSTwbWhTOa6UoW7WcuzpPZqMtiwJIkonZegptyzYHFfUePXslGcn3kgZbp4//eeO99cdeqcBHe0uMiCDSCwWnK/tl5pSMczF8r+jSaJcDxKlttpDbBWYSFPZVUJhje41q73n7fQvO30ufb3YWE9NtxlFIl4YWCRSdc9k+eHEsA6cJPypBmIlIwcTTb8aGiur7CK8Ul+IxqqVsjhn4051eFjNHB/VRUl5pNXrDD/cMXyeDhWMmzFihKvYsU9GzsSahujYAQrpnDAZBPnoMHcDoYxMBfE8hVvZtDV65VQ82VoqsOgO17MDVtxZ6b3+se2DluPiWn+zsNb7YETb8QbTpmVNrFuUeBzsfZluylSJnEV+ahK/dQI86qhqjQh1DCXsdTZwFZ9aG1MuA9+dtEJnifvnrX7rTFG4o05rCGrRmM8qbcx4NUJnu90fx80UNUG8pT4e3JZkJMSnuR29sw3VDnOIYucrFnXMoqLJ4rFN9mERNCONiyDRhMoBUxgse7ignrtSV4c6bBLZOyuej4D4c9CxtoSjI90EYUc5Tje6tV3U6ZLZGJjHk+JqPFAEqDEEJPwEeYmIkb3YT8WjBNzumtFeKAAZruEUjoYE5Tif7hihbn5ypNs9ZMg0v6Z0mjE87V391l3usS6MTfp8JeKXFpxJO6YeGmqFXCoRHFLF4rERoR7drTw3lHK0aUDJS9ZW1/CKSS5zMZYSvKv0wxkr68cZ6v6gLi2pWoF5ci2JsQbZ+bwauOOK8vitbjTxdgz9+Tg1dXnhSeIcpuuQhDrD4tcMIFW/p6mJ4RU8IylBTmx+lFc9shWseJLiIe0kybp9T8e2Gzd4oRxvPPMeXZ+prvXJdNrrZVemD3GMm4ThShXWBczqdQHraD5HFIRFcnDcPdGErmZ3xxKUYwT6huPMsmv3saADz8zOcClImigwmAQlKvDoRXevkGzkLAGUvmAKsc5JL5p+ZZjaXgxHmsOG8RoOyDJJiMbJYoCyuufnTk3QXHjesdjkRSrzl9duMjcctXJKV26kliH21Nc+OKmbEkTcpLOqpZNaiqx6g1XrCBL34WF/9yOjni8cVQLGlbj0Qq0TMNcQLFD6CULbUE4EybCeQZroU0EOdpvtvjdIIlby6cNWmL3iBl+77kL7PyOOiZYZEfbUCFTzU5QppLFlKMYi1WH5kBzp1SPaAYiDUDGUjIyCsxVyjVhiUdBI8b3qe3tTrxx5uaAe2hMp0TZihWOcsv18TMUsCjeCpQQwkVObm2Il6PCA8ZzxDNCpQl4aa/nNSI8LuphSOLQOVDgWcTr8sBLB8xX79tkY4YxWrzv3AVWVjNPk8VWC1jCXWUJa18hhQ/IAaqmnPHJnCfMVl9w1s5o13C+wjNiPss+y+FJYth/u25/QqWKKDHcLhWlJTafhmZhFy9rjlT6js8XXZh5GLZnoGcwl5GlHCTxWDPn85HCWTmTAHF3kn2MhVEqVYzHmsOmOFYFVoQz14XyKtUrgAYiY6mg4SIVADg9kpSUyi2D0iLlj0jsAlEo021imYhlHCvckwheaou6FSuwoLJ5oiDLPUUt58WzkwPDRJIq3jsYWkGCBZC1L12VUEwmcnzCcA8dCPN0rnkXShyGZYyHEWxnO14IzwgqXpJQ6G6YKEnBZiDxSikZqlQRhDWO9ZgDlcR0S0MfriWTNcilKU6U8o023tKRY+f4ygMHotG4mXnGNE5i7nihFd6cl5rJcpDHyhw1FIrnhTeA9SEemB88scPmLxBn/oELFsaVWy9ZMLWc9ypWDM+FZM1R8hXGkjHNdL16nu+8acMNLEZbUjHvy8Q6SZeX+Il5GCooW8dBlf1pLGGHjTVl5przF5q3nzE3koEDPUQOnsnylJjPyNtiZw3d+fwek4+ocpxDODVh6SD+DQVZEvOyUXMxqgUmmeLCaXM0pduSIYoHNYHTIQtY6rFSXxfGq6RnG3FpEwZCSTzAlU1NVbEkyz1JjdN0oBhnwh0/XlK5IMWSJi141+/tslUqiHOVkJhMVtDIFK7CajttjUJJ4rUntzZGOpBmukU2iq9bfQBrclgsNApcsBmIKKrZXEuidEhohb3GEq/lcSaTRRkzRFNNBAujrVjhP4u6imJzoh9CFrUJhAtKr8xnCa14cU+nnfPSLa91SvT5zrXLwUYsfoAn5q9ftThByY4SZoAslxAQLPUT6VEbCzwPrI/ZaOaEPJVScVHr9RcKXpm0svj65gDv5gzxPMeyl9Q7YTzpkvHif1NVZuddqtBB8V4RpveXFyw0n7hiuclHVDnOIW5pITateAOQCVT+wqyybK5RKgdELekGqYriB5VjsbLK88nnmpQSU4lVgu5UUticusByHwn3EtFLkKy0WK4h1jbsjISVCpcbwpA5hIWY+6fEFXGTkkyZj6WkXIv8WBLFsI64DXKSHRxmZiGEwSurWBa3DIblKrhxxyJnZC6yWWbzIIWHiNwCmTI0HMl0AhTWJ5SoqDW9qRd+xUkt5n2nz7AxmTyzsa4vDlaMLTIJuU1c8LM7O+KVWUQBi4qEfDCWNHhhf/jIJUtGKBdR71XaSJMrkk/hTKNRyDIZguO+75WnzLbJjW6DismCexCXpiDxeONRhlSEVcKqiahcYwxLZxDxOuUWWS8Wddvz1filynGOccssjac7XqYIs1qTpJQppKRbFNe6xBLSjphQBAlRSFXlIh+oqyqLL3DK4W1q64pbTgWxKEcd60xY7TMBFr/gxkyjGdo6Y42QeHmxHj+z3XPnUfcVo96SPGxC4HZWHGv8IUpqmKIpitOqOQ1Za0rD+uTzKUGW7JAp1lLbpe5gt/VWFWV5LXG/JOGyjkU5z0RnvGShFVGTttjkKU+5rLnaqRQxtrHh72TOi1uYGvEStjLawyDPirnIs7vh0hPMJ167PFQRjnqvVCx411nzPFd4AVWqcMc1G0q9rAlKLY6mMk6h4IU0eTINy7HsRzQIGWvuSr0/f2ps9aRo6wWjWjovEXM9VW3qfEGV4xwjm8Yavy1jNtyvo0EK0ruVH0bbvjJKSbcoyjEB+oALWLLrKWQ/0VUb0oEwF6WXZgtUrQgiB6FCc3UGwxAoR0iWtAhA5guc6scdk7UvVQoQlBOdVJgMros5OZ6NGCsdVlHehzVM7DWWKazK2ZyzrE/XdZqsKYy4L6XuaUOGG4CkCq1AGaX5ywVLp2elBjnPN6rSHWxdPl7lKNjMAC8RyXnIOpHvo3q/NNcTJbbaPQhQq3lGQ0Vka18+EaVyzFjwmq54OQaE+kw2eGaiR/Dv6y9eYq69YJFN6hzrfl5aUmxzj7JxyMpW1ZxMUnhHywIHdxcLlKQLOZ1NVI1egfi7rt4uK4Sz4QaXxJOoStiho/1ml68c87N8saImo6Z8uGIFSXlBhmKxeOe/dA1A8hHGYPuhbhvfGjzI4f5FeFJTFYsaGfe/WbMv7pXIV9eulKkbD8xLDgq5blsO6T7Ts5TVWHe/tCbOVK3hVBCugByhgg5fLN1MtTQPHm6itn925yBzdbyWbNuuuIzGTZV2PUt7Zw4GY7lX1slWv4JRsj0j6hyTe2Vd5rvcDCNbawlFD0NQ//GhgnwuUcBjRRjV8cGYlW9WxpUU2Qo2Y6We8KWKsqyEYEXRCSaSyXeEynOwMqFICEzgqNnN2QLrH/JidmPqQPqxQhxSlIQ8UY6plTtcA7oA3C+2NI1fscK/bpe1ezptbCLPOF3r6HyEFtbEkSbzcKAUs+FIxr00uZk1pTKeIZ6PcceZUBYnQjGOgtsMRA5suXBlooS4Md3Ik2w0qBlNlR7mIAo7zGwY/zPwQis8yxdx90JLXaU9KI8WnlEy6x6hOxIiE+m9fEUoXw+lEwmKHiXzJiush+D+wj2P5zDQUEWjnMzLcDcZNV+ZvDMlj3GFHRv0WBuAZFJhx+qRrcoCCP8oGchS2YLKDnScgul1+R1SISxvaYhfO61kBaxK33xoczwxiLbLhQaCLFWNaol9fYUfWiHMm4qXJD+VR+b8ZGgGkAw3KU8Ya4v60eLGQk9UW3cX5qBnSc2cO1eepcQdy2FwrAeBsPrTVJ4Iq0aSiuoySmdmtonGZMELK5rcKg9he67IHW9YW/0oEl9HS67k0ViZ3DMlT3E3rXypubhiZn1WBUeUTUOeRUf3cCmwfD9dCi2NlfH6q2I9PnS0z/zbvRttchr95D9wwSIzGcFKRWzavKbqBIUzk4md2SBfFfdM4DYDEXJVMpLQCnm02UjGGwu1fuxkprx0kkfBoVG8Rgv9DqhjgbhjsW6LNw+ZPJaDLJZytRyPhBDGifbSZhvmpHsAxOs3HuqrSrOmF+Apzuf47/y9spdBG+lsdqwaLfnQSUnCKqh2INnfhRC4D7ieJCmPeGlqn37l3o22xizlmq67aNGk3rA4xLihFbCkJf/KuL1cCDYDyWVJRBQQyaPIRs3asUC8qST8ZtryRafFN582x1x24nAJrbGEiUiYD9VgVs5qGPPhjdAK7ldJBPmbD7Xjs81wYt7Ils75ZEAoonFQnhgHw5h4jehlCEJVyq5MVAOQfCSuHPf0mwN+a2239Ws+Q9LCnEZPKG0/1GO+/sAmGxqCNfnDFy+1bt186xSXSaRqxekLPOWYUkKFUK5nMuM2A8l1pRQOS1hCx5MMlEkaKssynvgs4SMc4C87scU0jLGerGs95kCzas74kjyROZNZ1oxHGcuX+vHZhHnO2ueAlA9Gr1Tk8zzND8n1MlykFOomi/w0J6Hj5Y5YdqhvLN3x8r0BiIBForXJu9aHNx30flZWYkvqiNIfpRFKoYL7nGeAa/lvLl1qk7KitllWchN3nM0GIEGwCFEpI18SFim519ZdlHElhDne0+9VHhqvVZIa0ayb8SYwFkoo2kSQrfjZfIMqKtKVVRkbqhxPEK9fNct+5XtQei6R2rBDMWNLgkEhVXdY6sTYssERSuFa6/L5lJwJqFqB1XxZi1fCqyYLlU+U0Tc+oCscZZPcKjnZBkVxIpsb5QqsxzRZgfFm9XOQKI73Fhw7L4fQASX94XSyx1dnG929JhidwMMQ+C+WmFjM+xnl5QpJOcY6TALee8+Zb5VEl8lcRkgsVijHw+Wz8sNq+HJFmoH87WUn2HmZ60ops14GIWMYN1COCSHJ17KFysvTO53JZl4vR1Q5nmAms6t9rNYucVOiKBeSFYREmhtefYItNH9Cy8hKDZPdctzgN0foGxiK11tV8qPe8UQkxk3maiCum55KLSb28rhfRXm5oJrZBDPZFabR4ibNFFodWrKhqRUdphizb052y7Eb70jpLCV/1pMewrMHCXl6GFSUycXk363zGOJSKeGjjIw7zlW720ySqnwSmegvB8sScceQjU6LyugRi7EewrMH5ThrCsjDpShKelQzm0BwQSuJTKkZthzncw3EZDHTYWNKuMXyQPzxZIUSQjwHrbOaH1BKjUP4y8FrMVEw17VChKJMLlRiTiCajDeSJsdyXCgNQFyCSiFduU6e3fCySU7DOk7NY7Wk5QfMO1oJq+U4u2jyk6JMLlQ5nkA0DnAkU51QCkIRCg236QEKySmtjXlfiD3TtE6pftndc75b89VyrCiKEh3dwSYQteaMxO1gVIjdA8VyTF3Z1XMbX5ZjrCEV+Rd3/HKch4qiKGNFs2YmELXmjMRtOZzLdreZgjAKap5iMVYlUcmXihXlaslXFEWJjCrHE4hac0YirZYhlx29MkVtealZOashoeqGokwkmtugKIoyOjSsYgJR5Ti5ckzVMxK7CjEBipayiqIoiqIUJmo5nkA0rGIk86fVmOUz68yMukpN6lIURVEUJeeocjxBlJRoA5AwaIpy81Unm6FYLOdjoiiKoiiKUjBhFZ/73OfMOeecY6qrq01jY6MpdCpLNXs8GWUl2rRAURRFUZSJoWCU4/7+fvPmN7/ZXHvttWYyoDWOk0NmvSYRKYqiKIoyERRMWMWnP/1p+9/vfe97ZjKgyXipQytoeasoiqIoipJrCkY5Hgt9fX32S+js7LT/HRoasl+5gM+JxWKG/7lUlBbl7BoKDSJOyoq9Z5evyLjm8zUqo0fHdXKi4zo50XGdfAxleW+N+r6TWjm++eab4xZnlwMHDpje3t6cXAMD0d/TZQaLBkyRGbaG9nb2mbbB7pxcQ6Fx9Fi/KSsuNrFj+Ts9GdcjR47YRVxM1w9lUqDjOjnRcZ2c6LhOPoayvLd2dXVFet2Eah833nij+cIXvpDyNevWrTPLli0b0/t//OMfNx/96EcTLMetra1m+vTppr6+3uRqoLcf6jF9RTWmiOK9Pi3NjabRaXihDFPR028qykryOvSEcWU8mUuqHE8edFwnJzqukxMd18nHUJb31srKyvxXjm+44QZz9dVXp3zNwoULx/z+FRUV9isIDzyXCg0DLV9CVUWZKlVJqCgvNVVlJQnPKx/h+nI9l5Tso+M6OdFxnZzouE4+irK4t0Z9zwlVjjkZ8PVyA51PG4AkpxAUY0VRFEVRJif5G9QZYMeOHaa9vd3+d3Bw0Dz33HP254sXLza1tbWmkCgv5USkyl8yVDFWFEVRFGWiKBjl+FOf+pS57bbb4t+vXr3a/vf+++83F154oSkk8jmWVlEURVEU5eVMwQRLUt/YlkQLfBWaYgzaHU9RFEVRFCU/KRjleDKh3fEURVEURVHyE1WOJwANq1AURVEURclPVDmeACpo/6YoiqIoiqLkHaqlTQBqOVYURVEURclPVDmeADQhT1EURVEUJT9R5TjHlBQX2TrHiqIoiqIoSv6hWlqO0c54iqIoiqIo+YsqxzmmQhuAKIqiKIqi5C2qHOcYrXGsKIqiKIqSv6hynGO0UoWiKIqiKEr+ospxjlHlWFEURVEUJX9R5TjHVGqlCkVRFEVRlLxFleMco5ZjRVEURVGU/EWV4xyjyrGiKIqiKEr+ospxDikrLbZNQBRFURRFUZT8RJXjHKLxxoqiKIqiKPmNKsc5REMqFEVRFEVR8htVjnOIKseKoiiKoij5jSrHOUS74ymKoiiKouQ3qhznELUcK4qiKIqi5DeqHOeQytKSXH6coiiKoiiKMkpUOc4hFWX6uBVFURRFUfIZ1dZyRFGRMRXaOlpRFEVRFCWvUeU4R1SUlpgiNGRFURRFURQlb1HlOEdopQpFURRFUZT8R5XjHKHKsaIoiqIoSv6jynGOUOVYURRFURQl/1HlOIcxx4qiKIqiKEp+o8pxjtAax4qiKIqiKPmPKsc5QmscK4qiKIqi5D+qHOcIbR2tKIqiKIqS/6hynIuHXFxkykr0USuKoiiKouQ7qrHlgPISbf6hKIqiKIpSCKhynAPK1WqsKIqiKIpSEKhynAPKSvUxK4qiKIqiFAIFo7Vt27bNvO997zMLFiwwVVVVZtGiReamm24y/f39Jt9Ry7GiKIqiKEphUGoKhPXr15uhoSHzrW99yyxevNi8+OKL5v3vf7/p7u42X/rSl0w+o8l4iqIoiqIohUHBKMeXX365/RIWLlxoXnrpJfONb3wj75VjqlUoiqIoiqIo+U/BKMdhHDlyxEydOjXp7/v6+uyX0NnZaf+LBZqvXMDnxGKxnH2ekht0XCcnOq6TEx3XyYmO6+RjKMs6U9T3LVjleNOmTeZrX/taSqvxzTffbD796U+P+PmBAwdMb2+vyQUMBEo8g11cXDAh3koadFwnJzqukxMd18mJjuvkYyjLOlNXV1ek1xXFuIIJ5MYbbzRf+MIXUr5m3bp1ZtmyZfHvd+/ebS644AJz4YUXmv/8z/8cleW4tbXVHD582NTX15tcDTTK+PTp01U5nkTouE5OdFwnJzqukxMd18nHUJZ1JvTAKVOmWAU8lR444ZbjG264wVx99dUpX0N8sbBnzx5z0UUXmXPOOcd8+9vfTvl3FRUV9isIDzyXVtyioqKcf6aSfXRcJyc6rpMTHdfJiY7r5KMoizpT1PeccOWY0wFfUcBijGJ82mmnmVtvvVWVTUVRFEVRFCWjTLhyHBUUY8Io5s2bZ+OMMbsLLS0tE3ptiqIoiqIoyuSgYJTje+65xybh8TVnzpyE301w2LSiKIqiKIoySSgY5Zi45HSxyekQJVpKuuUquJzsyMrKSg0DmUTouE5OdFwnJzqukxMd18nHUJZ1JtH/0hlVC0Y5zmQJDypWKIqiKIqiKC8/urq6TENDQ/6Wcsv1iYRqF3V1dTYbMhdI+bidO3fmrHyckn10XCcnOq6TEx3XyYmO6+SjM8s6EyovivGsWbNSWqZfVpZjHkQwXjlXMMiqHE8+dFwnJzqukxMd18mJjuvkoz6LOlMqi7GghXcVRVEURVEUxUeVY0VRFEVRFEXxUeU4y9Ch76abbgrt1KcULjqukxMd18mJjuvkRMd18lGRJzrTyyohT1EURVEURVFSoZZjRVEURVEURfFR5VhRFEVRFEVRfFQ5VhRFURRFURQfVY4VRVEURVEUxUeV4yzz9a9/3cyfP9/2CT/zzDPNE088ke2PVDLEzTffbE4//XTbUbG5udm88Y1vNC+99FLCa3p7e811111nmpqaTG1trXnTm95k9u/fr2NQQNxyyy22Y+aHP/zh+M90XAuT3bt3m3e+8512PVZVVZmTTjrJPPXUU/Hfk3/+qU99ysycOdP+/pJLLjEbN26c0GtWUjM4OGg++clPmgULFtgxW7RokfnsZz9rx1LQcc1/HnroIfP617/edqZD3v7sZz9L+H2UMWxvbzfveMc7bHOQxsZG8773vc8cPXo0K9erynEW+fGPf2w++tGP2rIkzzzzjFm1apW57LLLTFtbWzY/VskQDz74oFV8H3vsMXPPPfeYgYEBc+mll5ru7u74az7ykY+YO++80/zkJz+xr6c9+VVXXaVjUCA8+eST5lvf+pY5+eSTE36u41p4HD582Jx77rmmrKzM3H333Wbt2rXmX/7lX8yUKVPir/nnf/5n89WvftV885vfNI8//ripqamxMpnDkJKffOELXzDf+MY3zL//+7+bdevW2e8Zx6997Wvx1+i45j/d3d1WB8JgGEaUMUQxXrNmjd2P77rrLqtwX3PNNdm5YEq5KdnhjDPOiF133XXx7wcHB2OzZs2K3XzzzfrIC5C2tjZMFbEHH3zQft/R0RErKyuL/eQnP4m/Zt26dfY1jz766AReqRKFrq6u2JIlS2L33HNP7IILLohdf/319uc6roXJ3/3d38Ve+cpXJv390NBQrKWlJfbFL34x/jPGuqKiIvbDH/4wR1epjJYrrrgi9t73vjfhZ1dddVXsHe94h/23jmvhYYyJ3XHHHfHvo4zh2rVr7d89+eST8dfcfffdsaKiotju3bszfo1qOc4S/f395umnn7auAaG4uNh+/+ijj2brY5UscuTIEfvfqVOn2v8yvliT3TFetmyZmTt3ro5xAYBX4IorrkgYP9BxLUx+8YtfmFe84hXmzW9+sw2DWr16tfnOd74T//3WrVvNvn37Esa7oaHBhrupTM5fzjnnHHPvvfeaDRs22O+ff/558/DDD5vXvOY19nsd18Jna4S1yX8JpWCNC7wevQpLc6Ypzfg7KpaDBw/aWKkZM2YkPBG+X79+vT6lAmNoaMjGpOK2Xblypf0Zi7m8vNwu2OAY8zslf/nRj35kQ50Iqwii41qYbNmyxbrfCWX7xCc+Ycf2Qx/6kF2j7373u+NrMkwm63rNX2688UbT2dlpDQ8lJSV2X/3c5z5nXeyg41r47IuwNvkvh16X0tJSa6zKxvpV5VhRIloZX3zxRWuxUAqbnTt3muuvv97GrZEoq0yeAyxWpc9//vP2eyzHrFliGFGOlcLkf//3f80PfvAD8z//8z/mxBNPNM8995w1VJDYpeOqZAsNq8gS06ZNs6fcYOUCvm9pacnWxypZ4IMf/KAN/r///vvNnDlz4j9nHAmf6ejoSHi9jnF+Q9gESbGnnnqqtTzwRTIlySD8G2uFjmvhQZb7ihUrEn62fPlys2PHDvtvkbsqkwuLv/3bv7XW47e97W22+sif//mf24RZqgmBjmvh0xJhbfLfYDGD48eP2woW2dCpVDnOErjyTjvtNBsr5Vo2+P7ss8/O1scqGYS8ARTjO+64w9x33322lJAL40tmvDvGlHpjM9Yxzl8uvvhi88ILL1gLlHxhccRNK//WcS08CHkKllokTnXevHn236xfNlF3veKuJ15R12v+0tPTY+NKXTA8sZ+CjmvhsyDC2uS/GKIwbgjsy8wDYpMzTsZT/JQ4P/rRj2y25fe+9z2baXnNNdfEGhsbY/v27dOnVABce+21sYaGhtgDDzwQ27t3b/yrp6cn/poPfOADsblz58buu+++2FNPPRU7++yz7ZdSWLjVKkDHtfB44oknYqWlpbHPfe5zsY0bN8Z+8IMfxKqrq2Pf//7346+55ZZbrAz++c9/HvvjH/8Ye8Mb3hBbsGBB7NixYxN67Upy3v3ud8dmz54du+uuu2Jbt26N3X777bFp06bFPvaxj8Vfo+NaGNWBnn32WfuF6vnlL3/Z/nv79u2Rx/Dyyy+PrV69Ovb444/HHn74YVtt6O1vf3tWrleV4yzzta99zSpP5eXltrTbY489lu2PVDIECzjs69Zbb42/hoX7V3/1V7EpU6bYjfjKK6+0CrRS2Mqxjmthcuedd8ZWrlxpjRLLli2Lffvb3074PSWjPvnJT8ZmzJhhX3PxxRfHXnrppQm7XiU9nZ2ddm2yj1ZWVsYWLlwY+/u///tYX19f/DU6rvnP/fffH7qfcviJOoaHDh2yynBtbW2svr4+9p73vMcq3dmgiP/LvD1aURRFURRFUQoPjTlWFEVRFEVRFB9VjhVFURRFURTFR5VjRVEURVEURfFR5VhRFEVRFEVRfFQ5VhRFURRFURQfVY4VRVEURVEUxUeVY0VRFEVRFEXxUeVYURRFURRFUXxUOVYURZkEPPDAA6aoqMh0dHRM9KUoiqIUNNohT1EUpQC58MILzSmnnGK+8pWv2O/7+/tNe3u7mTFjhlWSFUVRlLFROsa/UxRFUfKI8vJy09LSMtGXoSiKUvBoWIWiKEqBcfXVV5sHH3zQ/Nu//Zu1EvP1ve99LyGsgu8bGxvNXXfdZU444QRTXV1t/vRP/9T09PSY2267zcyfP99MmTLFfOhDHzKDg4Px9+7r6zN/8zd/Y2bPnm1qamrMmWeeaUM2FEVRXi6o5VhRFKXAQCnesGGDWblypfnMZz5jf7ZmzZoRr0MR/upXv2p+9KMfma6uLnPVVVeZK6+80irNv/rVr8yWLVvMm970JnPuueeat771rfZvPvjBD5q1a9fav5k1a5a54447zOWXX25eeOEFs2TJkpzfq6IoSq5R5VhRFKXAaGhosGEUWIMllGL9+vUjXjcwMGC+8Y1vmEWLFtnvsRz/93//t9m/f7+pra01K1asMBdddJG5//77rXK8Y8cOc+utt9r/ohgDVuRf//rX9uef//znc3yniqIouUeVY0VRlEkKyrMoxkCyHuEUKMbuz9ra2uy/sQ4TYrF06dKE9yHUoqmpKYdXriiKMnGocqwoijJJKSsrS/iemOSwnw0NDdl/Hz161JSUlJinn37a/tfFVagVRVEmM6ocK4qiFCCEVbiJdJlg9erV9j2xJJ933nkZfW9FUZRCQatVKIqiFCCERzz++ONm27Zt5uDBg3Hr73ggnOId73iHede73mVuv/12s3XrVvPEE0+Ym2++2fzyl7/MyHUriqLkO6ocK4qiFCAkyhH6QFLd9OnTbRJdJiDxDuX4hhtusCXg3vjGN5onn3zSzJ07NyPvryiKku9ohzxFURRFURRF8VHLsaIoiqIoiqL4qHKsKIqiKIqiKD6qHCuKoiiKoiiKjyrHiqIoiqIoiuKjyrGiKIqiKIqi+KhyrCiKoiiKoig+qhwriqIoiqIoio8qx4qiKIqiKIrio8qxoiiKoiiKoviocqwoiqIoiqIoPqocK4qiKIqiKIrx+P/H7qZYqcR5EwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Rerun the filter at the MLE and read the filtered state distributions.\n", + "with Filter(filter_config=KFConfig(filter_source=\"cuthbert\")):\n", + " result = dsx.condition(\n", + " \"f\",\n", + " make_dynamics(rho_history[-1]),\n", + " obs_times=obs_times,\n", + " obs_values=obs_values,\n", + " ctrl_times=ctrl_times,\n", + " ctrl_values=ctrl_values,\n", + " )\n", + "\n", + "filtered_means = jnp.stack([d.mean for d in result.dists]) # (T, state_dim)\n", + "filtered_covs = jnp.stack([d.covariance_matrix for d in result.dists]) # (T, state_dim, state_dim)\n", + "filtered_stds = jnp.sqrt(jnp.diagonal(filtered_covs, axis1=1, axis2=2)) # (T, state_dim)\n", + "\n", + "obs_times_np = jnp.asarray(obs_times)\n", + "obs_values_np = jnp.asarray(obs_values).squeeze() # (T,)\n", + "\n", + "\n", + "def plot_latent_recovery(mean_states, lo, hi, title, obs_times, obs_values, state_dim=2):\n", + " \"\"\"mean/lo/hi: (T, state_dim). One figure, one subplot per state component.\"\"\"\n", + " n_comp = state_dim\n", + " fig, axes = plt.subplots(\n", + " n_comp, 1, figsize=(7, 2.5 * n_comp), sharex=True, constrained_layout=True\n", + " )\n", + " if n_comp == 1:\n", + " axes = [axes]\n", + " for i in range(n_comp):\n", + " ax = axes[i]\n", + " ax.fill_between(obs_times_np, lo[:, i], hi[:, i], alpha=0.3)\n", + " ax.plot(obs_times_np, mean_states[:, i], label=f\"$x_{i}$ (mean)\")\n", + " if i == 0: # observed component: overlay data\n", + " ax.scatter(\n", + " obs_times_np,\n", + " obs_values_np,\n", + " s=8,\n", + " alpha=0.7,\n", + " color=\"k\",\n", + " label=\"observations\",\n", + " zorder=3,\n", + " )\n", + " ax.set_ylabel(f\"$x_{i}$\")\n", + " ax.legend(loc=\"upper right\", fontsize=8)\n", + " ax.grid(True, alpha=0.3)\n", + " axes[-1].set_xlabel(\"time\")\n", + " fig.suptitle(title)\n", + " plt.show()\n", + "\n", + "\n", + "plot_latent_recovery(\n", + " filtered_means,\n", + " filtered_means - 1.96 * filtered_stds,\n", + " filtered_means + 1.96 * filtered_stds,\n", + " r\"Latent state recovery --- filtered states at the MLE $\\hat{\\rho}$\",\n", + " obs_times_np,\n", + " obs_values_np,\n", + " state_dim=state_dim,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "232aa1fc", + "metadata": {}, + "source": [ + "The MLE workflow gives a point estimate of the parameters with state uncertainty from the filter, entirely without NumPyro. For full posterior inference over parameters --- and the comparison with joint state + parameter inference --- see the original NumPyro-based notebooks: [Part 4 (NUTS)](04_filtering_nuts_pseudomarginal.ipynb) and [Part 5 (SVI)](05_svi.ipynb)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv (3.12.11)", + "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.12.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dynestyx/__init__.py b/dynestyx/__init__.py index fc2d5f78..a04a54cf 100644 --- a/dynestyx/__init__.py +++ b/dynestyx/__init__.py @@ -5,7 +5,7 @@ __version__ = version("dynestyx") from dynestyx.discretizers import Discretizer, euler_maruyama -from dynestyx.handlers import plate, sample +from dynestyx.handlers import condition, plate, sample from dynestyx.inference.filters import Filter from dynestyx.inference.smoothers import Smoother from dynestyx.models import ( @@ -35,6 +35,7 @@ SDESimulator, Simulator, ) +from dynestyx.types import ConditionedResult from dynestyx.utils import flatten_draws __all__ = [ @@ -59,6 +60,8 @@ "Filter", "Smoother", "flatten_draws", + "condition", + "ConditionedResult", "plate", "sample", "DiracIdentityObservation", diff --git a/dynestyx/discretizers.py b/dynestyx/discretizers.py index 1f0095fb..a0c12cb7 100644 --- a/dynestyx/discretizers.py +++ b/dynestyx/discretizers.py @@ -3,7 +3,7 @@ from effectful.ops.syntax import ObjectInterpretation, implements from jaxtyping import Array, Real -from dynestyx.handlers import HandlesSelf, _sample_intp +from dynestyx.handlers import HandlesSelf, _condition_intp from dynestyx.models import ( DynamicalModel, GaussianStateEvolution, @@ -152,7 +152,7 @@ def __init__(self, discretize=euler_maruyama): super().__init__() self.discretize = discretize - @implements(_sample_intp) + @implements(_condition_intp) def _sample_ds( self, name: str, diff --git a/dynestyx/handlers.py b/dynestyx/handlers.py index e72d5c82..78976c69 100644 --- a/dynestyx/handlers.py +++ b/dynestyx/handlers.py @@ -1,4 +1,4 @@ -"""Contains the `sample` primitive and `effectful` utilities for `dynestyx`.""" +"""Contains the `sample` and `infer` primitives and `effectful` utilities for `dynestyx`.""" from typing import TypeVar @@ -11,7 +11,7 @@ from dynestyx.models import ( DynamicalModel, ) -from dynestyx.types import FunctionOfTime +from dynestyx.types import ConditionedResult, FunctionOfTime from dynestyx.utils import ( _get_dynamics_with_t0, _validate_control_dim, @@ -22,7 +22,7 @@ T = TypeVar("T") -def sample( +def _validate_and_prepare( name: str, dynamics: DynamicalModel, *, @@ -35,36 +35,8 @@ def sample( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, predict_times: Real[Array, "*predict_time_plate predict_time"] | None = None, - **kwargs, -) -> FunctionOfTime: - """ - Samples from a dynamical model. This is the main primitive of dynestyx. - - The `sample` primitive is meant to mimic the `numpyro.sample` primitive in usage, - but using a `DynamicalModel` instead of a `Distribution`. - - The `sample` method calls `_sample_intp`, which is defined as a `defop` in `effectful`. - This is where any real "work" is done, after input validation. - - Shape note: - Inside ``dsx.plate``, observation arrays use leading plate axes followed - by time and event axes, e.g. ``(N, T, obs_dim)``. Model parameters follow - the same leading-plate, trailing-event convention. See :class:`plate` - for the full plated-shape contract. - - Parameters: - name: Name of the sample site. - dynamics: Dynamical model to sample from. - obs_times: Times at which to sample the observations. - obs_values: Values of the observations at the given times. - ctrl_times: Times at which to sample the controls. - ctrl_values: Values of the controls at the given times. - predict_times: Times at which to predict the observations. - **kwargs: Additional keyword arguments. - - Returns: - FunctionOfTime: A function of time that samples from the dynamical model. - """ +) -> DynamicalModel: + """Validate inputs and return dynamics with t0 resolved.""" # Rule: obs_times must be accompanied with obs_values, which should be the same length. if obs_times is None and predict_times is None: raise ValueError("At least one of obs_times or predict_times must be provided") @@ -106,10 +78,50 @@ def sample( _validate_control_dim(dynamics, ctrl_values) # Initial dynamics may not have t0, which is then inferred from obs_times - dynamics_with_t0 = _get_dynamics_with_t0(dynamics, obs_times, predict_times) + return _get_dynamics_with_t0(dynamics, obs_times, predict_times) + + +def condition( + name: str, + dynamics: DynamicalModel, + *, + obs_times: Real[Array, "*obs_time_plate obs_time"] | None = None, + obs_values: Real[Array, "*obs_value_plate obs_time observation_dim"] + | Real[Array, "*obs_value_plate obs_time"] + | None = None, + ctrl_times: Real[Array, "*ctrl_time_plate ctrl_time"] | None = None, + ctrl_values: Real[Array, "*ctrl_value_plate ctrl_time control_dim"] + | Real[Array, "*ctrl_value_plate ctrl_time"] + | None = None, + predict_times: Real[Array, "*predict_time_plate predict_time"] | None = None, + **kwargs, +): + """Run inference on a dynamical model without registering numpyro sites. + + This is the numpyro-free entry point. When a Filter or Smoother handler + is active, returns a ConditionedResult dataclass with marginal_loglik, states, etc. + + Parameters: + name: Name of the inference site. + dynamics: Dynamical model to infer. + obs_times: Times at which observations are available. + obs_values: Values of the observations at the given times. + ctrl_times: Times at which controls are applied. + ctrl_values: Values of the controls at the given times. + predict_times: Times at which to predict. + **kwargs: Additional keyword arguments. + """ + dynamics_with_t0 = _validate_and_prepare( + name, + dynamics, + obs_times=obs_times, + obs_values=obs_values, + ctrl_times=ctrl_times, + ctrl_values=ctrl_values, + predict_times=predict_times, + ) - # Pass to interpreted version of `sample` for inference. - return _sample_intp( + return _condition_intp( name, dynamics_with_t0, obs_times=obs_times, @@ -121,8 +133,68 @@ def sample( ) +def sample( + name: str, + dynamics: DynamicalModel, + *, + obs_times: Real[Array, "*obs_time_plate obs_time"] | None = None, + obs_values: Real[Array, "*obs_value_plate obs_time observation_dim"] + | Real[Array, "*obs_value_plate obs_time"] + | None = None, + ctrl_times: Real[Array, "*ctrl_time_plate ctrl_time"] | None = None, + ctrl_values: Real[Array, "*ctrl_value_plate ctrl_time control_dim"] + | Real[Array, "*ctrl_value_plate ctrl_time"] + | None = None, + predict_times: Real[Array, "*predict_time_plate predict_time"] | None = None, + **kwargs, +): + """ + Samples from a dynamical model. This is the main primitive of dynestyx. + + The ``sample`` primitive is meant to mimic the ``numpyro.sample`` primitive + in usage, but using a ``DynamicalModel`` instead of a ``Distribution``. + + Internally, ``sample`` calls ``dsx.condition(...)`` and then registers the + results as numpyro sites (``numpyro.factor``, ``numpyro.deterministic``). + + Shape note: + Inside ``dsx.plate``, observation arrays use leading plate axes followed + by time and event axes, e.g. ``(N, T, obs_dim)``. Model parameters follow + the same leading-plate, trailing-event convention. See :class:`plate` + for the full plated-shape contract. + + Parameters: + name: Name of the sample site. + dynamics: Dynamical model to sample from. + obs_times: Times at which to sample the observations. + obs_values: Values of the observations at the given times. + ctrl_times: Times at which to sample the controls. + ctrl_values: Values of the controls at the given times. + predict_times: Times at which to predict the observations. + **kwargs: Additional keyword arguments. + """ + result = condition( + name, + dynamics, + obs_times=obs_times, + obs_values=obs_values, + ctrl_times=ctrl_times, + ctrl_values=ctrl_values, + predict_times=predict_times, + **kwargs, + ) + + if ( + isinstance(result, ConditionedResult) + and result._register_numpyro_sites is not None + ): + result._register_numpyro_sites(name) + + return result + + @defop -def _sample_intp( +def _condition_intp( name: str, dynamics: DynamicalModel, *, @@ -347,7 +419,7 @@ def __exit__(self, exc_type, exc, tb): self._cm.__exit__(exc_type, exc, tb) return self._numpyro_plate.__exit__(exc_type, exc, tb) - @implements(_sample_intp) + @implements(_condition_intp) def _sample_ds( self, name, dynamics, *, plate_shapes=(), **kwargs ) -> FunctionOfTime: diff --git a/dynestyx/inference/filters.py b/dynestyx/inference/filters.py index 5e8dc370..29c140f7 100644 --- a/dynestyx/inference/filters.py +++ b/dynestyx/inference/filters.py @@ -1,5 +1,6 @@ import dataclasses import math +from abc import ABC, abstractmethod from typing import cast import equinox as eqx @@ -11,7 +12,7 @@ from effectful.ops.syntax import ObjectInterpretation, implements from jaxtyping import Array, PRNGKeyArray, Real -from dynestyx.handlers import HandlesSelf, _sample_intp +from dynestyx.handlers import HandlesSelf, _condition_intp from dynestyx.inference.checkers import ( _validate_batched_plate_alignment, _validate_missing_observation_support, @@ -57,22 +58,26 @@ from dynestyx.inference.integrations.cuthbert.discrete import ( run_discrete_filter as run_cuthbert_discrete, ) +from dynestyx.inference.numpyro_sites import ( + register_filter_sites, + register_hmm_filter_sites, +) from dynestyx.inference.plate_utils import ( _array_plate_axis, _make_plate_in_axes, _slice_dist_for_plate_member, ) from dynestyx.models import DynamicalModel -from dynestyx.types import FunctionOfTime +from dynestyx.types import ConditionedResult, FunctionOfTime from dynestyx.utils import _dist_has_plate_batch_dims type SSMType = ContDiscreteNonlinearGaussianSSM | ContDiscreteNonlinearSSM -class BaseLogFactorAdder(ObjectInterpretation, HandlesSelf): +class BaseLogFactorAdder(ObjectInterpretation, HandlesSelf, ABC): """Base for filter handlers.""" - @implements(_sample_intp) + @implements(_condition_intp) def _sample_ds( self, name: str, @@ -102,8 +107,9 @@ def _sample_ds( **kwargs, ) - # Filter consumes obs_times and obs_values, so they are passed forward as None - return fwd( + # Filter consumes obs_times and obs_values, so they are passed forward as None. + # fwd() lets handlers above (e.g. Simulator) use filtered_dists for rollout. + fwd( name, dynamics, plate_shapes=plate_shapes, @@ -116,6 +122,9 @@ def _sample_ds( **kwargs, ) + return self._build_infer_result(name, filtered_dists) + + @abstractmethod def _add_log_factors( self, name: str, @@ -131,9 +140,12 @@ def _add_log_factors( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, **kwargs, - ) -> list[numpyro.distributions.Distribution] | None: - # Inheritors should implement this method. - raise NotImplementedError() + ) -> list[numpyro.distributions.Distribution] | None: ... + + @abstractmethod + def _build_infer_result( + self, name: str, filtered_dists: list | None + ) -> ConditionedResult: ... def _default_filter_config(dynamics: DynamicalModel): @@ -199,6 +211,13 @@ class Filter(BaseLogFactorAdder): """ filter_config: BaseFilterConfig | None = None + marginal_loglik: jax.Array | None = dataclasses.field( + default=None, repr=False, init=False + ) + filtered_states: object = dataclasses.field(default=None, repr=False, init=False) + _filter_config_used: BaseFilterConfig | None = dataclasses.field( + default=None, repr=False, init=False + ) def _add_log_factors( self, @@ -216,17 +235,10 @@ def _add_log_factors( | None = None, **kwargs, ) -> list[numpyro.distributions.Distribution] | None: - """ - Add the marginal log likelihood as a numpyro factor. - - Args: - name: Name of the factor. - dynamics: Dynamical model to filter. - plate_shapes: Tuple of plate sizes from enclosing dsx.plate contexts. - obs_times: Observation times. - obs_values: Observed values. - ctrl_times: Control times (optional). - ctrl_values: Control values (optional). + """Run filtering and store the marginal log-likelihood. + + Pure computation — no numpyro side effects. Site registration + happens via the callback in ConditionedResult when called through dsx.sample. """ if obs_times is None or obs_values is None: raise ValueError("obs_times and obs_values are required for filtering.") @@ -243,7 +255,16 @@ def _add_log_factors( mode="filter", ) - key = numpyro.prng_key() if config.crn_seed is None else config.crn_seed + # Resolve PRNG key: use explicit seed from config, fall back to numpyro + # context (inside a seeded model), or None (deterministic filters don't need one). + if config.crn_seed is not None: + key = config.crn_seed + else: + import warnings # noqa: PLC0415 + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + key = numpyro.prng_key() # returns None outside seed handler if plate_shapes: return self._add_log_factors_batched( @@ -267,7 +288,32 @@ def _add_log_factors( "inside `Filter()`. " f"Got {type(config).__name__}; valid continuous-time config types: {valid}." ) - return _filter_continuous_time( + marginal_loglik, states, filtered_dists = _filter_continuous_time( + name, + dynamics, + config, # type: ignore[arg-type] + key=key, + obs_times=obs_times, + obs_values=obs_values, + ctrl_times=ctrl_times, + ctrl_values=ctrl_values, + **kwargs, + ) + elif isinstance(config, HMMConfigs): + loglik, log_filt_seq, filtered_dists = _filter_hmm( + name, + dynamics, + cast(HMMConfig, config), + obs_times=obs_times, + obs_values=obs_values, + ctrl_times=ctrl_times, + ctrl_values=ctrl_values, + **kwargs, + ) + marginal_loglik = loglik + states = log_filt_seq + elif isinstance(config, DiscreteTimeConfigs): + marginal_loglik, states, filtered_dists = _filter_discrete_time( name, dynamics, config, # type: ignore[arg-type] @@ -279,35 +325,52 @@ def _add_log_factors( **kwargs, ) else: - if isinstance(config, HMMConfigs): - return _filter_hmm( - name, - dynamics, + valid = [c.__name__ for c in HMMConfigs + DiscreteTimeConfigs] + raise ValueError( + f"Invalid filter config: {type(config).__name__}. " + f"Valid config types: {valid}" + ) + + self.marginal_loglik = marginal_loglik + self.filtered_states = states + self._filter_config_used = config + + return filtered_dists + + def _build_infer_result( + self, name: str, filtered_dists: list | None + ) -> ConditionedResult: + """Construct ConditionedResult with a deferred numpyro registration callback.""" + marginal_loglik = self.marginal_loglik + states = self.filtered_states + config = self._filter_config_used + _is_batched = ( + isinstance(marginal_loglik, jax.Array) and marginal_loglik.ndim > 0 + ) + + def _register(site_name: str) -> None: + if marginal_loglik is None or config is None: + return + if _is_batched: + # TODO: support per-field recording for batched (plate) states + numpyro.factor(f"{site_name}_marginal_log_likelihood", marginal_loglik) + numpyro.deterministic(f"{site_name}_marginal_loglik", marginal_loglik) + elif isinstance(config, HMMConfigs): + register_hmm_filter_sites( + site_name, + marginal_loglik, + cast(jax.Array, states), cast(HMMConfig, config), - obs_times=obs_times, - obs_values=obs_values, - ctrl_times=ctrl_times, - ctrl_values=ctrl_values, - **kwargs, - ) - elif isinstance(config, DiscreteTimeConfigs): - return _filter_discrete_time( - name, - dynamics, - config, # type: ignore[arg-type] - key=key, - obs_times=obs_times, - obs_values=obs_values, - ctrl_times=ctrl_times, - ctrl_values=ctrl_values, - **kwargs, ) else: - valid = [c.__name__ for c in HMMConfigs + DiscreteTimeConfigs] - raise ValueError( - f"Invalid filter config: {type(config).__name__}. " - f"Valid config types: {valid}" - ) + register_filter_sites(site_name, marginal_loglik, states, config) + + return ConditionedResult( + marginal_loglik=marginal_loglik, + states=states, + dists=filtered_dists, + _register_numpyro_sites=_register, + ) def _add_log_factors_batched( self, @@ -495,8 +558,9 @@ def compute_output_member(dyn, ot, ov, ct, cv, k, *idxs): else: raise ValueError(f"Unsupported batched output kind: {output_kind}") - numpyro.factor(f"{name}_marginal_log_likelihood", marginal_logliks) - numpyro.deterministic(f"{name}_marginal_loglik", marginal_logliks) + self.marginal_loglik = marginal_logliks + self.filtered_states = outputs + self._filter_config_used = config if output_kind == "continuous": particle_mode = isinstance(config, ContinuousTimeDPFConfig) @@ -550,7 +614,7 @@ def _filter_discrete_time( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, **kwargs, -) -> list[numpyro.distributions.Distribution]: +) -> tuple[jax.Array | None, object | None, list[numpyro.distributions.Distribution]]: """Discrete-time marginal likelihood via cuthbert or cd-dynamax. Filter type inferred from config class: KFConfig, EKFConfig, UKFConfig @@ -607,7 +671,7 @@ def _filter_continuous_time( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, **kwargs, -) -> list[numpyro.distributions.Distribution]: +) -> tuple[jax.Array, object, list[numpyro.distributions.Distribution]]: """Continuous-time marginal likelihood via CD-Dynamax. Supports: EnKF, DPF, EKF, UKF (inferred from config type). diff --git a/dynestyx/inference/hmm_filters.py b/dynestyx/inference/hmm_filters.py index 4b0ae8f4..31e24876 100644 --- a/dynestyx/inference/hmm_filters.py +++ b/dynestyx/inference/hmm_filters.py @@ -4,7 +4,6 @@ import jax import jax.numpy as jnp -import numpyro import numpyro.distributions as dist from jax import lax from jax.scipy.special import logsumexp @@ -13,7 +12,6 @@ from dynestyx.inference.filter_configs import HMMConfig from dynestyx.models import DynamicalModel from dynestyx.models.core import DiscreteStateTransition -from dynestyx.utils import _should_record_field def enumerate_latent_states(dynamics: DynamicalModel) -> Int[Array, " n_states"]: @@ -222,7 +220,7 @@ def _filter_hmm( ctrl_times: Real[Array, "*ctrl_time_plate ctrl_time"] | None = None, ctrl_values: Real[Array, "*ctrl_value_plate obs_time control_dim"] | None = None, **kwargs, -) -> list[dist.Distribution]: +) -> tuple[jax.Array, Float[Array, "*plate time n_states"], list[dist.Distribution]]: """Exact HMM marginal likelihood via forward filtering. Args: @@ -235,8 +233,12 @@ def _filter_hmm( ctrl_values: Control values (optional). Returns: - List of Categorical distributions p(x_t | y_{1:t}) at each obs time, - for use with Filter + DiscreteTimeSimulator rollout. + tuple of: + - loglik: scalar marginal log-likelihood log p(y_{1:T}). + - log_filt_seq: log filtering probabilities log p(x_t | y_{1:t}), + shape (time, n_states). + - filtered_dists: list of Categorical distributions p(x_t | y_{1:t}) + at each obs time, for use with Filter + DiscreteTimeSimulator rollout. """ loglik, log_filt_seq = compute_hmm_filter( dynamics, @@ -245,29 +247,8 @@ def _filter_hmm( ctrl_values=ctrl_values, ) - numpyro.factor(f"{name}_marginal_log_likelihood", loglik) - numpyro.deterministic(f"{name}_marginal_loglik", loglik) - - record_max_elems = filter_config.record_max_elems - - if _should_record_field( - filter_config.record_log_filtered, log_filt_seq.shape, record_max_elems - ): - numpyro.deterministic( - f"{name}_log_filtered_states", - log_filt_seq, # (T, K) - ) - - if _should_record_field( - filter_config.record_filtered, log_filt_seq.shape, record_max_elems - ): - numpyro.deterministic( - f"{name}_filtered_states", - jnp.exp(log_filt_seq), # (T, K) - ) - - # Return filtered distributions for Filter + DiscreteTimeSimulator rollout - return [ + filtered_dists = [ dist.Categorical(probs=jnp.exp(log_filt_seq[i])) for i in range(log_filt_seq.shape[0]) ] + return loglik, log_filt_seq, filtered_dists diff --git a/dynestyx/inference/integrations/cd_dynamax/continuous_filter.py b/dynestyx/inference/integrations/cd_dynamax/continuous_filter.py index 6fc63b8b..79e49d14 100644 --- a/dynestyx/inference/integrations/cd_dynamax/continuous_filter.py +++ b/dynestyx/inference/integrations/cd_dynamax/continuous_filter.py @@ -2,7 +2,7 @@ import jax import jax.numpy as jnp -import numpyro +import numpyro.distributions as dist from cd_dynamax import ( ContDiscreteLinearGaussianSSM, ContDiscreteNonlinearGaussianSSM, @@ -19,14 +19,12 @@ ContinuousTimeEnKFConfig, ContinuousTimeKFConfig, ContinuousTimeUKFConfig, - _config_to_record_kwargs, ) from dynestyx.inference.integrations.cd_dynamax.utils import ( dsx_to_cd_dynamax, dsx_to_cdlgssm_params, ) from dynestyx.models import DynamicalModel -from dynestyx.utils import _should_record_field type SSMType = ContDiscreteNonlinearGaussianSSM | ContDiscreteNonlinearSSM @@ -111,41 +109,6 @@ def _config_to_cd_dynamax_filter_kwargs( return base -def _add_filter_sites( - name: str, - filter_config: ContinuousTimeFilterConfig, - filtered, -) -> None: - """Add marginal log-likelihood factor and filtered state deterministic sites.""" - record_kwargs = _config_to_record_kwargs(filter_config) - numpyro.factor(f"{name}_marginal_log_likelihood", filtered.marginal_loglik) - numpyro.deterministic(f"{name}_marginal_loglik", filtered.marginal_loglik) - - max_elems = record_kwargs["record_max_elems"] - means_shape = filtered.filtered_means.shape - cov_shape = filtered.filtered_covariances.shape - add_mean = _should_record_field( - record_kwargs["record_filtered_states_mean"], means_shape, max_elems - ) - add_cov = _should_record_field( - record_kwargs["record_filtered_states_cov"], cov_shape, max_elems - ) - add_cov_diag = _should_record_field( - record_kwargs["record_filtered_states_cov_diag"], - (cov_shape[0], cov_shape[1]), - max_elems, - ) - if add_mean: - numpyro.deterministic(f"{name}_filtered_states_mean", filtered.filtered_means) - if add_cov: - numpyro.deterministic( - f"{name}_filtered_states_cov", filtered.filtered_covariances - ) - if add_cov_diag: - diag_cov = jnp.diagonal(filtered.filtered_covariances, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) - - def _run_linear_kf( dynamics: DynamicalModel, obs_times, @@ -240,8 +203,20 @@ def run_continuous_filter( ctrl_times=None, ctrl_values=None, **kwargs, -) -> list[numpyro.distributions.Distribution]: - """Run continuous-time filter via CD-Dynamax.""" +) -> tuple[jax.Array, object, list[dist.Distribution]]: + """Run continuous-time filter via CD-Dynamax. + + Pure computation — no numpyro side-effects. Callers are responsible for + registering numpyro.factor / numpyro.deterministic if needed. + + Returns: + tuple of: + - marginal_loglik: scalar marginal log-likelihood log p(y_{1:T}). + - filtered_posterior: CD-Dynamax posterior object with filtered_means, + filtered_covariances, and marginal_loglik attributes. + - filtered_dists: list of MultivariateNormal distributions p(x_t | y_{1:t}) + at each obs time, for posterior rollout. + """ filtered = compute_continuous_filter( dynamics, filter_config, @@ -252,15 +227,14 @@ def run_continuous_filter( ctrl_values=ctrl_values, ) - _add_filter_sites(name, filter_config, filtered) - - return _posterior_sequence_to_dists( + filtered_dists = _posterior_sequence_to_dists( filtered, means_attr="filtered_means", covariances_attr="filtered_covariances", particle_mode=isinstance(filter_config, ContinuousTimeDPFConfig), missing_message="Filtered means/covariances unexpectedly None for non-DPF config", ) + return filtered.marginal_loglik, filtered, filtered_dists __all__ = [ diff --git a/dynestyx/inference/integrations/cd_dynamax/continuous_smoother.py b/dynestyx/inference/integrations/cd_dynamax/continuous_smoother.py index f3f55f81..97f9760c 100644 --- a/dynestyx/inference/integrations/cd_dynamax/continuous_smoother.py +++ b/dynestyx/inference/integrations/cd_dynamax/continuous_smoother.py @@ -2,7 +2,7 @@ import jax import jax.numpy as jnp -import numpyro +import numpyro.distributions as dist from cd_dynamax import ( ContDiscreteNonlinearGaussianSSM, EKFHyperParams, @@ -19,51 +19,14 @@ from dynestyx.inference.smoother_configs import ( ContinuousTimeEKFSmootherConfig, ContinuousTimeKFSmootherConfig, - _config_to_smoother_record_kwargs, ) from dynestyx.models import DynamicalModel -from dynestyx.utils import _should_record_field ContinuousTimeSmootherConfig = ( ContinuousTimeKFSmootherConfig | ContinuousTimeEKFSmootherConfig ) -def _add_smoother_sites( - name: str, - smoother_config: ContinuousTimeSmootherConfig, - smoothed, -) -> None: - """Add marginal log-likelihood factor and smoothed state deterministic sites.""" - record_kwargs = _config_to_smoother_record_kwargs(smoother_config) - numpyro.factor(f"{name}_marginal_log_likelihood", smoothed.marginal_loglik) - numpyro.deterministic(f"{name}_marginal_loglik", smoothed.marginal_loglik) - - max_elems = record_kwargs["record_max_elems"] - means = smoothed.smoothed_means - covs = smoothed.smoothed_covariances - means_shape = means.shape - cov_shape = covs.shape - add_mean = _should_record_field( - record_kwargs["record_smoothed_states_mean"], means_shape, max_elems - ) - add_cov = _should_record_field( - record_kwargs["record_smoothed_states_cov"], cov_shape, max_elems - ) - add_cov_diag = _should_record_field( - record_kwargs["record_smoothed_states_cov_diag"], - (cov_shape[0], cov_shape[1]), - max_elems, - ) - if add_mean: - numpyro.deterministic(f"{name}_smoothed_states_mean", means) - if add_cov: - numpyro.deterministic(f"{name}_smoothed_states_cov", covs) - if add_cov_diag: - diag_cov = jnp.diagonal(covs, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) - - def compute_continuous_smoother( dynamics: DynamicalModel, smoother_config: ContinuousTimeSmootherConfig, @@ -162,8 +125,20 @@ def run_continuous_smoother( ctrl_times=None, ctrl_values=None, **kwargs, -) -> list[numpyro.distributions.Distribution]: - """Run continuous-time smoother via CD-Dynamax.""" +) -> tuple[jax.Array, object, list[dist.Distribution]]: + """Run continuous-time smoother via CD-Dynamax. + + Pure computation — no numpyro side-effects. Callers are responsible for + registering numpyro.factor / numpyro.deterministic if needed. + + Returns: + tuple of: + - marginal_loglik: scalar marginal log-likelihood log p(y_{1:T}). + - smoothed_posterior: CD-Dynamax posterior object with smoothed_means, + smoothed_covariances, and marginal_loglik attributes. + - smoothed_dists: list of MultivariateNormal distributions p(x_t | y_{1:T}) + at each obs time, for posterior rollout. + """ smoothed = compute_continuous_smoother( dynamics, smoother_config, @@ -174,14 +149,14 @@ def run_continuous_smoother( ctrl_values=ctrl_values, ) - _add_smoother_sites(name, smoother_config, smoothed) - return _posterior_sequence_to_dists( + smoothed_dists = _posterior_sequence_to_dists( smoothed, means_attr="smoothed_means", covariances_attr="smoothed_covariances", particle_mode=False, missing_message="Smoothed means/covariances unexpectedly None.", ) + return smoothed.marginal_loglik, smoothed, smoothed_dists __all__ = ["compute_continuous_smoother", "run_continuous_smoother"] diff --git a/dynestyx/inference/integrations/cd_dynamax/discrete_filter.py b/dynestyx/inference/integrations/cd_dynamax/discrete_filter.py index f1ad4dc7..cfbde871 100644 --- a/dynestyx/inference/integrations/cd_dynamax/discrete_filter.py +++ b/dynestyx/inference/integrations/cd_dynamax/discrete_filter.py @@ -2,10 +2,8 @@ import jax import jax.numpy as jnp -import numpyro import numpyro.distributions as dist from cd_dynamax.dynamax.linear_gaussian_ssm.inference import ( - PosteriorGSSMFiltered, lgssm_filter, ) from cd_dynamax.dynamax.linear_gaussian_ssm.models import LinearGaussianSSM @@ -23,7 +21,6 @@ EKFConfig, KFConfig, UKFConfig, - _config_to_record_kwargs, ) from dynestyx.inference.integrations.cd_dynamax.utils import ( _require_constant_linear_gaussian_fields, @@ -35,7 +32,6 @@ LinearGaussianObservation, LinearGaussianStateEvolution, ) -from dynestyx.utils import _should_record_field def _lti_to_lgssm_params(dynamics: DynamicalModel): @@ -140,36 +136,6 @@ def compute_cd_dynamax_discrete_filter( ) -def _add_kf_sites( - name: str, posterior: PosteriorGSSMFiltered, record_kwargs: dict -) -> None: - """Add filtered means/covariances as deterministic sites (dynamax KF posterior).""" - max_elems = record_kwargs["record_max_elems"] - if posterior.filtered_means is None: - return - means = posterior.filtered_means - covs = posterior.filtered_covariances - t1, state_dim = means.shape - add_mean = _should_record_field( - record_kwargs["record_filtered_states_mean"], means.shape, max_elems - ) - add_cov = _should_record_field( - record_kwargs["record_filtered_states_cov"], - (t1, state_dim, state_dim), - max_elems, - ) - add_cov_diag = _should_record_field( - record_kwargs["record_filtered_states_cov_diag"], (t1, state_dim), max_elems - ) - if add_mean: - numpyro.deterministic(f"{name}_filtered_states_mean", means) - if add_cov and covs is not None: - numpyro.deterministic(f"{name}_filtered_states_cov", covs) - if add_cov_diag and covs is not None: - diag_cov = jnp.diagonal(covs, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) - - def run_discrete_filter( name: str, dynamics: DynamicalModel, @@ -180,8 +146,20 @@ def run_discrete_filter( ctrl_times=None, ctrl_values=None, **kwargs, -) -> list[dist.Distribution]: - """Run discrete-time filter via cd-dynamax (KF, EKF, UKF).""" +) -> tuple[jax.Array, object, list[dist.Distribution]]: + """Run discrete-time filter via cd-dynamax (KF, EKF, UKF). + + Pure computation — no numpyro side-effects. Callers are responsible for + registering numpyro.factor / numpyro.deterministic if needed. + + Returns: + tuple of: + - marginal_loglik: scalar marginal log-likelihood log p(y_{1:T}). + - posterior: CD-Dynamax posterior object with filtered_means and + filtered_covariances attributes. + - filtered_dists: list of MultivariateNormal distributions p(x_t | y_{1:t}) + at each obs time, for posterior rollout. + """ posterior = compute_cd_dynamax_discrete_filter( dynamics, filter_config, @@ -191,19 +169,14 @@ def run_discrete_filter( ctrl_values=ctrl_values, ) - record_kwargs = _config_to_record_kwargs(filter_config) - marginal_loglik = posterior.marginal_loglik - numpyro.factor(f"{name}_marginal_log_likelihood", marginal_loglik) - numpyro.deterministic(f"{name}_marginal_loglik", marginal_loglik) - _add_kf_sites(name, posterior, record_kwargs) - - return _posterior_sequence_to_dists( + filtered_dists = _posterior_sequence_to_dists( posterior, means_attr="filtered_means", covariances_attr="filtered_covariances", particle_mode=False, missing="empty", ) + return posterior.marginal_loglik, posterior, filtered_dists __all__ = [ diff --git a/dynestyx/inference/integrations/cd_dynamax/discrete_smoother.py b/dynestyx/inference/integrations/cd_dynamax/discrete_smoother.py index 1686ccc1..364d376f 100644 --- a/dynestyx/inference/integrations/cd_dynamax/discrete_smoother.py +++ b/dynestyx/inference/integrations/cd_dynamax/discrete_smoother.py @@ -1,8 +1,6 @@ """Discrete-time smoothers via cd-dynamax (dynamax): KF, EKF, UKF.""" import jax -import jax.numpy as jnp -import numpyro import numpyro.distributions as dist from cd_dynamax.dynamax.linear_gaussian_ssm.inference import lgssm_smoother from cd_dynamax.dynamax.nonlinear_gaussian_ssm.inference_ekf import ( @@ -26,10 +24,8 @@ from dynestyx.inference.integrations.cd_dynamax.utils import gaussian_to_nlgssm_params from dynestyx.inference.smoother_configs import ( BaseSmootherConfig, - _config_to_smoother_record_kwargs, ) from dynestyx.models import DynamicalModel -from dynestyx.utils import _should_record_field def compute_cd_dynamax_discrete_smoother( @@ -68,34 +64,6 @@ def compute_cd_dynamax_discrete_smoother( ) -def _add_smoother_sites(name: str, posterior, record_kwargs: dict) -> None: - """Add smoothed means/covariances as deterministic sites.""" - max_elems = record_kwargs["record_max_elems"] - means = posterior.smoothed_means - covs = posterior.smoothed_covariances - if means is None or covs is None: - return - t1, state_dim = means.shape - add_mean = _should_record_field( - record_kwargs["record_smoothed_states_mean"], means.shape, max_elems - ) - add_cov = _should_record_field( - record_kwargs["record_smoothed_states_cov"], - (t1, state_dim, state_dim), - max_elems, - ) - add_cov_diag = _should_record_field( - record_kwargs["record_smoothed_states_cov_diag"], (t1, state_dim), max_elems - ) - if add_mean: - numpyro.deterministic(f"{name}_smoothed_states_mean", means) - if add_cov: - numpyro.deterministic(f"{name}_smoothed_states_cov", covs) - if add_cov_diag: - diag_cov = jnp.diagonal(covs, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) - - def run_discrete_smoother( name: str, dynamics: DynamicalModel, @@ -106,8 +74,20 @@ def run_discrete_smoother( ctrl_times=None, ctrl_values=None, **kwargs, -) -> list[dist.Distribution]: - """Run discrete-time smoother via cd-dynamax (KF, EKF, UKF).""" +) -> tuple[jax.Array, object, list[dist.Distribution]]: + """Run discrete-time smoother via cd-dynamax (KF, EKF, UKF). + + Pure computation — no numpyro side-effects. Callers are responsible for + registering numpyro.factor / numpyro.deterministic if needed. + + Returns: + tuple of: + - marginal_loglik: scalar marginal log-likelihood log p(y_{1:T}). + - posterior: CD-Dynamax posterior object with smoothed_means and + smoothed_covariances attributes. + - smoothed_dists: list of MultivariateNormal distributions p(x_t | y_{1:T}) + at each obs time, for posterior rollout. + """ posterior = compute_cd_dynamax_discrete_smoother( dynamics, filter_config, @@ -117,19 +97,14 @@ def run_discrete_smoother( ctrl_values=ctrl_values, ) - numpyro.factor(f"{name}_marginal_log_likelihood", posterior.marginal_loglik) - numpyro.deterministic(f"{name}_marginal_loglik", posterior.marginal_loglik) - _add_smoother_sites( - name, posterior, _config_to_smoother_record_kwargs(filter_config) - ) - - return _posterior_sequence_to_dists( + smoothed_dists = _posterior_sequence_to_dists( posterior, means_attr="smoothed_means", covariances_attr="smoothed_covariances", particle_mode=False, missing="empty", ) + return posterior.marginal_loglik, posterior, smoothed_dists __all__ = ["compute_cd_dynamax_discrete_smoother", "run_discrete_smoother"] diff --git a/dynestyx/inference/integrations/cuthbert/discrete_filter.py b/dynestyx/inference/integrations/cuthbert/discrete_filter.py index fd69e894..bca1bd6f 100644 --- a/dynestyx/inference/integrations/cuthbert/discrete_filter.py +++ b/dynestyx/inference/integrations/cuthbert/discrete_filter.py @@ -3,7 +3,6 @@ import jax import jax.numpy as jnp -import numpyro import numpyro.distributions as dist from cuthbert import filter as cuthbert_filter from cuthbert.enkf import ensemble_kalman_filter @@ -15,7 +14,6 @@ stop_gradient_decorator, systematic, ) -from numpyro.distributions import Distribution from dynestyx.inference.distribution_utils import _cholesky_state_sequence_to_dists from dynestyx.inference.filter_configs import ( @@ -24,10 +22,8 @@ EnKFConfig, KFConfig, PFConfig, - _config_to_record_kwargs, ) from dynestyx.inference.integrations.utils import ( - covariance_from_cholesky, squeeze_leading_singletons, ) from dynestyx.models import ( @@ -36,7 +32,6 @@ LinearGaussianObservation, LinearGaussianStateEvolution, ) -from dynestyx.utils import _should_record_field class CuthbertInputs(NamedTuple): @@ -100,10 +95,10 @@ def _probe_state_independent_observation_noise( probe_u = jnp.zeros(()) probe_t = jnp.zeros(()) try: - probe_d0: Distribution | None = obs_model( + probe_d0: dist.Distribution | None = obs_model( jnp.zeros((state_dim,)), probe_u, probe_t ) - probe_d1: Distribution | None = obs_model( + probe_d1: dist.Distribution | None = obs_model( jnp.ones((state_dim,)), probe_u, probe_t ) except Exception: @@ -260,15 +255,24 @@ def run_discrete_filter( ctrl_times=None, ctrl_values=None, **kwargs, -) -> list[dist.Distribution]: +) -> tuple[jax.Array | None, object | None, list[dist.Distribution]]: """Run discrete-time filter via cuthbert (Kalman, Taylor KF, particle filter). + Pure computation — no numpyro side-effects. Callers are responsible for + registering numpyro.factor / numpyro.deterministic if needed. + Returns: - list[dist.Distribution]: Filtered state distributions at each obs time. + tuple of: + - marginal_loglik: scalar marginal log-likelihood log p(y_{1:T}), + or None if obs_values is empty. + - raw_states: cuthbert filter state object (KalmanFilterState, + ParticleFilterState, etc.), or None if obs_values is empty. + - filtered_dists: list of distributions p(x_t | y_{1:t}) at each + obs time, for posterior rollout. """ obs_len = int(obs_values.shape[0]) if obs_len == 0: - return [] + return None, None, [] marginal_loglik, states = compute_cuthbert_filter( dynamics, @@ -279,19 +283,11 @@ def run_discrete_filter( ctrl_times=ctrl_times, ctrl_values=ctrl_values, ) - record_kwargs = _config_to_record_kwargs(filter_config) - - numpyro.factor(f"{name}_marginal_log_likelihood", marginal_loglik) - numpyro.deterministic(f"{name}_marginal_loglik", marginal_loglik) - - if isinstance(filter_config, PFConfig): - _add_sites_pf(name, states, record_kwargs) - else: - _add_sites_gaussian_filter(name, states, record_kwargs) - return _cholesky_state_sequence_to_dists( + filtered_dists = _cholesky_state_sequence_to_dists( states, particle_mode=isinstance(filter_config, PFConfig), ) + return marginal_loglik, states, filtered_dists def _cuthbert_filter_pf(dynamics: DynamicalModel, filter_kwargs: dict | None = None): @@ -649,104 +645,3 @@ def log_potential(x): ignore_nan_dims=True, ) return kf - - -def _add_sites_pf( - name: str, states: particle_filter.ParticleFilterState, record_kwargs: dict -): - log_weights = states.log_weights - particles = states.particles - if particles.ndim == 2: - particles = particles[..., None] - max_elems = record_kwargs["record_max_elems"] - t_len, n_particles, state_dim = particles.shape - - add_particles = _should_record_field( - record_kwargs["record_filtered_particles"], particles.shape, max_elems - ) - add_log_weights = _should_record_field( - record_kwargs["record_filtered_log_weights"], log_weights.shape, max_elems - ) - add_mean = _should_record_field( - record_kwargs["record_filtered_states_mean"], (t_len, state_dim), max_elems - ) - add_filtered_states_cov = _should_record_field( - record_kwargs["record_filtered_states_cov"], - (t_len, state_dim, state_dim), - max_elems, - ) - add_filtered_states_cov_diag = _should_record_field( - record_kwargs["record_filtered_states_cov_diag"], (t_len, state_dim), max_elems - ) - - need_filtered_means = ( - add_mean or add_filtered_states_cov or add_filtered_states_cov_diag - ) - - if need_filtered_means: - w = jax.nn.softmax(log_weights, axis=1)[..., None] # (T+1, n_particles, 1) - filtered_means = jnp.sum(particles * w, axis=1) # (T+1, state_dim) - - if add_filtered_states_cov or add_filtered_states_cov_diag: - second_mom = jnp.einsum( - "...tnj,...tnk,...tn->...tjk", particles, particles, w.squeeze(-1) - ) - filtered_covariances = second_mom - jnp.einsum( - "...tj,...tk->...tjk", filtered_means, filtered_means - ) - - if add_particles: - numpyro.deterministic(f"{name}_filtered_particles", particles) - if add_log_weights: - numpyro.deterministic(f"{name}_filtered_log_weights", log_weights) - if add_mean: - numpyro.deterministic(f"{name}_filtered_states_mean", filtered_means) - if add_filtered_states_cov: - numpyro.deterministic(f"{name}_filtered_states_cov", filtered_covariances) - if add_filtered_states_cov_diag: - diag_cov = jnp.diagonal(filtered_covariances, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) - - -def _add_sites_gaussian_filter( - name: str, - states: kalman.KalmanFilterState - | taylor.LinearizedKalmanFilterState - | ensemble_kalman_filter.EnKFState, - record_kwargs: dict, -): - max_elems = record_kwargs["record_max_elems"] - mean = states.mean - chol_cov = states.chol_cov - t_len, state_dim, _ = chol_cov.shape - - add_mean = _should_record_field( - record_kwargs["record_filtered_states_mean"], mean.shape, max_elems - ) - add_chol_cov = _should_record_field( - record_kwargs["record_filtered_states_chol_cov"], - chol_cov.shape, - max_elems, - ) - add_filtered_states_cov = _should_record_field( - record_kwargs["record_filtered_states_cov"], - (t_len, state_dim, state_dim), - max_elems, - ) - add_filtered_states_cov_diag = _should_record_field( - record_kwargs["record_filtered_states_cov_diag"], (t_len, state_dim), max_elems - ) - - if add_mean: - numpyro.deterministic(f"{name}_filtered_states_mean", mean) - if add_chol_cov: - numpyro.deterministic(f"{name}_filtered_states_chol_cov", chol_cov) - - if add_filtered_states_cov or add_filtered_states_cov_diag: - filtered_cov = covariance_from_cholesky(chol_cov) - - if add_filtered_states_cov: - numpyro.deterministic(f"{name}_filtered_states_cov", filtered_cov) - if add_filtered_states_cov_diag: - diag_cov = jnp.diagonal(filtered_cov, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) diff --git a/dynestyx/inference/integrations/cuthbert/discrete_smoother.py b/dynestyx/inference/integrations/cuthbert/discrete_smoother.py index ef54dba7..5c9294c3 100644 --- a/dynestyx/inference/integrations/cuthbert/discrete_smoother.py +++ b/dynestyx/inference/integrations/cuthbert/discrete_smoother.py @@ -6,7 +6,6 @@ import jax import jax.numpy as jnp -import numpyro import numpyro.distributions as dist from cuthbert import smoother as cuthbert_smoother from cuthbert.gaussian import kalman, taylor @@ -23,21 +22,18 @@ compute_cuthbert_filter, ) from dynestyx.inference.integrations.utils import ( - covariance_from_cholesky, squeeze_leading_singletons, ) from dynestyx.inference.smoother_configs import ( EKFSmootherConfig, KFSmootherConfig, PFSmootherConfig, - _config_to_smoother_record_kwargs, ) from dynestyx.models import ( DynamicalModel, LinearGaussianObservation, LinearGaussianStateEvolution, ) -from dynestyx.utils import _should_record_field CuthbertSmootherConfig = KFSmootherConfig | EKFSmootherConfig | PFSmootherConfig @@ -224,96 +220,6 @@ def compute_cuthbert_smoother( return marginal_loglik, smoothed_states -def _add_sites_pf(name: str, states, record_kwargs: dict): - log_weights = states.log_weights - particles = states.particles - if particles.ndim == 2: - particles = particles[..., None] - max_elems = record_kwargs["record_max_elems"] - t1, _, state_dim = particles.shape - - add_particles = _should_record_field( - record_kwargs["record_smoothed_particles"], particles.shape, max_elems - ) - add_log_weights = _should_record_field( - record_kwargs["record_smoothed_log_weights"], log_weights.shape, max_elems - ) - add_mean = _should_record_field( - record_kwargs["record_smoothed_states_mean"], (t1, state_dim), max_elems - ) - add_smoothed_states_cov = _should_record_field( - record_kwargs["record_smoothed_states_cov"], - (t1, state_dim, state_dim), - max_elems, - ) - add_smoothed_states_cov_diag = _should_record_field( - record_kwargs["record_smoothed_states_cov_diag"], (t1, state_dim), max_elems - ) - - need_means = add_mean or add_smoothed_states_cov or add_smoothed_states_cov_diag - if need_means: - w = jax.nn.softmax(log_weights, axis=1)[..., None] - smoothed_means = jnp.sum(particles * w, axis=1) - - if add_smoothed_states_cov or add_smoothed_states_cov_diag: - second_mom = jnp.einsum( - "...tnj,...tnk,...tn->...tjk", particles, particles, w.squeeze(-1) - ) - smoothed_cov = second_mom - jnp.einsum( - "...tj,...tk->...tjk", smoothed_means, smoothed_means - ) - - if add_particles: - numpyro.deterministic(f"{name}_smoothed_particles", particles) - if add_log_weights: - numpyro.deterministic(f"{name}_smoothed_log_weights", log_weights) - if add_mean: - numpyro.deterministic(f"{name}_smoothed_states_mean", smoothed_means) - if add_smoothed_states_cov: - numpyro.deterministic(f"{name}_smoothed_states_cov", smoothed_cov) - if add_smoothed_states_cov_diag: - diag_cov = jnp.diagonal(smoothed_cov, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) - - -def _add_sites_taylor_kf(name: str, states, record_kwargs: dict): - max_elems = record_kwargs["record_max_elems"] - mean = states.mean - chol_cov = states.chol_cov - t1, state_dim, _ = chol_cov.shape - - add_mean = _should_record_field( - record_kwargs["record_smoothed_states_mean"], mean.shape, max_elems - ) - add_chol_cov = _should_record_field( - record_kwargs["record_smoothed_states_chol_cov"], - chol_cov.shape, - max_elems, - ) - add_smoothed_states_cov = _should_record_field( - record_kwargs["record_smoothed_states_cov"], - (t1, state_dim, state_dim), - max_elems, - ) - add_smoothed_states_cov_diag = _should_record_field( - record_kwargs["record_smoothed_states_cov_diag"], (t1, state_dim), max_elems - ) - - if add_mean: - numpyro.deterministic(f"{name}_smoothed_states_mean", mean) - if add_chol_cov: - numpyro.deterministic(f"{name}_smoothed_states_chol_cov", chol_cov) - - if add_smoothed_states_cov or add_smoothed_states_cov_diag: - smoothed_cov = covariance_from_cholesky(chol_cov) - - if add_smoothed_states_cov: - numpyro.deterministic(f"{name}_smoothed_states_cov", smoothed_cov) - if add_smoothed_states_cov_diag: - diag_cov = jnp.diagonal(smoothed_cov, axis1=1, axis2=2) - numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) - - def run_discrete_smoother( name: str, dynamics: DynamicalModel, @@ -325,11 +231,21 @@ def run_discrete_smoother( ctrl_times=None, ctrl_values=None, **kwargs, -) -> list[dist.Distribution]: - """Run discrete-time smoother via cuthbert.""" +) -> tuple[jax.Array | None, object | None, list[dist.Distribution]]: + """Run discrete-time smoother via cuthbert. + + Returns: + tuple of: + - marginal_loglik: scalar marginal log-likelihood log p(y_{1:T}), + or None if obs_values is empty. + - raw_states: cuthbert smoother state object, or None if obs_values + is empty. + - smoothed_dists: list of distributions p(x_t | y_{1:T}) at each + obs time, for posterior rollout. + """ t1 = int(obs_values.shape[0]) if t1 == 0: - return [] + return None, None, [] marginal_loglik, states = compute_cuthbert_smoother( dynamics, @@ -340,19 +256,11 @@ def run_discrete_smoother( ctrl_times=ctrl_times, ctrl_values=ctrl_values, ) - record_kwargs = _config_to_smoother_record_kwargs(smoother_config) - - numpyro.factor(f"{name}_marginal_log_likelihood", marginal_loglik) - numpyro.deterministic(f"{name}_marginal_loglik", marginal_loglik) - - if isinstance(smoother_config, PFSmootherConfig): - _add_sites_pf(name, states, record_kwargs) - else: - _add_sites_taylor_kf(name, states, record_kwargs) - return _cholesky_state_sequence_to_dists( + smoothed_dists = _cholesky_state_sequence_to_dists( states, particle_mode=isinstance(smoother_config, PFSmootherConfig), ) + return marginal_loglik, states, smoothed_dists __all__ = ["compute_cuthbert_smoother", "run_discrete_smoother"] diff --git a/dynestyx/inference/numpyro_sites.py b/dynestyx/inference/numpyro_sites.py new file mode 100644 index 00000000..2b797494 --- /dev/null +++ b/dynestyx/inference/numpyro_sites.py @@ -0,0 +1,362 @@ +"""NumPyro site registration for filter and smoother outputs. + +All numpyro.factor and numpyro.deterministic calls live here, +keeping the integration backends (cuthbert, cd-dynamax) free of numpyro +side effects (they still use numpyro.distributions for return types). +""" + +import jax +import jax.numpy as jnp +import numpyro + +from dynestyx.inference.filter_configs import ( + BaseFilterConfig, + ContinuousTimeConfigs, + HMMConfig, + PFConfig, + _config_to_record_kwargs, +) +from dynestyx.inference.integrations.utils import covariance_from_cholesky +from dynestyx.inference.smoother_configs import ( + BaseSmootherConfig, + PFSmootherConfig, + _config_to_smoother_record_kwargs, +) +from dynestyx.utils import _should_record_field + + +def register_filter_sites( + name: str, + marginal_loglik: jax.Array, + states: object, + filter_config: BaseFilterConfig, +) -> None: + """Register numpyro.factor and deterministic sites for a filter run.""" + numpyro.factor(f"{name}_marginal_log_likelihood", marginal_loglik) + numpyro.deterministic(f"{name}_marginal_loglik", marginal_loglik) + + if isinstance(filter_config, HMMConfig): + return + + record_kwargs = _config_to_record_kwargs(filter_config) + + if isinstance(filter_config, tuple(ContinuousTimeConfigs)): + _add_continuous_filter_sites(name, states, record_kwargs) + elif isinstance(filter_config, PFConfig): + _add_cuthbert_pf_sites(name, states, record_kwargs) + else: + _add_gaussian_filter_sites(name, states, filter_config, record_kwargs) + + +def register_hmm_filter_sites( + name: str, + loglik: jax.Array, + log_filt_seq: jax.Array, + filter_config: HMMConfig, +) -> None: + """Register numpyro sites for HMM filter output.""" + numpyro.factor(f"{name}_marginal_log_likelihood", loglik) + numpyro.deterministic(f"{name}_marginal_loglik", loglik) + + record_max_elems = filter_config.record_max_elems + + if _should_record_field( + filter_config.record_log_filtered, log_filt_seq.shape, record_max_elems + ): + numpyro.deterministic(f"{name}_log_filtered_states", log_filt_seq) + + if _should_record_field( + filter_config.record_filtered, log_filt_seq.shape, record_max_elems + ): + numpyro.deterministic(f"{name}_filtered_states", jnp.exp(log_filt_seq)) + + +def register_smoother_sites( + name: str, + marginal_loglik: jax.Array, + states: object, + smoother_config: BaseSmootherConfig, +) -> None: + """Register numpyro.factor and deterministic sites for a smoother run.""" + numpyro.factor(f"{name}_marginal_log_likelihood", marginal_loglik) + numpyro.deterministic(f"{name}_marginal_loglik", marginal_loglik) + + record_kwargs = _config_to_smoother_record_kwargs(smoother_config) + + if isinstance(smoother_config, PFSmootherConfig): + _add_cuthbert_pf_smoother_sites(name, states, record_kwargs) + elif hasattr(states, "smoothed_means"): + _add_cd_dynamax_smoother_sites(name, states, record_kwargs) + elif states is not None and hasattr(states, "mean"): + _add_cuthbert_gaussian_smoother_sites(name, states, record_kwargs) + + +def _add_continuous_filter_sites(name: str, filtered, record_kwargs: dict) -> None: + max_elems = record_kwargs["record_max_elems"] + means_shape = filtered.filtered_means.shape + cov_shape = filtered.filtered_covariances.shape + add_mean = _should_record_field( + record_kwargs["record_filtered_states_mean"], means_shape, max_elems + ) + add_cov = _should_record_field( + record_kwargs["record_filtered_states_cov"], cov_shape, max_elems + ) + add_cov_diag = _should_record_field( + record_kwargs["record_filtered_states_cov_diag"], + (cov_shape[0], cov_shape[1]), + max_elems, + ) + if add_mean: + numpyro.deterministic(f"{name}_filtered_states_mean", filtered.filtered_means) + if add_cov: + numpyro.deterministic( + f"{name}_filtered_states_cov", filtered.filtered_covariances + ) + if add_cov_diag: + diag_cov = jnp.diagonal(filtered.filtered_covariances, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) + + +def _add_cuthbert_pf_sites(name: str, states, record_kwargs: dict) -> None: + log_weights = states.log_weights + particles = states.particles + if particles.ndim == 2: + particles = particles[..., None] + max_elems = record_kwargs["record_max_elems"] + t_len, n_particles, state_dim = particles.shape + + add_particles = _should_record_field( + record_kwargs["record_filtered_particles"], particles.shape, max_elems + ) + add_log_weights = _should_record_field( + record_kwargs["record_filtered_log_weights"], log_weights.shape, max_elems + ) + add_mean = _should_record_field( + record_kwargs["record_filtered_states_mean"], (t_len, state_dim), max_elems + ) + add_filtered_states_cov = _should_record_field( + record_kwargs["record_filtered_states_cov"], + (t_len, state_dim, state_dim), + max_elems, + ) + add_filtered_states_cov_diag = _should_record_field( + record_kwargs["record_filtered_states_cov_diag"], (t_len, state_dim), max_elems + ) + + need_filtered_means = ( + add_mean or add_filtered_states_cov or add_filtered_states_cov_diag + ) + + if need_filtered_means: + w = jax.nn.softmax(log_weights, axis=1)[..., None] + filtered_means = jnp.sum(particles * w, axis=1) + + if add_filtered_states_cov or add_filtered_states_cov_diag: + second_mom = jnp.einsum( + "...tnj,...tnk,...tn->...tjk", particles, particles, w.squeeze(-1) + ) + filtered_covariances = second_mom - jnp.einsum( + "...tj,...tk->...tjk", filtered_means, filtered_means + ) + + if add_particles: + numpyro.deterministic(f"{name}_filtered_particles", particles) + if add_log_weights: + numpyro.deterministic(f"{name}_filtered_log_weights", log_weights) + if add_mean: + numpyro.deterministic(f"{name}_filtered_states_mean", filtered_means) + if add_filtered_states_cov: + numpyro.deterministic(f"{name}_filtered_states_cov", filtered_covariances) + if add_filtered_states_cov_diag: + diag_cov = jnp.diagonal(filtered_covariances, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) + + +def _add_gaussian_filter_sites( + name: str, states, filter_config: BaseFilterConfig, record_kwargs: dict +) -> None: + """Sites for cuthbert Gaussian filters (KF, EKF, EnKF) or cd-dynamax discrete.""" + max_elems = record_kwargs["record_max_elems"] + + if hasattr(states, "filtered_means"): + means = states.filtered_means + covs = states.filtered_covariances + if means is None: + return + t_len, state_dim = means.shape + add_mean = _should_record_field( + record_kwargs["record_filtered_states_mean"], means.shape, max_elems + ) + add_cov = _should_record_field( + record_kwargs["record_filtered_states_cov"], + (t_len, state_dim, state_dim), + max_elems, + ) + add_cov_diag = _should_record_field( + record_kwargs["record_filtered_states_cov_diag"], + (t_len, state_dim), + max_elems, + ) + if add_mean: + numpyro.deterministic(f"{name}_filtered_states_mean", means) + if add_cov and covs is not None: + numpyro.deterministic(f"{name}_filtered_states_cov", covs) + if add_cov_diag and covs is not None: + diag_cov = jnp.diagonal(covs, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) + elif hasattr(states, "mean"): + mean = states.mean + chol_cov = states.chol_cov + t_len, state_dim, _ = chol_cov.shape + + add_mean = _should_record_field( + record_kwargs["record_filtered_states_mean"], mean.shape, max_elems + ) + add_chol_cov = _should_record_field( + record_kwargs["record_filtered_states_chol_cov"], + chol_cov.shape, + max_elems, + ) + add_filtered_states_cov = _should_record_field( + record_kwargs["record_filtered_states_cov"], + (t_len, state_dim, state_dim), + max_elems, + ) + add_filtered_states_cov_diag = _should_record_field( + record_kwargs["record_filtered_states_cov_diag"], + (t_len, state_dim), + max_elems, + ) + + if add_mean: + numpyro.deterministic(f"{name}_filtered_states_mean", mean) + if add_chol_cov: + numpyro.deterministic(f"{name}_filtered_states_chol_cov", chol_cov) + + if add_filtered_states_cov or add_filtered_states_cov_diag: + filtered_cov = covariance_from_cholesky(chol_cov) + + if add_filtered_states_cov: + numpyro.deterministic(f"{name}_filtered_states_cov", filtered_cov) + if add_filtered_states_cov_diag: + diag_cov = jnp.diagonal(filtered_cov, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_filtered_states_cov_diag", diag_cov) + + +def _add_cuthbert_pf_smoother_sites(name: str, states, record_kwargs: dict) -> None: + log_weights = states.log_weights + particles = states.particles + if particles.ndim == 2: + particles = particles[..., None] + max_elems = record_kwargs["record_max_elems"] + t1, _, state_dim = particles.shape + + add_particles = _should_record_field( + record_kwargs["record_smoothed_particles"], particles.shape, max_elems + ) + add_log_weights = _should_record_field( + record_kwargs["record_smoothed_log_weights"], log_weights.shape, max_elems + ) + add_mean = _should_record_field( + record_kwargs["record_smoothed_states_mean"], (t1, state_dim), max_elems + ) + add_smoothed_states_cov = _should_record_field( + record_kwargs["record_smoothed_states_cov"], + (t1, state_dim, state_dim), + max_elems, + ) + add_smoothed_states_cov_diag = _should_record_field( + record_kwargs["record_smoothed_states_cov_diag"], (t1, state_dim), max_elems + ) + + need_means = add_mean or add_smoothed_states_cov or add_smoothed_states_cov_diag + if need_means: + w = jax.nn.softmax(log_weights, axis=1)[..., None] + smoothed_means = jnp.sum(particles * w, axis=1) + + if add_smoothed_states_cov or add_smoothed_states_cov_diag: + second_mom = jnp.einsum( + "...tnj,...tnk,...tn->...tjk", particles, particles, w.squeeze(-1) + ) + smoothed_cov = second_mom - jnp.einsum( + "...tj,...tk->...tjk", smoothed_means, smoothed_means + ) + + if add_particles: + numpyro.deterministic(f"{name}_smoothed_particles", particles) + if add_log_weights: + numpyro.deterministic(f"{name}_smoothed_log_weights", log_weights) + if add_mean: + numpyro.deterministic(f"{name}_smoothed_states_mean", smoothed_means) + if add_smoothed_states_cov: + numpyro.deterministic(f"{name}_smoothed_states_cov", smoothed_cov) + if add_smoothed_states_cov_diag: + diag_cov = jnp.diagonal(smoothed_cov, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) + + +def _add_cd_dynamax_smoother_sites(name: str, posterior, record_kwargs: dict) -> None: + max_elems = record_kwargs["record_max_elems"] + means = posterior.smoothed_means + covs = posterior.smoothed_covariances + if means is None or covs is None: + return + t1, state_dim = means.shape + add_mean = _should_record_field( + record_kwargs["record_smoothed_states_mean"], means.shape, max_elems + ) + add_cov = _should_record_field( + record_kwargs["record_smoothed_states_cov"], + (t1, state_dim, state_dim), + max_elems, + ) + add_cov_diag = _should_record_field( + record_kwargs["record_smoothed_states_cov_diag"], (t1, state_dim), max_elems + ) + if add_mean: + numpyro.deterministic(f"{name}_smoothed_states_mean", means) + if add_cov: + numpyro.deterministic(f"{name}_smoothed_states_cov", covs) + if add_cov_diag: + diag_cov = jnp.diagonal(covs, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) + + +def _add_cuthbert_gaussian_smoother_sites( + name: str, states, record_kwargs: dict +) -> None: + max_elems = record_kwargs["record_max_elems"] + mean = states.mean + chol_cov = states.chol_cov + t1, state_dim, _ = chol_cov.shape + + add_mean = _should_record_field( + record_kwargs["record_smoothed_states_mean"], mean.shape, max_elems + ) + add_chol_cov = _should_record_field( + record_kwargs["record_smoothed_states_chol_cov"], + chol_cov.shape, + max_elems, + ) + add_smoothed_states_cov = _should_record_field( + record_kwargs["record_smoothed_states_cov"], + (t1, state_dim, state_dim), + max_elems, + ) + add_smoothed_states_cov_diag = _should_record_field( + record_kwargs["record_smoothed_states_cov_diag"], (t1, state_dim), max_elems + ) + + if add_mean: + numpyro.deterministic(f"{name}_smoothed_states_mean", mean) + if add_chol_cov: + numpyro.deterministic(f"{name}_smoothed_states_chol_cov", chol_cov) + + if add_smoothed_states_cov or add_smoothed_states_cov_diag: + smoothed_cov = covariance_from_cholesky(chol_cov) + + if add_smoothed_states_cov: + numpyro.deterministic(f"{name}_smoothed_states_cov", smoothed_cov) + if add_smoothed_states_cov_diag: + diag_cov = jnp.diagonal(smoothed_cov, axis1=1, axis2=2) + numpyro.deterministic(f"{name}_smoothed_states_cov_diag", diag_cov) diff --git a/dynestyx/inference/smoothers.py b/dynestyx/inference/smoothers.py index ea55fff7..e95e1a2f 100644 --- a/dynestyx/inference/smoothers.py +++ b/dynestyx/inference/smoothers.py @@ -1,5 +1,6 @@ import dataclasses import math +from abc import ABC, abstractmethod from typing import cast import equinox as eqx @@ -11,7 +12,7 @@ from effectful.ops.syntax import ObjectInterpretation, implements from jaxtyping import Array, PRNGKeyArray, Real -from dynestyx.handlers import HandlesSelf, _sample_intp +from dynestyx.handlers import HandlesSelf, _condition_intp from dynestyx.inference.checkers import ( _validate_batched_plate_alignment, _validate_missing_observation_support, @@ -37,6 +38,7 @@ from dynestyx.inference.integrations.cuthbert.discrete_smoother import ( run_discrete_smoother as run_cuthbert_discrete_smoother, ) +from dynestyx.inference.numpyro_sites import register_smoother_sites from dynestyx.inference.plate_utils import ( _array_plate_axis, _make_plate_in_axes, @@ -54,7 +56,7 @@ UKFSmootherConfig, ) from dynestyx.models import DynamicalModel -from dynestyx.types import FunctionOfTime +from dynestyx.types import ConditionedResult, FunctionOfTime from dynestyx.utils import _dist_has_plate_batch_dims DiscreteSmootherConfig = ( @@ -106,10 +108,10 @@ def _final_obs_times_for_rollout( return obs_times[..., -1:] -class BaseSmootherLogFactorAdder(ObjectInterpretation, HandlesSelf): +class BaseSmootherLogFactorAdder(ObjectInterpretation, HandlesSelf, ABC): """Base class for smoother handlers.""" - @implements(_sample_intp) + @implements(_condition_intp) def _sample_ds( self, name: str, @@ -153,7 +155,8 @@ def _sample_ds( smoothed_times = None smoothed_dists = None - return fwd( + # fwd() lets handlers above (e.g. Simulator) use smoothed_dists for rollout. + fwd( name, dynamics, plate_shapes=plate_shapes, @@ -170,6 +173,9 @@ def _sample_ds( **kwargs, ) + return self._build_infer_result(name, smoothed_dists) + + @abstractmethod def _add_log_factors( self, name: str, @@ -185,8 +191,12 @@ def _add_log_factors( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, **kwargs, - ) -> list[numpyro.distributions.Distribution] | None: - raise NotImplementedError() + ) -> list[numpyro.distributions.Distribution] | None: ... + + @abstractmethod + def _build_infer_result( + self, name: str, smoothed_dists: list | None + ) -> ConditionedResult: ... @dataclasses.dataclass @@ -194,6 +204,13 @@ class Smoother(BaseSmootherLogFactorAdder): r"""Performs Bayesian smoothing to compute the smoothing distribution p(x_t | y_{1:T}).""" smoother_config: SmootherAnyConfig | None = None + marginal_loglik: jax.Array | None = dataclasses.field( + default=None, repr=False, init=False + ) + smoothed_states: object = dataclasses.field(default=None, repr=False, init=False) + _smoother_config_used: BaseSmootherConfig | None = dataclasses.field( + default=None, repr=False, init=False + ) def _add_log_factors( self, @@ -234,12 +251,17 @@ def _add_log_factors( mode="smoother", ) + # Resolve PRNG key: use explicit seed from config, fall back to numpyro + # context (inside a seeded model), or None (deterministic smoothers don't need one). typed_config = config - key = ( - numpyro.prng_key() - if typed_config.crn_seed is None - else typed_config.crn_seed - ) + if typed_config.crn_seed is not None: + key = typed_config.crn_seed + else: + import warnings # noqa: PLC0415 + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + key = numpyro.prng_key() # returns None outside seed handler if plate_shapes: return self._add_log_factors_batched( @@ -262,7 +284,7 @@ def _add_log_factors( f"Valid continuous-time config types: {valid}" ) continuous_config = cast(ContinuousSmootherConfig, typed_config) - return _smooth_continuous_time( + marginal_loglik, states, smoothed_dists = _smooth_continuous_time( name, dynamics, continuous_config, @@ -273,25 +295,58 @@ def _add_log_factors( ctrl_values=ctrl_values, **kwargs, ) - - if not isinstance(typed_config, DiscreteTimeSmootherConfigs): + elif not isinstance(typed_config, DiscreteTimeSmootherConfigs): valid = _valid_smoother_config_names(continuous_time=False) raise ValueError( f"Invalid smoother config: {type(typed_config).__name__}. " f"Valid discrete-time config types: {valid}" ) - discrete_config = cast(DiscreteSmootherConfig, typed_config) + else: + discrete_config = cast(DiscreteSmootherConfig, typed_config) + marginal_loglik, states, smoothed_dists = _smooth_discrete_time( + name, + dynamics, + discrete_config, + key=key, + obs_times=obs_times, + obs_values=obs_values, + ctrl_times=ctrl_times, + ctrl_values=ctrl_values, + **kwargs, + ) - return _smooth_discrete_time( - name, - dynamics, - discrete_config, - key=key, - obs_times=obs_times, - obs_values=obs_values, - ctrl_times=ctrl_times, - ctrl_values=ctrl_values, - **kwargs, + self.marginal_loglik = marginal_loglik + self.smoothed_states = states + self._smoother_config_used = typed_config + + return smoothed_dists + + def _build_infer_result( + self, name: str, smoothed_dists: list | None + ) -> ConditionedResult: + """Construct ConditionedResult with a deferred numpyro registration callback.""" + marginal_loglik = self.marginal_loglik + states = self.smoothed_states + config = self._smoother_config_used + _is_batched = ( + isinstance(marginal_loglik, jax.Array) and marginal_loglik.ndim > 0 + ) + + def _register(site_name: str) -> None: + if marginal_loglik is None or config is None: + return + if _is_batched: + # TODO: support per-field recording for batched (plate) states + numpyro.factor(f"{site_name}_marginal_log_likelihood", marginal_loglik) + numpyro.deterministic(f"{site_name}_marginal_loglik", marginal_loglik) + else: + register_smoother_sites(site_name, marginal_loglik, states, config) + + return ConditionedResult( + marginal_loglik=marginal_loglik, + states=states, + dists=smoothed_dists, + _register_numpyro_sites=_register, ) def _add_log_factors_batched( @@ -461,8 +516,9 @@ def compute_output_member(dyn, ot, ov, ct, cv, k, *idxs): else: raise ValueError(f"Unsupported batched output kind: {output_kind}") - numpyro.factor(f"{name}_marginal_log_likelihood", marginal_logliks) - numpyro.deterministic(f"{name}_marginal_loglik", marginal_logliks) + self.marginal_loglik = marginal_logliks + self.smoothed_states = outputs + self._smoother_config_used = config if output_kind == "continuous": return _posterior_sequence_to_dists( @@ -510,7 +566,7 @@ def _smooth_discrete_time( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, **kwargs, -) -> list[numpyro.distributions.Distribution]: +) -> tuple[jax.Array | None, object | None, list[numpyro.distributions.Distribution]]: """Discrete-time marginal likelihood via cuthbert or cd-dynamax smoothers.""" if isinstance(smoother_config, UKFSmootherConfig) and ( @@ -530,7 +586,7 @@ def _smooth_discrete_time( ) if smoother_config.filter_source == "cd_dynamax": - return run_cd_dynamax_discrete_smoother( + marginal_loglik, states, smoothed_dists = run_cd_dynamax_discrete_smoother( name, dynamics, smoother_config, @@ -540,15 +596,14 @@ def _smooth_discrete_time( ctrl_values=ctrl_values, **kwargs, ) - - if smoother_config.filter_source == "cuthbert": + elif smoother_config.filter_source == "cuthbert": if isinstance(smoother_config, UKFSmootherConfig): raise ValueError( "UKF smoothing is not available in cuthbert. " "Use UKFSmootherConfig(filter_source='cd_dynamax') or a cuthbert-supported smoother " "(KFSmootherConfig, EKFSmootherConfig, PFSmootherConfig)." ) - return run_cuthbert_discrete_smoother( + marginal_loglik, states, smoothed_dists = run_cuthbert_discrete_smoother( name, dynamics, smoother_config, @@ -559,8 +614,10 @@ def _smooth_discrete_time( ctrl_values=ctrl_values, **kwargs, ) + else: + raise ValueError(f"Unknown filter source: {smoother_config.filter_source}") - raise ValueError(f"Unknown filter source: {smoother_config.filter_source}") + return marginal_loglik, states, smoothed_dists def _smooth_continuous_time( @@ -577,14 +634,14 @@ def _smooth_continuous_time( | Real[Array, "*ctrl_value_plate ctrl_time"] | None = None, **kwargs, -) -> list[numpyro.distributions.Distribution]: +) -> tuple[jax.Array, object, list[numpyro.distributions.Distribution]]: """Continuous-time marginal likelihood via CD-Dynamax smoothers.""" if smoother_config.filter_source != "cd_dynamax": raise ValueError( f"{type(smoother_config).__name__} supports only filter_source='cd_dynamax'." ) - return run_continuous_smoother( + marginal_loglik, smoothed, smoothed_dists = run_continuous_smoother( name, dynamics, smoother_config, @@ -595,6 +652,7 @@ def _smooth_continuous_time( ctrl_values=ctrl_values, **kwargs, ) + return marginal_loglik, smoothed, smoothed_dists __all__ = [ diff --git a/dynestyx/simulators.py b/dynestyx/simulators.py index f4bea538..2dc277b6 100644 --- a/dynestyx/simulators.py +++ b/dynestyx/simulators.py @@ -19,7 +19,7 @@ from jaxtyping import Real from numpyro.contrib.control_flow import scan as nscan -from dynestyx.handlers import HandlesSelf, _sample_intp +from dynestyx.handlers import HandlesSelf, _condition_intp from dynestyx.inference.plate_utils import ( _slice_array_for_plate_member, _slice_dist_for_plate_member, @@ -460,7 +460,7 @@ def _run_plated_simulation( stacked[key] = flat.reshape(*plate_shapes, *values[0].shape) return stacked - @implements(_sample_intp) + @implements(_condition_intp) def _sample_ds( self, name: str, diff --git a/dynestyx/types.py b/dynestyx/types.py index 9e5f445b..0d78e2f2 100644 --- a/dynestyx/types.py +++ b/dynestyx/types.py @@ -1,7 +1,10 @@ """Shared typing helpers for dynamical systems.""" +import dataclasses +from collections.abc import Callable from typing import Protocol, runtime_checkable +import jax import jax.numpy as jnp from jaxtyping import Array, Real @@ -14,6 +17,30 @@ def __call__( raise NotImplementedError() +@dataclasses.dataclass +class ConditionedResult: + """Result of dsx.condition — the numpyro-free conditioning primitive. + + Carries all outputs from the handler stack (Filter, Smoother, etc.) + without registering any numpyro sites. + """ + + marginal_loglik: jax.Array | None = None + states: object = None + dists: list | None = None + _register_numpyro_sites: Callable[[str], None] | None = dataclasses.field( + default=None, repr=False + ) + + def __call__( + self, t: float | int | Real[Array, ""] + ) -> Real[Array, " state_dim"] | Real[Array, ""]: + raise NotImplementedError( + "ConditionedResult is not callable as a FunctionOfTime. " + "Access .marginal_loglik, .states, or .dists instead." + ) + + def as_scalar_time_array( value: float | int | Array, *, name: str, dtype=None ) -> Real[Array, ""]: diff --git a/tests/test_filter_standalone.py b/tests/test_filter_standalone.py new file mode 100644 index 00000000..e477e6db --- /dev/null +++ b/tests/test_filter_standalone.py @@ -0,0 +1,148 @@ +"""Tests for dsx.condition (standalone, no numpyro) and dsx.sample (numpyro model).""" + +import jax +import jax.numpy as jnp +import jax.random as jr +import optax + +import dynestyx as dsx +from dynestyx.inference.filter_configs import EnKFConfig, KFConfig +from dynestyx.inference.filters import Filter +from dynestyx.types import ConditionedResult + + +def _make_lti_dynamics(alpha): + return dsx.LTI_discrete( + A=jnp.array([[alpha, 0.1], [0.1, 0.8]]), + Q=0.1 * jnp.eye(2), + H=jnp.array([[1.0, 0.0]]), + R=jnp.array([[0.25]]), + ) + + +def _make_data(): + obs_times = jnp.arange(0.0, 10.0, 1.0) + key = jr.PRNGKey(42) + obs_values = jr.normal(key, (len(obs_times), 1)) + return obs_times, obs_values + + +# --- dsx.condition tests (standalone, no numpyro) --- + + +def test_infer_returns_infer_result(): + """dsx.condition returns an ConditionedResult with marginal_loglik.""" + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with Filter(filter_config=KFConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is not None + assert jnp.isfinite(result.marginal_loglik) + assert result.states is not None + assert result.dists is not None + + +def test_infer_enkf_with_crn_seed(): + """dsx.condition works with EnKF and explicit crn_seed.""" + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with Filter( + filter_config=EnKFConfig(n_particles=16, crn_seed=jr.PRNGKey(0)), + ): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is not None + assert jnp.isfinite(result.marginal_loglik) + + +def test_infer_optax_mle(): + """Use dsx.condition + optax to do MLE without numpyro.""" + obs_times, obs_values = _make_data() + + def neg_loglik(alpha): + dynamics = _make_lti_dynamics(alpha) + with Filter(filter_config=KFConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + return -result.marginal_loglik + + optimizer = optax.adam(1e-2) + alpha = jnp.array(0.3) + opt_state = optimizer.init(alpha) + + initial_loss = neg_loglik(alpha) + grad_fn = jax.grad(neg_loglik) + + for _ in range(20): + grads = grad_fn(alpha) + updates, opt_state = optimizer.update(grads, opt_state) + alpha = optax.apply_updates(alpha, updates) + + final_loss = neg_loglik(alpha) + assert final_loss < initial_loss + + +def test_infer_does_not_register_numpyro_sites(): + """dsx.condition does NOT register numpyro sites — that's dsx.sample's job.""" + from numpyro.handlers import seed, trace + + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with trace() as tr, seed(rng_seed=jr.PRNGKey(0)): + with Filter(filter_config=KFConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is not None + assert "f_marginal_loglik" not in tr + assert "f_marginal_log_likelihood" not in tr + + +def test_condition_no_observations(): + """dsx.condition with no obs returns ConditionedResult with marginal_loglik=None.""" + dynamics = _make_lti_dynamics(0.5) + + with Filter(filter_config=KFConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", + dynamics, + obs_times=None, + obs_values=None, + predict_times=jnp.arange(0.0, 5.0, 1.0), + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is None + assert result.states is None + assert result.dists is None + + +# --- dsx.sample tests (numpyro model) --- + + +def test_sample_registers_numpyro_sites(): + """dsx.sample registers numpyro sites via the callback.""" + from numpyro.handlers import seed, trace + + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with trace() as tr, seed(rng_seed=jr.PRNGKey(0)): + with Filter(filter_config=KFConfig(filter_source="cuthbert")): + dsx.sample("f", dynamics, obs_times=obs_times, obs_values=obs_values) + + assert "f_marginal_loglik" in tr + assert jnp.isfinite(tr["f_marginal_loglik"]["value"]) diff --git a/tests/test_filters.py b/tests/test_filters.py index 69830460..91252a72 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -238,15 +238,14 @@ def test_cuthbert_filtered_distribution_shapes_match_observations(filter_config) obs_times, obs_values = _make_discrete_lti_data() dynamics = _make_discrete_lti_dynamics() - with trace(), seed(rng_seed=jr.PRNGKey(1)): - filtered_dists = run_cuthbert_discrete_filter( - "f", - dynamics, - filter_config, - key=jr.PRNGKey(2), - obs_times=obs_times, - obs_values=obs_values, - ) + _marginal_loglik, _states, filtered_dists = run_cuthbert_discrete_filter( + "f", + dynamics, + filter_config, + key=jr.PRNGKey(2), + obs_times=obs_times, + obs_values=obs_values, + ) assert len(filtered_dists) == len(obs_times) for filtered_dist in filtered_dists: @@ -336,15 +335,14 @@ def test_cuthbert_enkf_accepts_callable_independent_normal_observation(): ), ) - with trace(), seed(rng_seed=jr.PRNGKey(1)): - filtered_dists = run_cuthbert_discrete_filter( - "f", - dynamics, - EnKFConfig(n_particles=16, filter_source="cuthbert"), - key=jr.PRNGKey(2), - obs_times=obs_times, - obs_values=obs_values, - ) + _marginal_loglik, _states, filtered_dists = run_cuthbert_discrete_filter( + "f", + dynamics, + EnKFConfig(n_particles=16, filter_source="cuthbert"), + key=jr.PRNGKey(2), + obs_times=obs_times, + obs_values=obs_values, + ) assert len(filtered_dists) == len(obs_times) assert all(d.event_shape == (dynamics.state_dim,) for d in filtered_dists) diff --git a/tests/test_smoother_standalone.py b/tests/test_smoother_standalone.py new file mode 100644 index 00000000..bf75ea4d --- /dev/null +++ b/tests/test_smoother_standalone.py @@ -0,0 +1,131 @@ +"""Tests for dsx.condition with Smoother (standalone, no numpyro).""" + +import jax +import jax.numpy as jnp +import jax.random as jr +import optax + +import dynestyx as dsx +from dynestyx.inference.smoother_configs import KFSmootherConfig +from dynestyx.inference.smoothers import Smoother +from dynestyx.types import ConditionedResult + + +def _make_lti_dynamics(alpha): + return dsx.LTI_discrete( + A=jnp.array([[alpha, 0.1], [0.1, 0.8]]), + Q=0.1 * jnp.eye(2), + H=jnp.array([[1.0, 0.0]]), + R=jnp.array([[0.25]]), + ) + + +def _make_data(): + obs_times = jnp.arange(0.0, 10.0, 1.0) + key = jr.PRNGKey(42) + obs_values = jr.normal(key, (len(obs_times), 1)) + return obs_times, obs_values + + +# --- dsx.condition tests (standalone, no numpyro) --- + + +def test_infer_smoother_returns_infer_result(): + """dsx.condition with Smoother returns an ConditionedResult.""" + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with Smoother(smoother_config=KFSmootherConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is not None + assert jnp.isfinite(result.marginal_loglik) + assert result.states is not None + assert result.dists is not None + + +def test_infer_smoother_optax_mle(): + """Use dsx.condition + Smoother + optax to do MLE without numpyro.""" + obs_times, obs_values = _make_data() + + def neg_loglik(alpha): + dynamics = _make_lti_dynamics(alpha) + with Smoother(smoother_config=KFSmootherConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + return -result.marginal_loglik + + optimizer = optax.adam(1e-2) + alpha = jnp.array(0.3) + opt_state = optimizer.init(alpha) + + initial_loss = neg_loglik(alpha) + grad_fn = jax.grad(neg_loglik) + + for _ in range(20): + grads = grad_fn(alpha) + updates, opt_state = optimizer.update(grads, opt_state) + alpha = optax.apply_updates(alpha, updates) + + final_loss = neg_loglik(alpha) + assert final_loss < initial_loss + + +def test_infer_smoother_does_not_register_numpyro_sites(): + """dsx.condition with Smoother does NOT register numpyro sites.""" + from numpyro.handlers import seed, trace + + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with trace() as tr, seed(rng_seed=jr.PRNGKey(0)): + with Smoother(smoother_config=KFSmootherConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", dynamics, obs_times=obs_times, obs_values=obs_values + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is not None + assert "f_marginal_loglik" not in tr + assert "f_marginal_log_likelihood" not in tr + + +def test_condition_smoother_no_observations(): + """dsx.condition with Smoother and no obs returns ConditionedResult with marginal_loglik=None.""" + dynamics = _make_lti_dynamics(0.5) + + with Smoother(smoother_config=KFSmootherConfig(filter_source="cuthbert")): + result = dsx.condition( + "f", + dynamics, + obs_times=None, + obs_values=None, + predict_times=jnp.arange(0.0, 5.0, 1.0), + ) + + assert isinstance(result, ConditionedResult) + assert result.marginal_loglik is None + assert result.states is None + assert result.dists is None + + +# --- dsx.sample tests (numpyro model) --- + + +def test_sample_smoother_registers_numpyro_sites(): + """dsx.sample with Smoother registers numpyro sites via the callback.""" + from numpyro.handlers import seed, trace + + obs_times, obs_values = _make_data() + dynamics = _make_lti_dynamics(0.5) + + with trace() as tr, seed(rng_seed=jr.PRNGKey(0)): + with Smoother(smoother_config=KFSmootherConfig(filter_source="cuthbert")): + dsx.sample("f", dynamics, obs_times=obs_times, obs_values=obs_values) + + assert "f_marginal_loglik" in tr + assert jnp.isfinite(tr["f_marginal_loglik"]["value"])