From 51afb9fd65dce3adefe7db9d387600b9b0b9bfa2 Mon Sep 17 00:00:00 2001 From: Michal-Novomestsky Date: Wed, 2 Jul 2025 17:11:28 +1000 Subject: [PATCH 01/21] changed laplace approx to return MvNormal --- pymc_extras/inference/laplace.py | 685 +++++++++++++++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 pymc_extras/inference/laplace.py diff --git a/pymc_extras/inference/laplace.py b/pymc_extras/inference/laplace.py new file mode 100644 index 00000000..1b9f3048 --- /dev/null +++ b/pymc_extras/inference/laplace.py @@ -0,0 +1,685 @@ +# Copyright 2024 The PyMC Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import logging + +from collections.abc import Callable +from functools import reduce +from importlib.util import find_spec +from itertools import product +from typing import Literal + +import arviz as az +import numpy as np +import pymc as pm +import pytensor +import pytensor.tensor as pt +import xarray as xr + +from arviz import dict_to_dataset +from better_optimize.constants import minimize_method +from numpy.typing import ArrayLike +from pymc import DictToArrayBijection +from pymc.backends.arviz import ( + coords_and_dims_for_inferencedata, + find_constants, + find_observations, +) +from pymc.blocking import RaveledVars +from pymc.model.transform.conditioning import remove_value_transforms +from pymc.model.transform.optimization import freeze_dims_and_data +from pymc.util import get_default_varnames +from pytensor.tensor import TensorVariable +from pytensor.tensor.optimize import minimize +from scipy import stats + +from pymc_extras.inference.find_map import ( + GradientBackend, + _unconstrained_vector_to_constrained_rvs, + find_MAP, + get_nearest_psd, + scipy_optimize_funcs_from_loss, +) + +_log = logging.getLogger(__name__) + + +def get_conditional_gaussian_approximation( + x: TensorVariable, + Q: TensorVariable | ArrayLike, + mu: TensorVariable | ArrayLike, + args: list[TensorVariable] | None = None, + model: pm.Model | None = None, + method: minimize_method = "BFGS", + use_jac: bool = True, + use_hess: bool = False, + optimizer_kwargs: dict | None = None, +) -> Callable: + """ + Returns a function to estimate the a posteriori log probability of a latent Gaussian field x and its mode x0 using the Laplace approximation. + + That is: + y | x, sigma ~ N(Ax, sigma^2 W) + x | params ~ N(mu, Q(params)^-1) + + We seek to estimate log(p(x | y, params)): + + log(p(x | y, params)) = log(p(y | x, params)) + log(p(x | params)) + const + + Let f(x) = log(p(y | x, params)). From the definition of our model above, we have log(p(x | params)) = -0.5*(x - mu).T Q (x - mu) + 0.5*logdet(Q). + + This gives log(p(x | y, params)) = f(x) - 0.5*(x - mu).T Q (x - mu) + 0.5*logdet(Q). We will estimate this using the Laplace approximation by Taylor expanding f(x) about the mode. + + Thus: + + 1. Maximize log(p(x | y, params)) = f(x) - 0.5*(x - mu).T Q (x - mu) wrt x (note that logdet(Q) does not depend on x) to find the mode x0. + + 2. Substitute x0 into the Laplace approximation expanded about the mode: log(p(x | y, params)) ~= -0.5*x.T (-f''(x0) + Q) x + x.T (Q.mu + f'(x0) - f''(x0).x0) + 0.5*logdet(Q). + + Parameters + ---------- + x: TensorVariable + The parameter with which to maximize wrt (that is, find the mode in x). In INLA, this is the latent field x~N(mu,Q^-1). + Q: TensorVariable | ArrayLike + The precision matrix of the latent field x. + mu: TensorVariable | ArrayLike + The mean of the latent field x. + args: list[TensorVariable] + Args to supply to the compiled function. That is, (x0, logp) = f(x, *args). If set to None, assumes the model RVs are args. + model: Model + PyMC model to use. + method: minimize_method + Which minimization algorithm to use. + use_jac: bool + If true, the minimizer will compute the gradient of log(p(x | y, params)). + use_hess: bool + If true, the minimizer will compute the Hessian log(p(x | y, params)). + optimizer_kwargs: dict + Kwargs to pass to scipy.optimize.minimize. + + Returns + ------- + f: Callable + A function which accepts a value of x and args and returns [x0, log(p(x | y, params))], where x0 is the mode. x is currently both the point at which to evaluate logp and the initial guess for the minimizer. + """ + model = pm.modelcontext(model) + + if args is None: + args = model.continuous_value_vars + model.discrete_value_vars + + # f = log(p(y | x, params)) + f_x = model.logp() + jac = pytensor.gradient.grad(f_x, x) + hess = pytensor.gradient.jacobian(jac.flatten(), x) + + # log(p(x | y, params)) only including terms that depend on x for the minimization step (logdet(Q) ignored as it is a constant wrt x) + log_x_posterior = f_x - 0.5 * (x - mu).T @ Q @ (x - mu) + + # Maximize log(p(x | y, params)) wrt x to find mode x0 + x0, _ = minimize( + objective=-log_x_posterior, + x=x, + method=method, + jac=use_jac, + hess=use_hess, + optimizer_kwargs=optimizer_kwargs, + ) + + # require f'(x0) and f''(x0) for Laplace approx + jac = pytensor.graph.replace.graph_replace(jac, {x: x0}) + hess = pytensor.graph.replace.graph_replace(hess, {x: x0}) + + # Full log(p(x | y, params)) using the Laplace approximation (up to a constant) + _, logdetQ = pt.nlinalg.slogdet(Q) + conditional_gaussian_approx = ( + -0.5 * x.T @ (-hess + Q) @ x + x.T @ (Q @ mu + jac - hess @ x0) + 0.5 * logdetQ + ) + + # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is + # far from the mode x0 or in a neighbourhood which results in poor convergence. + return pytensor.function(args, pm.MvNormal(mu=x0, tau=Q-hess)) + + +def laplace_draws_to_inferencedata( + posterior_draws: list[np.ndarray[float | int]], model: pm.Model | None = None +) -> az.InferenceData: + """ + Convert draws from a posterior estimated with the Laplace approximation to an InferenceData object. + + + Parameters + ---------- + posterior_draws: list of np.ndarray + A list of arrays containing the posterior draws. Each array should have shape (chains, draws, *shape), where + shape is the shape of the variable in the posterior. + model: Model, optional + A PyMC model. If None, the model is taken from the current model context. + + Returns + ------- + idata: az.InferenceData + An InferenceData object containing the approximated posterior samples + """ + model = pm.modelcontext(model) + chains, draws, *_ = posterior_draws[0].shape + + def make_rv_coords(name): + coords = {"chain": range(chains), "draw": range(draws)} + extra_dims = model.named_vars_to_dims.get(name) + if extra_dims is None: + return coords + return coords | {dim: list(model.coords[dim]) for dim in extra_dims} + + def make_rv_dims(name): + dims = ["chain", "draw"] + extra_dims = model.named_vars_to_dims.get(name) + if extra_dims is None: + return dims + return dims + list(extra_dims) + + names = [ + x.name for x in get_default_varnames(model.unobserved_value_vars, include_transformed=False) + ] + idata = { + name: xr.DataArray( + data=draws, + coords=make_rv_coords(name), + dims=make_rv_dims(name), + name=name, + ) + for name, draws in zip(names, posterior_draws) + } + + coords, dims = coords_and_dims_for_inferencedata(model) + idata = az.convert_to_inference_data(idata, coords=coords, dims=dims) + + return idata + + +def add_fit_to_inferencedata( + idata: az.InferenceData, mu: RaveledVars, H_inv: np.ndarray, model: pm.Model | None = None +) -> az.InferenceData: + """ + Add the mean vector and covariance matrix of the Laplace approximation to an InferenceData object. + + + Parameters + ---------- + idata: az.InfereceData + An InferenceData object containing the approximated posterior samples. + mu: RaveledVars + The MAP estimate of the model parameters. + H_inv: np.ndarray + The inverse Hessian matrix of the log-posterior evaluated at the MAP estimate. + model: Model, optional + A PyMC model. If None, the model is taken from the current model context. + + Returns + ------- + idata: az.InferenceData + The provided InferenceData, with the mean vector and covariance matrix added to the "fit" group. + """ + model = pm.modelcontext(model) + coords = model.coords + + variable_names, *_ = zip(*mu.point_map_info) + + def make_unpacked_variable_names(name): + value_to_dim = { + x.name: model.named_vars_to_dims.get(model.values_to_rvs[x].name, None) + for x in model.value_vars + } + value_to_dim = {k: v for k, v in value_to_dim.items() if v is not None} + + rv_to_dim = model.named_vars_to_dims + dims_dict = rv_to_dim | value_to_dim + + dims = dims_dict.get(name) + if dims is None: + return [name] + labels = product(*(coords[dim] for dim in dims)) + return [f"{name}[{','.join(map(str, label))}]" for label in labels] + + unpacked_variable_names = reduce( + lambda lst, name: lst + make_unpacked_variable_names(name), variable_names, [] + ) + + mean_dataarray = xr.DataArray(mu.data, dims=["rows"], coords={"rows": unpacked_variable_names}) + cov_dataarray = xr.DataArray( + H_inv, + dims=["rows", "columns"], + coords={"rows": unpacked_variable_names, "columns": unpacked_variable_names}, + ) + + dataset = xr.Dataset({"mean_vector": mean_dataarray, "covariance_matrix": cov_dataarray}) + idata.add_groups(fit=dataset) + + return idata + + +def add_data_to_inferencedata( + idata: az.InferenceData, + progressbar: bool = True, + model: pm.Model | None = None, + compile_kwargs: dict | None = None, +) -> az.InferenceData: + """ + Add observed and constant data to an InferenceData object. + + Parameters + ---------- + idata: az.InferenceData + An InferenceData object containing the approximated posterior samples. + progressbar: bool + Whether to display a progress bar during computations. Default is True. + model: Model, optional + A PyMC model. If None, the model is taken from the current model context. + compile_kwargs: dict, optional + Additional keyword arguments to pass to pytensor.function. + + Returns + ------- + idata: az.InferenceData + The provided InferenceData, with observed and constant data added. + """ + model = pm.modelcontext(model) + + if model.deterministics: + idata.posterior = pm.compute_deterministics( + idata.posterior, + model=model, + merge_dataset=True, + progressbar=progressbar, + compile_kwargs=compile_kwargs, + ) + + coords, dims = coords_and_dims_for_inferencedata(model) + + observed_data = dict_to_dataset( + find_observations(model), + library=pm, + coords=coords, + dims=dims, + default_dims=[], + ) + + constant_data = dict_to_dataset( + find_constants(model), + library=pm, + coords=coords, + dims=dims, + default_dims=[], + ) + + idata.add_groups( + {"observed_data": observed_data, "constant_data": constant_data}, + coords=coords, + dims=dims, + ) + + return idata + + +def fit_mvn_at_MAP( + optimized_point: dict[str, np.ndarray], + model: pm.Model | None = None, + on_bad_cov: Literal["warn", "error", "ignore"] = "ignore", + transform_samples: bool = False, + gradient_backend: GradientBackend = "pytensor", + zero_tol: float = 1e-8, + diag_jitter: float | None = 1e-8, + compile_kwargs: dict | None = None, +) -> tuple[RaveledVars, np.ndarray]: + """ + Create a multivariate normal distribution using the inverse of the negative Hessian matrix of the log-posterior + evaluated at the MAP estimate. This is the basis of the Laplace approximation. + + Parameters + ---------- + optimized_point : dict[str, np.ndarray] + Local maximum a posteriori (MAP) point returned from pymc.find_MAP or jax_tools.fit_map + model : Model, optional + A PyMC model. If None, the model is taken from the current model context. + on_bad_cov : str, one of 'ignore', 'warn', or 'error', default: 'ignore' + What to do when ``H_inv`` (inverse Hessian) is not positive semi-definite. + If 'ignore' or 'warn', the closest positive-semi-definite matrix to ``H_inv`` (in L1 norm) will be returned. + If 'error', an error will be raised. + transform_samples : bool + Whether to transform the samples back to the original parameter space. Default is True. + gradient_backend: str, default "pytensor" + The backend to use for gradient computations. Must be one of "pytensor" or "jax". + zero_tol: float + Value below which an element of the Hessian matrix is counted as 0. + This is used to stabilize the computation of the inverse Hessian matrix. Default is 1e-8. + diag_jitter: float | None + A small value added to the diagonal of the inverse Hessian matrix to ensure it is positive semi-definite. + If None, no jitter is added. Default is 1e-8. + compile_kwargs: dict, optional + Additional keyword arguments to pass to pytensor.function when compiling loss functions + + Returns + ------- + map_estimate: RaveledVars + The MAP estimate of the model parameters, raveled into a 1D array. + + inverse_hessian: np.ndarray + The inverse Hessian matrix of the log-posterior evaluated at the MAP estimate. + """ + if gradient_backend == "jax" and not find_spec("jax"): + raise ImportError("JAX must be installed to use JAX gradients") + + model = pm.modelcontext(model) + compile_kwargs = {} if compile_kwargs is None else compile_kwargs + frozen_model = freeze_dims_and_data(model) + + if not transform_samples: + untransformed_model = remove_value_transforms(frozen_model) + logp = untransformed_model.logp(jacobian=False) + variables = untransformed_model.continuous_value_vars + else: + logp = frozen_model.logp(jacobian=True) + variables = frozen_model.continuous_value_vars + + variable_names = {var.name for var in variables} + optimized_free_params = {k: v for k, v in optimized_point.items() if k in variable_names} + mu = DictToArrayBijection.map(optimized_free_params) + + _, f_hess, _ = scipy_optimize_funcs_from_loss( + loss=-logp, + inputs=variables, + initial_point_dict=optimized_free_params, + use_grad=True, + use_hess=True, + use_hessp=False, + gradient_backend=gradient_backend, + compile_kwargs=compile_kwargs, + ) + + H = -f_hess(mu.data) + if H.ndim == 1: + H = np.expand_dims(H, axis=1) + H_inv = np.linalg.pinv(np.where(np.abs(H) < zero_tol, 0, -H)) + + def stabilize(x, jitter): + return x + np.eye(x.shape[0]) * jitter + + H_inv = H_inv if diag_jitter is None else stabilize(H_inv, diag_jitter) + + try: + np.linalg.cholesky(H_inv) + except np.linalg.LinAlgError: + if on_bad_cov == "error": + raise np.linalg.LinAlgError( + "Inverse Hessian not positive-semi definite at the provided point" + ) + H_inv = get_nearest_psd(H_inv) + if on_bad_cov == "warn": + _log.warning( + "Inverse Hessian is not positive semi-definite at the provided point, using the closest PSD " + "matrix in L1-norm instead" + ) + + return mu, H_inv + + +def sample_laplace_posterior( + mu: RaveledVars, + H_inv: np.ndarray, + model: pm.Model | None = None, + chains: int = 2, + draws: int = 500, + transform_samples: bool = False, + progressbar: bool = True, + random_seed: int | np.random.Generator | None = None, + compile_kwargs: dict | None = None, +) -> az.InferenceData: + """ + Generate samples from a multivariate normal distribution with mean `mu` and inverse covariance matrix `H_inv`. + + Parameters + ---------- + mu: RaveledVars + The MAP estimate of the model parameters. + H_inv: np.ndarray + The inverse Hessian matrix of the log-posterior evaluated at the MAP estimate. + model : Model + A PyMC model + chains : int + The number of sampling chains running in parallel. Default is 2. + draws : int + The number of samples to draw from the approximated posterior. Default is 500. + transform_samples : bool + Whether to transform the samples back to the original parameter space. Default is True. + progressbar : bool + Whether to display a progress bar during computations. Default is True. + random_seed: int | np.random.Generator | None + Seed for the random number generator or a numpy Generator for reproducibility + + Returns + ------- + idata: az.InferenceData + An InferenceData object containing the approximated posterior samples. + """ + model = pm.modelcontext(model) + compile_kwargs = {} if compile_kwargs is None else compile_kwargs + rng = np.random.default_rng(random_seed) + + posterior_dist = stats.multivariate_normal( + mean=mu.data, cov=H_inv, allow_singular=True, seed=rng + ) + + posterior_draws = posterior_dist.rvs(size=(chains, draws)) + if mu.data.shape == (1,): + posterior_draws = np.expand_dims(posterior_draws, -1) + + if transform_samples: + constrained_rvs, unconstrained_vector = _unconstrained_vector_to_constrained_rvs(model) + batched_values = pt.tensor( + "batched_values", + shape=(chains, draws, *unconstrained_vector.type.shape), + dtype=unconstrained_vector.type.dtype, + ) + batched_rvs = pytensor.graph.vectorize_graph( + constrained_rvs, replace={unconstrained_vector: batched_values} + ) + + f_constrain = pm.compile(inputs=[batched_values], outputs=batched_rvs, **compile_kwargs) + posterior_draws = f_constrain(posterior_draws) + + else: + info = mu.point_map_info + flat_shapes = [size for _, _, size, _ in info] + slices = [ + slice(sum(flat_shapes[:i]), sum(flat_shapes[: i + 1])) for i in range(len(flat_shapes)) + ] + + posterior_draws = [ + posterior_draws[..., idx].reshape((chains, draws, *shape)).astype(dtype) + for idx, (name, shape, _, dtype) in zip(slices, info) + ] + + idata = laplace_draws_to_inferencedata(posterior_draws, model) + idata = add_fit_to_inferencedata(idata, mu, H_inv) + idata = add_data_to_inferencedata(idata, progressbar, model, compile_kwargs) + + return idata + + +def fit_laplace( + optimize_method: minimize_method | Literal["basinhopping"] = "BFGS", + *, + model: pm.Model | None = None, + use_grad: bool | None = None, + use_hessp: bool | None = None, + use_hess: bool | None = None, + initvals: dict | None = None, + random_seed: int | np.random.Generator | None = None, + return_raw: bool = False, + jitter_rvs: list[pt.TensorVariable] | None = None, + progressbar: bool = True, + include_transformed: bool = True, + gradient_backend: GradientBackend = "pytensor", + chains: int = 2, + draws: int = 500, + on_bad_cov: Literal["warn", "error", "ignore"] = "ignore", + fit_in_unconstrained_space: bool = False, + zero_tol: float = 1e-8, + diag_jitter: float | None = 1e-8, + optimizer_kwargs: dict | None = None, + compile_kwargs: dict | None = None, +) -> az.InferenceData: + """ + Create a Laplace (quadratic) approximation for a posterior distribution. + + This function generates a Laplace approximation for a given posterior distribution using a specified + number of draws. This is useful for obtaining a parametric approximation to the posterior distribution + that can be used for further analysis. + + Parameters + ---------- + model : pm.Model + The PyMC model to be fit. If None, the current model context is used. + method : str + The optimization method to use. Valid choices are: Nelder-Mead, Powell, CG, BFGS, L-BFGS-B, TNC, SLSQP, + trust-constr, dogleg, trust-ncg, trust-exact, trust-krylov, and basinhopping. + + See scipy.optimize.minimize documentation for details. + use_grad : bool | None, optional + Whether to use gradients in the optimization. Defaults to None, which determines this automatically based on + the ``method``. + use_hessp : bool | None, optional + Whether to use Hessian-vector products in the optimization. Defaults to None, which determines this automatically based on + the ``method``. + use_hess : bool | None, optional + Whether to use the Hessian matrix in the optimization. Defaults to None, which determines this automatically based on + the ``method``. + initvals : None | dict, optional + Initial values for the model parameters, as str:ndarray key-value pairs. Paritial initialization is permitted. + If None, the model's default initial values are used. + random_seed : None | int | np.random.Generator, optional + Seed for the random number generator or a numpy Generator for reproducibility + return_raw: bool | False, optinal + Whether to also return the full output of `scipy.optimize.minimize` + jitter_rvs : list of TensorVariables, optional + Variables whose initial values should be jittered. If None, all variables are jittered. + progressbar : bool, optional + Whether to display a progress bar during optimization. Defaults to True. + fit_in_unconstrained_space: bool, default False + Whether to fit the Laplace approximation in the unconstrained parameter space. If True, samples will be drawn + from a mean and covariance matrix computed at a point in the **unconstrained** parameter space. Samples will + then be transformed back to the original parameter space. This will guarantee that the samples will respect + the domain of prior distributions (for exmaple, samples from a Beta distribution will be strictly between 0 + and 1). + + .. warning:: + This argument should be considered highly experimental. It has not been verified if this method produces + valid draws from the posterior. **Use at your own risk**. + + gradient_backend: str, default "pytensor" + The backend to use for gradient computations. Must be one of "pytensor" or "jax". + chains: int, default: 2 + The number of chain dimensions to sample. Note that this is *not* the number of chains to run in parallel, + because the Laplace approximation is not an MCMC method. This argument exists to ensure that outputs are + compatible with the ArviZ library. + draws: int, default: 500 + The number of samples to draw from the approximated posterior. Totals samples will be chains * draws. + on_bad_cov : str, one of 'ignore', 'warn', or 'error', default: 'ignore' + What to do when ``H_inv`` (inverse Hessian) is not positive semi-definite. + If 'ignore' or 'warn', the closest positive-semi-definite matrix to ``H_inv`` (in L1 norm) will be returned. + If 'error', an error will be raised. + zero_tol: float + Value below which an element of the Hessian matrix is counted as 0. + This is used to stabilize the computation of the inverse Hessian matrix. Default is 1e-8. + diag_jitter: float | None + A small value added to the diagonal of the inverse Hessian matrix to ensure it is positive semi-definite. + If None, no jitter is added. Default is 1e-8. + optimizer_kwargs + Additional keyword arguments to pass to the ``scipy.optimize`` function being used. Unless + ``method = "basinhopping"``, ``scipy.optimize.minimize`` will be used. For ``basinhopping``, + ``scipy.optimize.basinhopping`` will be used. See the documentation of these functions for details. + compile_kwargs: dict, optional + Additional keyword arguments to pass to pytensor.function. + + Returns + ------- + :class:`~arviz.InferenceData` + An InferenceData object containing the approximated posterior samples. + + Examples + -------- + >>> from pymc_extras.inference.laplace import fit_laplace + >>> import numpy as np + >>> import pymc as pm + >>> import arviz as az + >>> y = np.array([2642, 3503, 4358]*10) + >>> with pm.Model() as m: + >>> logsigma = pm.Uniform("logsigma", 1, 100) + >>> mu = pm.Uniform("mu", -10000, 10000) + >>> yobs = pm.Normal("y", mu=mu, sigma=pm.math.exp(logsigma), observed=y) + >>> idata = fit_laplace() + + Notes + ----- + This method of approximation may not be suitable for all types of posterior distributions, + especially those with significant skewness or multimodality. + + See Also + -------- + fit : Calling the inference function 'fit' like pmx.fit(method="laplace", model=m) + will forward the call to 'fit_laplace'. + + """ + compile_kwargs = {} if compile_kwargs is None else compile_kwargs + optimizer_kwargs = {} if optimizer_kwargs is None else optimizer_kwargs + + optimized_point = find_MAP( + method=optimize_method, + model=model, + use_grad=use_grad, + use_hessp=use_hessp, + use_hess=use_hess, + initvals=initvals, + random_seed=random_seed, + return_raw=return_raw, + jitter_rvs=jitter_rvs, + progressbar=progressbar, + include_transformed=include_transformed, + gradient_backend=gradient_backend, + compile_kwargs=compile_kwargs, + **optimizer_kwargs, + ) + + mu, H_inv = fit_mvn_at_MAP( + optimized_point=optimized_point, + model=model, + on_bad_cov=on_bad_cov, + transform_samples=fit_in_unconstrained_space, + gradient_backend=gradient_backend, + zero_tol=zero_tol, + diag_jitter=diag_jitter, + compile_kwargs=compile_kwargs, + ) + + return sample_laplace_posterior( + mu=mu, + H_inv=H_inv, + model=model, + chains=chains, + draws=draws, + transform_samples=fit_in_unconstrained_space, + progressbar=progressbar, + random_seed=random_seed, + compile_kwargs=compile_kwargs, + ) From c32652511c9bbb161c8dd482660a26f2cff7105c Mon Sep 17 00:00:00 2001 From: Michal-Novomestsky Date: Wed, 2 Jul 2025 17:28:48 +1000 Subject: [PATCH 02/21] added seperate line for evaluating Q-hess --- pymc_extras/inference/laplace.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pymc_extras/inference/laplace.py b/pymc_extras/inference/laplace.py index 1b9f3048..996f5ac0 100644 --- a/pymc_extras/inference/laplace.py +++ b/pymc_extras/inference/laplace.py @@ -143,13 +143,16 @@ def get_conditional_gaussian_approximation( # Full log(p(x | y, params)) using the Laplace approximation (up to a constant) _, logdetQ = pt.nlinalg.slogdet(Q) - conditional_gaussian_approx = ( - -0.5 * x.T @ (-hess + Q) @ x + x.T @ (Q @ mu + jac - hess @ x0) + 0.5 * logdetQ - ) + # conditional_gaussian_approx = ( + # -0.5 * x.T @ (-hess + Q) @ x + x.T @ (Q @ mu + jac - hess @ x0) + 0.5 * logdetQ + # ) + + # In the future, this could be made more efficient with only adding the diagonal of -hess + tau = Q - hess # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is # far from the mode x0 or in a neighbourhood which results in poor convergence. - return pytensor.function(args, pm.MvNormal(mu=x0, tau=Q-hess)) + return pytensor.function(args, [x0, pm.MvNormal(mu=x0, tau=tau)]) def laplace_draws_to_inferencedata( From 61d4d89635f8a2cd002e4b3b765c4120af9a37ca Mon Sep 17 00:00:00 2001 From: Michal-Novomestsky Date: Fri, 4 Jul 2025 16:15:36 +1000 Subject: [PATCH 03/21] WIP: minor refactor --- pymc_extras/inference/laplace.py | 20 +++++++++++++------ .../inference/laplace_approx/test_laplace.py | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pymc_extras/inference/laplace.py b/pymc_extras/inference/laplace.py index 996f5ac0..11858c27 100644 --- a/pymc_extras/inference/laplace.py +++ b/pymc_extras/inference/laplace.py @@ -121,11 +121,13 @@ def get_conditional_gaussian_approximation( # f = log(p(y | x, params)) f_x = model.logp() - jac = pytensor.gradient.grad(f_x, x) - hess = pytensor.gradient.jacobian(jac.flatten(), x) + # jac = pytensor.gradient.grad(f_x, x) + # hess = pytensor.gradient.jacobian(jac.flatten(), x) # log(p(x | y, params)) only including terms that depend on x for the minimization step (logdet(Q) ignored as it is a constant wrt x) - log_x_posterior = f_x - 0.5 * (x - mu).T @ Q @ (x - mu) + log_x_posterior = f_x - 0.5 * (x - mu).T @ Q @ ( + x - mu + ) # TODO could be f + x.logp - IS X.LOGP DUPLICATED IN F? # Maximize log(p(x | y, params)) wrt x to find mode x0 x0, _ = minimize( @@ -138,11 +140,13 @@ def get_conditional_gaussian_approximation( ) # require f'(x0) and f''(x0) for Laplace approx - jac = pytensor.graph.replace.graph_replace(jac, {x: x0}) + # jac = pytensor.graph.replace.graph_replace(jac, {x: x0}) + jac = pytensor.gradient.grad(f_x, x) + hess = pytensor.gradient.jacobian(jac.flatten(), x) hess = pytensor.graph.replace.graph_replace(hess, {x: x0}) # Full log(p(x | y, params)) using the Laplace approximation (up to a constant) - _, logdetQ = pt.nlinalg.slogdet(Q) + # _, logdetQ = pt.nlinalg.slogdet(Q) # conditional_gaussian_approx = ( # -0.5 * x.T @ (-hess + Q) @ x + x.T @ (Q @ mu + jac - hess @ x0) + 0.5 * logdetQ # ) @@ -152,7 +156,11 @@ def get_conditional_gaussian_approximation( # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is # far from the mode x0 or in a neighbourhood which results in poor convergence. - return pytensor.function(args, [x0, pm.MvNormal(mu=x0, tau=tau)]) + return ( + x0, + pm.MvNormal(f"{x.name}_laplace_approx", mu=x0, tau=tau), + tau, + ) # pytensor.function(args, [x0, pm.MvNormal(mu=x0, tau=tau)]) def laplace_draws_to_inferencedata( diff --git a/tests/inference/laplace_approx/test_laplace.py b/tests/inference/laplace_approx/test_laplace.py index 6196673b..fde2c956 100644 --- a/tests/inference/laplace_approx/test_laplace.py +++ b/tests/inference/laplace_approx/test_laplace.py @@ -363,7 +363,7 @@ def test_get_conditional_gaussian_approximation(): Q = pm.MvNormal("Q", mu=Q_mu, cov=Q_cov) # Pytensor currently doesn't support autograd for pt inverses, so we use a numeric Q instead - x = pm.MvNormal("x", mu=mu_param, cov=np.linalg.inv(Q_val)) + x = pm.MvNormal("x", mu=mu_param, tau=Q) # cov=np.linalg.inv(Q_val)) y = pm.MvNormal( "y", From 1960cb9306b708f58583efee6624ddd3163a41fe Mon Sep 17 00:00:00 2001 From: Michal Novomestsky Date: Sun, 6 Jul 2025 21:11:37 +1000 Subject: [PATCH 04/21] started writing fit_INLA routine --- pymc_extras/inference/fit.py | 14 +- pymc_extras/inference/inla.py | 164 ++++++++++++++++++ pymc_extras/inference/laplace.py | 111 ------------ .../inference/laplace_approx/test_laplace.py | 89 +--------- tests/test_inla.py | 105 +++++++++++ 5 files changed, 284 insertions(+), 199 deletions(-) create mode 100644 pymc_extras/inference/inla.py create mode 100644 tests/test_inla.py diff --git a/pymc_extras/inference/fit.py b/pymc_extras/inference/fit.py index ac51e76b..8814ba3b 100644 --- a/pymc_extras/inference/fit.py +++ b/pymc_extras/inference/fit.py @@ -36,7 +36,17 @@ def fit(method: str, **kwargs) -> az.InferenceData: return fit_pathfinder(**kwargs) - if method == "laplace": - from pymc_extras.inference import fit_laplace + elif method == "laplace": + from pymc_extras.inference.laplace import fit_laplace return fit_laplace(**kwargs) + + elif method == "INLA": + from pymc_extras.inference.laplace import fit_INLA + + return fit_INLA(**kwargs) + + else: + raise ValueError( + f"method '{method}' not supported. Use one of 'pathfinder', 'laplace' or 'INLA'." + ) diff --git a/pymc_extras/inference/inla.py b/pymc_extras/inference/inla.py new file mode 100644 index 00000000..0eaa649c --- /dev/null +++ b/pymc_extras/inference/inla.py @@ -0,0 +1,164 @@ +import arviz as az +import numpy as np +import pymc as pm +import pytensor +import pytensor.tensor as pt + +from better_optimize.constants import minimize_method +from numpy.typing import ArrayLike +from pytensor.tensor import TensorVariable +from pytensor.tensor.optimize import minimize + + +def get_conditional_gaussian_approximation( + x: TensorVariable, + Q: TensorVariable | ArrayLike, + mu: TensorVariable | ArrayLike, + model: pm.Model | None = None, + method: minimize_method = "BFGS", + use_jac: bool = True, + use_hess: bool = False, + optimizer_kwargs: dict | None = None, +) -> list[TensorVariable]: + """ + Returns an estimate the a posteriori probability of a latent Gaussian field x and its mode x0 using the Laplace approximation. + + That is: + y | x, sigma ~ N(Ax, sigma^2 W) + x | params ~ N(mu, Q(params)^-1) + + We seek to estimate p(x | y, params) with a Gaussian: + + log(p(x | y, params)) = log(p(y | x, params)) + log(p(x | params)) + const + + Let f(x) = log(p(y | x, params)). From the definition of our model above, we have log(p(x | params)) = -0.5*(x - mu).T Q (x - mu) + 0.5*logdet(Q). + + This gives log(p(x | y, params)) = f(x) - 0.5*(x - mu).T Q (x - mu) + 0.5*logdet(Q). We will estimate this using the Laplace approximation by Taylor expanding f(x) about the mode. + + Thus: + + 1. Maximize log(p(x | y, params)) = f(x) - 0.5*(x - mu).T Q (x - mu) wrt x (note that logdet(Q) does not depend on x) to find the mode x0. + + 2. Use the Laplace approximation expanded about the mode: p(x | y, params) ~= N(mu=x0, tau=Q - f''(x0)). + + Parameters + ---------- + x: TensorVariable + The parameter with which to maximize wrt (that is, find the mode in x). In INLA, this is the latent Gaussian field x~N(mu,Q^-1). + Q: TensorVariable | ArrayLike + The precision matrix of the latent field x. + mu: TensorVariable | ArrayLike + The mean of the latent field x. + model: Model + PyMC model to use. + method: minimize_method + Which minimization algorithm to use. + use_jac: bool + If true, the minimizer will compute the gradient of log(p(x | y, params)). + use_hess: bool + If true, the minimizer will compute the Hessian log(p(x | y, params)). + optimizer_kwargs: dict + Kwargs to pass to scipy.optimize.minimize. + + Returns + ------- + x0, p(x | y, params): list[TensorVariable] + Mode and Laplace approximation for posterior. + """ + model = pm.modelcontext(model) + + # f = log(p(y | x, params)) + f_x = model.logp() + + # log(p(x | y, params)) only including terms that depend on x for the minimization step (logdet(Q) ignored as it is a constant wrt x) + log_x_posterior = f_x - 0.5 * (x - mu).T @ Q @ (x - mu) + + # Maximize log(p(x | y, params)) wrt x to find mode x0 + x0, _ = minimize( + objective=-log_x_posterior, + x=x, + method=method, + jac=use_jac, + hess=use_hess, + optimizer_kwargs=optimizer_kwargs, + ) + + # require f''(x0) for Laplace approx + hess = pytensor.gradient.hessian(f_x, x) + hess = pytensor.graph.replace.graph_replace(hess, {x: x0}) + + # Could be made more efficient with adding diagonals only + tau = Q - hess + + # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is + # far from the mode x0 or in a neighbourhood which results in poor convergence. + return x0, pm.MvNormal(f"{x.name}_laplace_approx", mu=x0, tau=tau) + + +def get_log_marginal_likelihood( + x: TensorVariable, + Q: TensorVariable | ArrayLike, + mu: TensorVariable | ArrayLike, + model: pm.Model | None = None, + method: minimize_method = "BFGS", + use_jac: bool = True, + use_hess: bool = False, + optimizer_kwargs: dict | None = None, +) -> TensorVariable: + model = pm.modelcontext(model) + + x0, laplace_approx = get_conditional_gaussian_approximation( + x, Q, mu, model, method, use_jac, use_hess, optimizer_kwargs + ) + log_laplace_approx = pm.logp(laplace_approx, model.rvs_to_values[x]) + + _, logdetQ = pt.nlinalg.slogdet(Q) + log_x_likelihood = ( + -0.5 * (x - mu).T @ Q @ (x - mu) + 0.5 * logdetQ - 0.5 * x.shape[0] * np.log(2 * np.pi) + ) + + log_likelihood = ( # logp(y | params) = + model.logp() # logp(y | x, params) + + log_x_likelihood # * logp(x | params) + - log_laplace_approx # / logp(x | y, params) + ) + + return log_likelihood + + +def fit_INLA( + x: TensorVariable, + Q: TensorVariable | ArrayLike, + mu: TensorVariable | ArrayLike, + model: pm.Model | None = None, + method: minimize_method = "BFGS", + use_jac: bool = True, + use_hess: bool = False, + optimizer_kwargs: dict | None = None, +) -> az.InferenceData: + model = pm.modelcontext(model) + + # logp(y | params) + log_likelihood = get_log_marginal_likelihood( + x, Q, mu, model, method, use_jac, use_hess, optimizer_kwargs + ) + + # TODO How to obtain prior? It can parametrise Q, mu, y, etc. Not sure if we could extract from model.logp somehow. Otherwise simply specify as a user input + prior = None + params = None + log_prior = pm.logp(prior, model.rvs_to_values[params]) + + # logp(params | y) = logp(y | params) + logp(params) + const + log_posterior = log_likelihood + log_prior + + # TODO log_marginal_x_likelihood is almost the same as log_likelihood, but need to do some sampling? + log_marginal_x_likelihood = None + log_marginal_x_posterior = log_marginal_x_likelihood + log_prior + + # TODO can we sample over log likelihoods? + # Marginalize params + idata_params = log_posterior.sample() # TODO something like NUTS, QMC, etc.? + idata_x = log_marginal_x_posterior.sample() + + # Bundle up idatas somehow + return idata_params, idata_x diff --git a/pymc_extras/inference/laplace.py b/pymc_extras/inference/laplace.py index 11858c27..9c0a0d27 100644 --- a/pymc_extras/inference/laplace.py +++ b/pymc_extras/inference/laplace.py @@ -15,7 +15,6 @@ import logging -from collections.abc import Callable from functools import reduce from importlib.util import find_spec from itertools import product @@ -30,7 +29,6 @@ from arviz import dict_to_dataset from better_optimize.constants import minimize_method -from numpy.typing import ArrayLike from pymc import DictToArrayBijection from pymc.backends.arviz import ( coords_and_dims_for_inferencedata, @@ -41,8 +39,6 @@ from pymc.model.transform.conditioning import remove_value_transforms from pymc.model.transform.optimization import freeze_dims_and_data from pymc.util import get_default_varnames -from pytensor.tensor import TensorVariable -from pytensor.tensor.optimize import minimize from scipy import stats from pymc_extras.inference.find_map import ( @@ -56,113 +52,6 @@ _log = logging.getLogger(__name__) -def get_conditional_gaussian_approximation( - x: TensorVariable, - Q: TensorVariable | ArrayLike, - mu: TensorVariable | ArrayLike, - args: list[TensorVariable] | None = None, - model: pm.Model | None = None, - method: minimize_method = "BFGS", - use_jac: bool = True, - use_hess: bool = False, - optimizer_kwargs: dict | None = None, -) -> Callable: - """ - Returns a function to estimate the a posteriori log probability of a latent Gaussian field x and its mode x0 using the Laplace approximation. - - That is: - y | x, sigma ~ N(Ax, sigma^2 W) - x | params ~ N(mu, Q(params)^-1) - - We seek to estimate log(p(x | y, params)): - - log(p(x | y, params)) = log(p(y | x, params)) + log(p(x | params)) + const - - Let f(x) = log(p(y | x, params)). From the definition of our model above, we have log(p(x | params)) = -0.5*(x - mu).T Q (x - mu) + 0.5*logdet(Q). - - This gives log(p(x | y, params)) = f(x) - 0.5*(x - mu).T Q (x - mu) + 0.5*logdet(Q). We will estimate this using the Laplace approximation by Taylor expanding f(x) about the mode. - - Thus: - - 1. Maximize log(p(x | y, params)) = f(x) - 0.5*(x - mu).T Q (x - mu) wrt x (note that logdet(Q) does not depend on x) to find the mode x0. - - 2. Substitute x0 into the Laplace approximation expanded about the mode: log(p(x | y, params)) ~= -0.5*x.T (-f''(x0) + Q) x + x.T (Q.mu + f'(x0) - f''(x0).x0) + 0.5*logdet(Q). - - Parameters - ---------- - x: TensorVariable - The parameter with which to maximize wrt (that is, find the mode in x). In INLA, this is the latent field x~N(mu,Q^-1). - Q: TensorVariable | ArrayLike - The precision matrix of the latent field x. - mu: TensorVariable | ArrayLike - The mean of the latent field x. - args: list[TensorVariable] - Args to supply to the compiled function. That is, (x0, logp) = f(x, *args). If set to None, assumes the model RVs are args. - model: Model - PyMC model to use. - method: minimize_method - Which minimization algorithm to use. - use_jac: bool - If true, the minimizer will compute the gradient of log(p(x | y, params)). - use_hess: bool - If true, the minimizer will compute the Hessian log(p(x | y, params)). - optimizer_kwargs: dict - Kwargs to pass to scipy.optimize.minimize. - - Returns - ------- - f: Callable - A function which accepts a value of x and args and returns [x0, log(p(x | y, params))], where x0 is the mode. x is currently both the point at which to evaluate logp and the initial guess for the minimizer. - """ - model = pm.modelcontext(model) - - if args is None: - args = model.continuous_value_vars + model.discrete_value_vars - - # f = log(p(y | x, params)) - f_x = model.logp() - # jac = pytensor.gradient.grad(f_x, x) - # hess = pytensor.gradient.jacobian(jac.flatten(), x) - - # log(p(x | y, params)) only including terms that depend on x for the minimization step (logdet(Q) ignored as it is a constant wrt x) - log_x_posterior = f_x - 0.5 * (x - mu).T @ Q @ ( - x - mu - ) # TODO could be f + x.logp - IS X.LOGP DUPLICATED IN F? - - # Maximize log(p(x | y, params)) wrt x to find mode x0 - x0, _ = minimize( - objective=-log_x_posterior, - x=x, - method=method, - jac=use_jac, - hess=use_hess, - optimizer_kwargs=optimizer_kwargs, - ) - - # require f'(x0) and f''(x0) for Laplace approx - # jac = pytensor.graph.replace.graph_replace(jac, {x: x0}) - jac = pytensor.gradient.grad(f_x, x) - hess = pytensor.gradient.jacobian(jac.flatten(), x) - hess = pytensor.graph.replace.graph_replace(hess, {x: x0}) - - # Full log(p(x | y, params)) using the Laplace approximation (up to a constant) - # _, logdetQ = pt.nlinalg.slogdet(Q) - # conditional_gaussian_approx = ( - # -0.5 * x.T @ (-hess + Q) @ x + x.T @ (Q @ mu + jac - hess @ x0) + 0.5 * logdetQ - # ) - - # In the future, this could be made more efficient with only adding the diagonal of -hess - tau = Q - hess - - # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is - # far from the mode x0 or in a neighbourhood which results in poor convergence. - return ( - x0, - pm.MvNormal(f"{x.name}_laplace_approx", mu=x0, tau=tau), - tau, - ) # pytensor.function(args, [x0, pm.MvNormal(mu=x0, tau=tau)]) - - def laplace_draws_to_inferencedata( posterior_draws: list[np.ndarray[float | int]], model: pm.Model | None = None ) -> az.InferenceData: diff --git a/tests/inference/laplace_approx/test_laplace.py b/tests/inference/laplace_approx/test_laplace.py index fde2c956..d35b8e82 100644 --- a/tests/inference/laplace_approx/test_laplace.py +++ b/tests/inference/laplace_approx/test_laplace.py @@ -22,7 +22,8 @@ from pymc_extras.inference.laplace_approx.find_map import GradientBackend from pymc_extras.inference.laplace_approx.laplace import ( fit_laplace, - get_conditional_gaussian_approximation, + fit_mvn_at_MAP, + sample_laplace_posterior, ) @@ -317,88 +318,4 @@ def test_laplace_scalar_basinhopping(optimizer_method): assert idata_laplace.fit.mean_vector.shape == (1,) assert idata_laplace.fit.covariance_matrix.shape == (1, 1) - np.testing.assert_allclose( - idata_laplace.posterior.p.mean(dim=["chain", "draw"]), data.mean(), atol=0.1 - ) - - -def test_get_conditional_gaussian_approximation(): - """ - Consider the trivial case of: - - y | x ~ N(x, cov_param) - x | param ~ N(mu_param, Q^-1) - - cov_param ~ N(cov_mu, cov_cov) - mu_param ~ N(mu_mu, mu_cov) - Q ~ N(Q_mu, Q_cov) - - This has an analytic solution at the mode which we can compare against. - """ - rng = np.random.default_rng(12345) - n = 10000 - d = 10 - - # Initialise arrays - mu_true = rng.random(d) - cov_true = np.diag(rng.random(d)) - Q_val = np.diag(rng.random(d)) - cov_param_val = np.diag(rng.random(d)) - - x_val = rng.random(d) - mu_val = rng.random(d) - - mu_mu = rng.random(d) - mu_cov = np.diag(np.ones(d)) - cov_mu = rng.random(d**2) - cov_cov = np.diag(np.ones(d**2)) - Q_mu = rng.random(d**2) - Q_cov = np.diag(np.ones(d**2)) - - with pm.Model() as model: - y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n) - - mu_param = pm.MvNormal("mu_param", mu=mu_mu, cov=mu_cov) - cov_param = pm.MvNormal("cov_param", mu=cov_mu, cov=cov_cov) - Q = pm.MvNormal("Q", mu=Q_mu, cov=Q_cov) - - # Pytensor currently doesn't support autograd for pt inverses, so we use a numeric Q instead - x = pm.MvNormal("x", mu=mu_param, tau=Q) # cov=np.linalg.inv(Q_val)) - - y = pm.MvNormal( - "y", - mu=x, - cov=cov_param.reshape((d, d)), - observed=y_obs, - ) - - # logp(x | y, params) - cga = get_conditional_gaussian_approximation( - x=model.rvs_to_values[x], - Q=Q.reshape((d, d)), - mu=mu_param, - optimizer_kwargs={"tol": 1e-25}, - ) - - x0, log_x_posterior = cga( - x=x_val, mu_param=mu_val, cov_param=cov_param_val.flatten(), Q=Q_val.flatten() - ) - - # Get analytic values of the mode and Laplace-approximated log posterior - cov_param_inv = np.linalg.inv(cov_param_val) - - x0_true = np.linalg.inv(n * cov_param_inv + 2 * Q_val) @ ( - cov_param_inv @ y_obs.sum(axis=0) + 2 * Q_val @ mu_val - ) - - jac_true = cov_param_inv @ (y_obs - x0_true).sum(axis=0) - Q_val @ (x0_true - mu_val) - hess_true = -n * cov_param_inv - Q_val - - log_x_posterior_laplace_true = ( - -0.5 * x_val.T @ (-hess_true + Q_val) @ x_val - + x_val.T @ (Q_val @ mu_val + jac_true - hess_true @ x0_true) - + 0.5 * np.log(np.linalg.det(Q_val)) - ) - - np.testing.assert_allclose(x0, x0_true, atol=0.1, rtol=0.1) - np.testing.assert_allclose(log_x_posterior, log_x_posterior_laplace_true, atol=0.1, rtol=0.1) + np.testing.assert_allclose(idata_laplace.fit.mean_vector.values.item(), data.mean(), atol=0.1) diff --git a/tests/test_inla.py b/tests/test_inla.py new file mode 100644 index 00000000..cda24bb5 --- /dev/null +++ b/tests/test_inla.py @@ -0,0 +1,105 @@ +# Copyright 2024 The PyMC Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import numpy as np +import pymc as pm +import pytensor + +from pymc_extras.inference.inla import get_conditional_gaussian_approximation + + +def test_get_conditional_gaussian_approximation(): + """ + Consider the trivial case of: + + y | x ~ N(x, cov_param) + x | param ~ N(mu_param, Q^-1) + + cov_param ~ N(cov_mu, cov_cov) + mu_param ~ N(mu_mu, mu_cov) + Q ~ N(Q_mu, Q_cov) + + This has an analytic solution at the mode which we can compare against. + """ + rng = np.random.default_rng(12345) + n = 10000 + d = 10 + + # Initialise arrays + mu_true = rng.random(d) + cov_true = np.diag(rng.random(d)) + Q_val = np.diag(rng.random(d)) + cov_param_val = np.diag(rng.random(d)) + + x_val = rng.random(d) + mu_val = rng.random(d) + + mu_mu = rng.random(d) + mu_cov = np.diag(np.ones(d)) + cov_mu = rng.random(d**2) + cov_cov = np.diag(np.ones(d**2)) + Q_mu = rng.random(d**2) + Q_cov = np.diag(np.ones(d**2)) + + with pm.Model() as model: + y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n) + + mu_param = pm.MvNormal("mu_param", mu=mu_mu, cov=mu_cov) + cov_param = pm.MvNormal("cov_param", mu=cov_mu, cov=cov_cov) + Q = pm.MvNormal("Q", mu=Q_mu, cov=Q_cov) + + x = pm.MvNormal("x", mu=mu_param, tau=Q_val) + + y = pm.MvNormal( + "y", + mu=x, + cov=cov_param.reshape((d, d)), + observed=y_obs, + ) + + args = model.continuous_value_vars + model.discrete_value_vars + + # logp(x | y, params) + x0, x_g = get_conditional_gaussian_approximation( + x=model.rvs_to_values[x], + Q=Q.reshape((d, d)), + mu=mu_param, + optimizer_kwargs={"tol": 1e-25}, + ) + + cga = pytensor.function(args, [x0, pm.logp(x_g, model.rvs_to_values[x])]) + + x0, log_x_posterior = cga( + x=x_val, mu_param=mu_val, cov_param=cov_param_val.flatten(), Q=Q_val.flatten() + ) + + # Get analytic values of the mode and Laplace-approximated log posterior + cov_param_inv = np.linalg.inv(cov_param_val) + + x0_true = np.linalg.inv(n * cov_param_inv + 2 * Q_val) @ ( + cov_param_inv @ y_obs.sum(axis=0) + 2 * Q_val @ mu_val + ) + + hess_true = -n * cov_param_inv - Q_val + tau_true = Q_val - hess_true + + log_x_taylor = ( + -0.5 * (x_val - x0_true).T @ tau_true @ (x_val - x0_true) + + 0.5 * np.log(np.linalg.det(tau_true)) + - 0.5 * d * np.log(2 * np.pi) + ) + + np.testing.assert_allclose(x0, x0_true, atol=0.1, rtol=0.1) + np.testing.assert_allclose(log_x_posterior, log_x_taylor, atol=0.1, rtol=0.1) From 6a1d523b5c885b3812be2c6e63334366f22f1f94 Mon Sep 17 00:00:00 2001 From: Michal Novomestsky Date: Sun, 6 Jul 2025 21:43:54 +1000 Subject: [PATCH 05/21] changed minimizer tol to 1e-8 --- tests/test_inla.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_inla.py b/tests/test_inla.py index cda24bb5..58ff9ae1 100644 --- a/tests/test_inla.py +++ b/tests/test_inla.py @@ -76,7 +76,7 @@ def test_get_conditional_gaussian_approximation(): x=model.rvs_to_values[x], Q=Q.reshape((d, d)), mu=mu_param, - optimizer_kwargs={"tol": 1e-25}, + optimizer_kwargs={"tol": 1e-8}, ) cga = pytensor.function(args, [x0, pm.logp(x_g, model.rvs_to_values[x])]) From 674d813a6eac0683b8bd3f063d2012c702bd043e Mon Sep 17 00:00:00 2001 From: Michal Novomestsky Date: Wed, 16 Jul 2025 18:57:56 +1000 Subject: [PATCH 06/21] WIP: MarginalLaplaceRV --- pymc_extras/inference/__init__.py | 3 +- pymc_extras/inference/inla.py | 20 +++++--- pymc_extras/model/marginal/distributions.py | 57 +++++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/pymc_extras/inference/__init__.py b/pymc_extras/inference/__init__.py index a536f91e..19752172 100644 --- a/pymc_extras/inference/__init__.py +++ b/pymc_extras/inference/__init__.py @@ -15,6 +15,7 @@ from pymc_extras.inference.fit import fit from pymc_extras.inference.laplace_approx.find_map import find_MAP from pymc_extras.inference.laplace_approx.laplace import fit_laplace +from pymc_extras.inference.inla import fit_INLA from pymc_extras.inference.pathfinder.pathfinder import fit_pathfinder -__all__ = ["fit", "fit_pathfinder", "fit_laplace", "find_MAP"] +__all__ = ["fit", "fit_pathfinder", "fit_laplace", "find_MAP", "fit_INLA"] diff --git a/pymc_extras/inference/inla.py b/pymc_extras/inference/inla.py index 0eaa649c..3f6db2cf 100644 --- a/pymc_extras/inference/inla.py +++ b/pymc_extras/inference/inla.py @@ -92,7 +92,8 @@ def get_conditional_gaussian_approximation( # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is # far from the mode x0 or in a neighbourhood which results in poor convergence. - return x0, pm.MvNormal(f"{x.name}_laplace_approx", mu=x0, tau=tau) + _, logdetTau = pt.nlinalg.slogdet(tau) + return x0, 0.5 * logdetTau - 0.5 * x0.shape[0] * np.log(2 * np.pi) def get_log_marginal_likelihood( @@ -107,14 +108,17 @@ def get_log_marginal_likelihood( ) -> TensorVariable: model = pm.modelcontext(model) - x0, laplace_approx = get_conditional_gaussian_approximation( + x0, log_laplace_approx = get_conditional_gaussian_approximation( x, Q, mu, model, method, use_jac, use_hess, optimizer_kwargs ) - log_laplace_approx = pm.logp(laplace_approx, model.rvs_to_values[x]) + # log_laplace_approx = pm.logp(laplace_approx, x)#model.rvs_to_values[x]) _, logdetQ = pt.nlinalg.slogdet(Q) + # log_x_likelihood = ( + # -0.5 * (x - mu).T @ Q @ (x - mu) + 0.5 * logdetQ - 0.5 * x.shape[0] * np.log(2 * np.pi) + # ) log_x_likelihood = ( - -0.5 * (x - mu).T @ Q @ (x - mu) + 0.5 * logdetQ - 0.5 * x.shape[0] * np.log(2 * np.pi) + -0.5 * (x0 - mu).T @ Q @ (x0 - mu) + 0.5 * logdetQ - 0.5 * x0.shape[0] * np.log(2 * np.pi) ) log_likelihood = ( # logp(y | params) = @@ -123,7 +127,7 @@ def get_log_marginal_likelihood( - log_laplace_approx # / logp(x | y, params) ) - return log_likelihood + return x0, log_likelihood def fit_INLA( @@ -139,23 +143,25 @@ def fit_INLA( model = pm.modelcontext(model) # logp(y | params) - log_likelihood = get_log_marginal_likelihood( + x0, log_likelihood = get_log_marginal_likelihood( x, Q, mu, model, method, use_jac, use_hess, optimizer_kwargs ) # TODO How to obtain prior? It can parametrise Q, mu, y, etc. Not sure if we could extract from model.logp somehow. Otherwise simply specify as a user input + # Perhaps obtain as RVs which y depends on which aren't x? prior = None params = None log_prior = pm.logp(prior, model.rvs_to_values[params]) # logp(params | y) = logp(y | params) + logp(params) + const log_posterior = log_likelihood + log_prior + log_posterior = pytensor.graph.replace.graph_replace(log_posterior, {x: x0}) # TODO log_marginal_x_likelihood is almost the same as log_likelihood, but need to do some sampling? log_marginal_x_likelihood = None log_marginal_x_posterior = log_marginal_x_likelihood + log_prior - # TODO can we sample over log likelihoods? + # TODO can we sample over log likelihoods?w # Marginalize params idata_params = log_posterior.sample() # TODO something like NUTS, QMC, etc.? idata_x = log_marginal_x_posterior.sample() diff --git a/pymc_extras/model/marginal/distributions.py b/pymc_extras/model/marginal/distributions.py index 86aa5f02..6e08352e 100644 --- a/pymc_extras/model/marginal/distributions.py +++ b/pymc_extras/model/marginal/distributions.py @@ -132,6 +132,10 @@ class MarginalDiscreteMarkovChainRV(MarginalRV): """Base class for Marginalized Discrete Markov Chain RVs""" +class MarginalLaplaceRV(MarginalRV): + """Base class for Marginalized Laplace-Approximated RVs""" + + def get_domain_of_finite_discrete_rv(rv: TensorVariable) -> tuple[int, ...]: op = rv.owner.op dist_params = rv.owner.op.dist_params(rv.owner) @@ -371,3 +375,56 @@ def step_alpha(logp_emission, log_alpha, log_P): warn_non_separable_logp(values) dummy_logps = (DUMMY_ZERO,) * (len(values) - 1) return joint_logp, *dummy_logps + + +@_logprob.register(MarginalLaplaceRV) +def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs): + # Clone the inner RV graph of the Marginalized RV + x, *inner_rvs = inline_ofg_outputs(op, inputs) + + # Obtain the joint_logp graph of the inner RV graph + inner_rv_values = dict(zip(inner_rvs, values)) + marginalized_vv = x.clone() + rv_values = inner_rv_values | {x: marginalized_vv} + logps_dict = conditional_logp(rv_values=rv_values, **kwargs) + + logp = pt.sum( + [pt.sum(logps_dict[k]) for k in logps_dict] + ) # TODO check this gives the proper p(y | x, params) + + import pytensor + + from pytensor.tensor.optimize import minimize + + # Maximize log(p(x | y, params)) wrt x to find mode x0 + x0, _ = minimize( + objective=-logp, + x=marginalized_vv, + method="BFGS", + # jac=use_jac, + # hess=use_hess, + optimizer_kwargs={"tol": 1e-8}, + ) + + # require f''(x0) for Laplace approx + hess = pytensor.gradient.hessian(logp, marginalized_vv) + # hess = pytensor.graph.replace.graph_replace(hess, {marginalized_vv: x0}) + + # Could be made more efficient with adding diagonals only + rng = np.random.default_rng(12345) + d = 3 + Q = np.diag(rng.random(d)) + tau = Q - hess + + # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is + # far from the mode x0 or in a neighbourhood which results in poor convergence. + _, logdetTau = pt.nlinalg.slogdet(tau) + log_laplace_approx = 0.5 * logdetTau - 0.5 * x0.shape[0] * np.log(2 * np.pi) + + # Reduce logp dimensions corresponding to broadcasted variables + # marginalized_logp = logps_dict.pop(marginalized_vv) + joint_logp = logp - log_laplace_approx + + joint_logp = pytensor.graph.replace.graph_replace(joint_logp, {marginalized_vv: x0}) + + return joint_logp # TODO check if pm.sample adds on p(params). Otherwise this is p(y|params) not p(params|y) From 3b5d49cac0bdc78556abae798125935de4832cfe Mon Sep 17 00:00:00 2001 From: Michal-Novomestsky Date: Sat, 19 Jul 2025 21:44:28 +1000 Subject: [PATCH 07/21] WIP: Minimize inside logp --- notebooks/INLA_testing.ipynb | 875 ++++++++++++++++++++ pymc_extras/__init__.py | 2 +- pymc_extras/model/marginal/distributions.py | 28 +- 3 files changed, 900 insertions(+), 5 deletions(-) create mode 100644 notebooks/INLA_testing.ipynb diff --git a/notebooks/INLA_testing.ipynb b/notebooks/INLA_testing.ipynb new file mode 100644 index 00000000..e2c5e27b --- /dev/null +++ b/notebooks/INLA_testing.ipynb @@ -0,0 +1,875 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "ffd6780e-1bfb-42f0-ba6a-055e9ffd1490", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5a2819fd-6e01-47c0-88b2-f2b5e4215b9b", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pymc as pm\n", + "import pytensor.tensor as pt\n", + "\n", + "import pytensor\n", + "from pytensor.tensor.optimize import minimize\n", + "from pymc_extras.inference.inla import *\n", + "\n", + "from pymc.model.fgraph import fgraph_from_model, model_from_fgraph\n", + "from pymc_extras.model.marginal.marginal_model import marginalize" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0ad97d05-f577-4793-ba6c-dd5f1300c022", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ExpandDims{axis=0}.0\n", + "(1, None)\n", + "(1, None, 1)\n" + ] + }, + { + "data": { + "text/plain": [ + "Reshape{4}.0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pytensor.gradient import grad, hessian, jacobian\n", + "from pytensor.tensor.optimize import root\n", + "\n", + "x = pt.vector(\"x\")\n", + "var = pt.stack([x])\n", + "y = pt.stack([var[0], var[0] ** 2])\n", + "sol, _ = root(y, variables=var)\n", + "jacobian(sol, var, vectorize=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2f475324-9fba-48a1-a79a-563a5e7818c9", + "metadata": {}, + "outputs": [], + "source": [ + "rng = np.random.default_rng(12345)\n", + "n = 10000\n", + "d = 10\n", + "\n", + "# Initialise arrays\n", + "mu_true = rng.random(d)\n", + "cov_true = np.diag(rng.random(d))\n", + "Q_val = np.diag(rng.random(d))\n", + "cov_param_val = np.diag(rng.random(d))\n", + "\n", + "x_val = rng.random(d)\n", + "mu_val = rng.random(d)\n", + "\n", + "mu_mu = rng.random(d)\n", + "mu_cov = np.diag(np.ones(d))\n", + "cov_mu = rng.random(d**2)\n", + "cov_cov = np.diag(np.ones(d**2))\n", + "Q_mu = rng.random(d**2)\n", + "Q_cov = np.diag(np.ones(d**2))\n", + "\n", + "with pm.Model() as model:\n", + " y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n)\n", + "\n", + " mu_param = pm.MvNormal(\"mu_param\", mu=mu_mu, cov=mu_cov)\n", + " # cov_param = np.abs(pm.MvNormal(\"cov_param\", mu=cov_mu, cov=cov_cov))\n", + " # Q = pm.MvNormal(\"Q\", mu=Q_mu, cov=Q_cov)\n", + "\n", + " x = pm.MvNormal(\"x\", mu=mu_param, tau=Q_val)\n", + "\n", + " y = pm.MvNormal(\n", + " \"y\",\n", + " mu=x,\n", + " cov=cov_param_val, # cov_param.reshape((d, d)),\n", + " observed=y_obs,\n", + " )\n", + "\n", + " # x0, log_likelihood = get_log_marginal_likelihood(\n", + " # x=model.rvs_to_values[x],\n", + " # Q=Q_val,#Q.reshape((d, d)),\n", + " # mu=mu_param,\n", + " # optimizer_kwargs={\"tol\": 1e-8},\n", + " # )\n", + "\n", + " # args = model.continuous_value_vars + model.discrete_value_vars\n", + " # for i, rv in enumerate(args):\n", + " # if rv == model.rvs_to_values[x]:\n", + " # args.pop(i)\n", + " # log_likelihood = pytensor.graph.replace.graph_replace(log_likelihood, {model.rvs_to_values[x]: rng.random(d)})\n", + " # log_laplace_approx = pytensor.function(args, log_likelihood)\n", + "\n", + " # pm.sample()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "5121ab56-7841-4ff2-b9b0-016639d2bdb2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ModelFreeRV{transform=None} [id A] 'mu_param' 3\n", + " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id B] 'mu_param' 2\n", + " │ ├─ RNG() [id C]\n", + " │ ├─ NoneConst{None} [id D]\n", + " │ ├─ Second [id E] 1\n", + " │ │ ├─ Subtensor{:, i} [id F] 0\n", + " │ │ │ ├─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n", + " │ │ │ └─ -1 [id H]\n", + " │ │ └─ [0.2552323 ... .18013059] [id I]\n", + " │ └─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n", + " └─ mu_param [id J]\n", + "ModelFreeRV{transform=None} [id K] 'x' 8\n", + " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id L] 'x' 7\n", + " │ ├─ RNG() [id M]\n", + " │ ├─ NoneConst{None} [id D]\n", + " │ ├─ Second [id N] 6\n", + " │ │ ├─ Subtensor{:, i} [id O] 5\n", + " │ │ │ ├─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id P] 4\n", + " │ │ │ │ └─ [[0.081594 ... 59856801]] [id Q]\n", + " │ │ │ └─ -1 [id R]\n", + " │ │ └─ ModelFreeRV{transform=None} [id A] 'mu_param' 3\n", + " │ │ └─ ···\n", + " │ └─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id P] 4\n", + " │ └─ ···\n", + " └─ x [id S]\n", + "ModelObservedRV{transform=None} [id T] 'y' 14\n", + " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id U] 'y' 13\n", + " │ ├─ RNG() [id V]\n", + " │ ├─ [10000] [id W]\n", + " │ ├─ ExpandDims{axis=0} [id X] 12\n", + " │ │ └─ Second [id Y] 11\n", + " │ │ ├─ Subtensor{:, i} [id Z] 10\n", + " │ │ │ ├─ [[0.854741 ... 27377318]] [id BA]\n", + " │ │ │ └─ -1 [id BB]\n", + " │ │ └─ ModelFreeRV{transform=None} [id K] 'x' 8\n", + " │ │ └─ ···\n", + " │ └─ ExpandDims{axis=0} [id BC] 9\n", + " │ └─ [[0.854741 ... 27377318]] [id BA]\n", + " └─ y{[[ 0.64235 ... 56333986]]} [id BD]\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster10\n", + "\n", + "10\n", + "\n", + "\n", + "cluster10000 x 10\n", + "\n", + "10000 x 10\n", + "\n", + "\n", + "\n", + "x\n", + "\n", + "x\n", + "~\n", + "MvNormal\n", + "\n", + "\n", + "\n", + "y\n", + "\n", + "y\n", + "~\n", + "MvNormal\n", + "\n", + "\n", + "\n", + "x->y\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "mu_param\n", + "\n", + "mu_param\n", + "~\n", + "MvNormal\n", + "\n", + "\n", + "\n", + "mu_param->x\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rvs_to_marginalize = [x]\n", + "\n", + "fg, memo = fgraph_from_model(model)\n", + "fg.dprint()\n", + "rvs_to_marginalize = [memo[rv] for rv in rvs_to_marginalize]\n", + "toposort = fg.toposort()\n", + "\n", + "# fg.dprint()\n", + "# print(rvs_to_marginalize)\n", + "# print(toposort)\n", + "\n", + "from pymc.model.fgraph import (\n", + " ModelFreeRV,\n", + " ModelValuedVar,\n", + ")\n", + "\n", + "from pymc_extras.model.marginal.graph_analysis import (\n", + " find_conditional_dependent_rvs,\n", + " find_conditional_input_rvs,\n", + " is_conditional_dependent,\n", + " subgraph_batch_dim_connection,\n", + ")\n", + "\n", + "from pymc_extras.model.marginal.marginal_model import (\n", + " _unique,\n", + " collect_shared_vars,\n", + " remove_model_vars,\n", + ")\n", + "\n", + "from pymc_extras.model.marginal.distributions import (\n", + " MarginalLaplaceRV,\n", + ")\n", + "\n", + "from pymc.pytensorf import collect_default_updates\n", + "\n", + "from pytensor.graph import (\n", + " FunctionGraph,\n", + " Variable,\n", + " clone_replace,\n", + ")\n", + "\n", + "for rv_to_marginalize in sorted(\n", + " rvs_to_marginalize,\n", + " key=lambda rv: toposort.index(rv.owner),\n", + " reverse=True,\n", + "):\n", + " all_rvs = [node.out for node in fg.toposort() if isinstance(node.op, ModelValuedVar)]\n", + "\n", + " dependent_rvs = find_conditional_dependent_rvs(rv_to_marginalize, all_rvs)\n", + " if not dependent_rvs:\n", + " # TODO: This should at most be a warning, not an error\n", + " raise ValueError(f\"No RVs depend on marginalized RV {rv_to_marginalize}\")\n", + "\n", + " # Issue warning for IntervalTransform on dependent RVs\n", + " for dependent_rv in dependent_rvs:\n", + " transform = dependent_rv.owner.op.transform\n", + "\n", + " # if isinstance(transform, IntervalTransform) or (\n", + " # isinstance(transform, Chain)\n", + " # and any(isinstance(tr, IntervalTransform) for tr in transform.transform_list)\n", + " # ):\n", + " # warnings.warn(\n", + " # f\"The transform {transform} for the variable {dependent_rv}, which depends on the \"\n", + " # f\"marginalized {rv_to_marginalize} may no longer work if bounds depended on other variables.\",\n", + " # UserWarning,\n", + " # )\n", + "\n", + " # Check that no deterministics or potentials depend on the rv to marginalize\n", + " for det in model.deterministics:\n", + " if is_conditional_dependent(memo[det], rv_to_marginalize, all_rvs):\n", + " raise NotImplementedError(\n", + " f\"Cannot marginalize {rv_to_marginalize} due to dependent Deterministic {det}\"\n", + " )\n", + " for pot in model.potentials:\n", + " if is_conditional_dependent(memo[pot], rv_to_marginalize, all_rvs):\n", + " raise NotImplementedError(\n", + " f\"Cannot marginalize {rv_to_marginalize} due to dependent Potential {pot}\"\n", + " )\n", + "\n", + " marginalized_rv_input_rvs = find_conditional_input_rvs([rv_to_marginalize], all_rvs)\n", + " other_direct_rv_ancestors = [\n", + " rv\n", + " for rv in find_conditional_input_rvs(dependent_rvs, all_rvs)\n", + " if rv is not rv_to_marginalize\n", + " ]\n", + " input_rvs = _unique((*marginalized_rv_input_rvs, *other_direct_rv_ancestors))\n", + "\n", + "pm.model_to_graphviz(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7d2d4683-fc83-47a4-bca8-77085688c42f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[mu_param, RNG(), RNG()]\n", + "[x, y, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0]\n", + "[mu_param, RNG(), RNG()]\n", + "[x, y, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0]\n", + "[x, y, MarginalLaplaceRV{inline=False}.2, MarginalLaplaceRV{inline=False}.3]\n", + "ModelFreeRV{transform=None} [id A] 'mu_param' 3\n", + " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id B] 'mu_param' 2\n", + " │ ├─ RNG() [id C]\n", + " │ ├─ NoneConst{None} [id D]\n", + " │ ├─ Second [id E] 1\n", + " │ │ ├─ Subtensor{:, i} [id F] 0\n", + " │ │ │ ├─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n", + " │ │ │ └─ -1 [id H]\n", + " │ │ └─ [0.2552323 ... .18013059] [id I]\n", + " │ └─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n", + " └─ mu_param [id J]\n", + "MarginalLaplaceRV{inline=False}.0 [id K] 'x' 4\n", + " ├─ ModelFreeRV{transform=None} [id A] 'mu_param' 3\n", + " │ └─ ···\n", + " ├─ RNG() [id L]\n", + " └─ RNG() [id M]\n", + "ModelObservedRV{transform=None} [id N] 'y' 5\n", + " ├─ MarginalLaplaceRV{inline=False}.1 [id K] 'y' 4\n", + " │ └─ ···\n", + " └─ y{[[ 0.64235 ... 56333986]]} [id O]\n", + "\n", + "Inner graphs:\n", + "\n", + "MarginalLaplaceRV{inline=False} [id K]\n", + " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id P] 'x'\n", + " ├─ *2- [id Q]\n", + " ├─ NoneConst{None} [id D]\n", + " ├─ Second [id R]\n", + " │ ├─ Subtensor{:, i} [id S]\n", + " │ │ ├─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id T]\n", + " │ │ │ └─ [[0.081594 ... 59856801]] [id U]\n", + " │ │ └─ -1 [id V]\n", + " │ └─ *0- [id W]\n", + " └─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id T]\n", + " └─ ···\n", + " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id X] 'y'\n", + " ├─ *1- [id Y]\n", + " ├─ [10000] [id Z]\n", + " ├─ ExpandDims{axis=0} [id BA]\n", + " │ └─ Second [id BB]\n", + " │ ├─ Subtensor{:, i} [id BC]\n", + " │ │ ├─ [[0.854741 ... 27377318]] [id BD]\n", + " │ │ └─ -1 [id BE]\n", + " │ └─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id P] 'x'\n", + " │ └─ ···\n", + " └─ ExpandDims{axis=0} [id BF]\n", + " └─ [[0.854741 ... 27377318]] [id BD]\n", + " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0 [id X]\n", + " └─ ···\n", + " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0 [id P]\n", + " └─ ···\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster10\n", + "\n", + "10\n", + "\n", + "\n", + "cluster10000 x 10\n", + "\n", + "10000 x 10\n", + "\n", + "\n", + "\n", + "mu_param\n", + "\n", + "mu_param\n", + "~\n", + "MvNormal\n", + "\n", + "\n", + "\n", + "y\n", + "\n", + "y\n", + "~\n", + "MarginalLaplace\n", + "\n", + "\n", + "\n", + "mu_param->y\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "output_rvs = [rv_to_marginalize, *dependent_rvs]\n", + "rng_updates = collect_default_updates(output_rvs, inputs=input_rvs, must_be_shared=False)\n", + "outputs = output_rvs + list(rng_updates.values())\n", + "inputs = input_rvs + list(rng_updates.keys())\n", + "# Add any other shared variable inputs\n", + "inputs += collect_shared_vars(output_rvs, blockers=inputs)\n", + "\n", + "inner_inputs = [inp.clone() for inp in inputs]\n", + "inner_outputs = clone_replace(outputs, replace=dict(zip(inputs, inner_inputs)))\n", + "inner_outputs = remove_model_vars(inner_outputs)\n", + "\n", + "marginalize_constructor = MarginalLaplaceRV\n", + "\n", + "_, _, *dims = rv_to_marginalize.owner.inputs\n", + "marginalization_op = marginalize_constructor(\n", + " inputs=inner_inputs,\n", + " outputs=inner_outputs,\n", + " dims_connections=[\n", + " (None,),\n", + " ], # dependent_rvs_dim_connections, # TODO NOT SURE WHAT THIS IS\n", + " dims=dims,\n", + " # x0=x0,\n", + " # marginalized_rv_input_rvs=marginalized_rv_input_rvs\n", + ")\n", + "\n", + "new_outputs = marginalization_op(*inputs)\n", + "for old_output, new_output in zip(outputs, new_outputs):\n", + " new_output.name = old_output.name\n", + "\n", + "model_replacements = []\n", + "for old_output, new_output in zip(outputs, new_outputs):\n", + " if old_output is rv_to_marginalize or not isinstance(old_output.owner.op, ModelValuedVar):\n", + " # Replace the marginalized ModelFreeRV (or non model-variables) themselves\n", + " var_to_replace = old_output\n", + " else:\n", + " # Replace the underlying RV, keeping the same value, transform and dims\n", + " var_to_replace = old_output.owner.inputs[0]\n", + " model_replacements.append((var_to_replace, new_output))\n", + "\n", + "print(inner_inputs)\n", + "print(inner_outputs)\n", + "print(inputs)\n", + "\n", + "print(outputs)\n", + "print(new_outputs)\n", + "\n", + "fg.replace_all(model_replacements)\n", + "fg.dprint()\n", + "\n", + "model_marg = model_from_fgraph(fg, mutate_fgraph=True)\n", + "pm.model_to_graphviz(model_marg)" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "793248a1-8088-41fc-9dbd-c58e596e0df7", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Only tensors with the same number of dimensions can be joined. Input ndims were: [3, 2]", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mTypeError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[93]\u001b[39m\u001b[32m, line 8\u001b[39m\n\u001b[32m 5\u001b[39m b = pt.vector(\u001b[33m'\u001b[39m\u001b[33mb\u001b[39m\u001b[33m'\u001b[39m, shape=(\u001b[32m3\u001b[39m,))\n\u001b[32m 7\u001b[39m eqns = pt.stack([A @ x - b])\n\u001b[32m----> \u001b[39m\u001b[32m8\u001b[39m var = \u001b[43mpt\u001b[49m\u001b[43m.\u001b[49m\u001b[43mstack\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mA\u001b[49m\u001b[43m,\u001b[49m\u001b[43mb\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 10\u001b[39m soln, _ = root(eqns, variables=var)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/tensor/basic.py:2977\u001b[39m, in \u001b[36mstack\u001b[39m\u001b[34m(tensors, axis)\u001b[39m\n\u001b[32m 2973\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mconcatenate\u001b[39m(tensor_list, axis=\u001b[32m0\u001b[39m):\n\u001b[32m 2974\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Alias for `join`(axis, *tensor_list).\u001b[39;00m\n\u001b[32m 2975\u001b[39m \n\u001b[32m 2976\u001b[39m \u001b[33;03m This function is similar to `join`, but uses the signature of\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m2977\u001b[39m \u001b[33;03m numpy's concatenate function.\u001b[39;00m\n\u001b[32m 2978\u001b[39m \n\u001b[32m 2979\u001b[39m \u001b[33;03m Raises\u001b[39;00m\n\u001b[32m 2980\u001b[39m \u001b[33;03m ------\u001b[39;00m\n\u001b[32m 2981\u001b[39m \u001b[33;03m TypeError\u001b[39;00m\n\u001b[32m 2982\u001b[39m \u001b[33;03m The tensor_list must be a tuple or list.\u001b[39;00m\n\u001b[32m 2983\u001b[39m \n\u001b[32m 2984\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m 2985\u001b[39m \u001b[38;5;66;03m# Check someone did not make the common mistake to do something like:\u001b[39;00m\n\u001b[32m 2986\u001b[39m \u001b[38;5;66;03m# c = concatenate(x, y)\u001b[39;00m\n\u001b[32m 2987\u001b[39m \u001b[38;5;66;03m# instead of\u001b[39;00m\n\u001b[32m 2988\u001b[39m \u001b[38;5;66;03m# c = concatenate((x, y))\u001b[39;00m\n\u001b[32m 2989\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(tensor_list, \u001b[38;5;28mtuple\u001b[39m | \u001b[38;5;28mlist\u001b[39m):\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/tensor/basic.py:2817\u001b[39m, in \u001b[36mjoin\u001b[39m\u001b[34m(axis, *tensors_list)\u001b[39m\n\u001b[32m 2815\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m tensors_list[\u001b[32m0\u001b[39m]\n\u001b[32m 2816\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m2817\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_join\u001b[49m\u001b[43m(\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43mtensors_list\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/graph/op.py:293\u001b[39m, in \u001b[36mOp.__call__\u001b[39m\u001b[34m(self, name, return_list, *inputs, **kwargs)\u001b[39m\n\u001b[32m 249\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__call__\u001b[39m(\n\u001b[32m 250\u001b[39m \u001b[38;5;28mself\u001b[39m, *inputs: Any, name=\u001b[38;5;28;01mNone\u001b[39;00m, return_list=\u001b[38;5;28;01mFalse\u001b[39;00m, **kwargs\n\u001b[32m 251\u001b[39m ) -> Variable | \u001b[38;5;28mlist\u001b[39m[Variable]:\n\u001b[32m 252\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33mr\u001b[39m\u001b[33;03m\"\"\"Construct an `Apply` node using :meth:`Op.make_node` and return its outputs.\u001b[39;00m\n\u001b[32m 253\u001b[39m \n\u001b[32m 254\u001b[39m \u001b[33;03m This method is just a wrapper around :meth:`Op.make_node`.\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 291\u001b[39m \n\u001b[32m 292\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m293\u001b[39m node = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mmake_node\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 294\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m name \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 295\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(node.outputs) == \u001b[32m1\u001b[39m:\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/tensor/basic.py:2510\u001b[39m, in \u001b[36mJoin.make_node\u001b[39m\u001b[34m(self, axis, *tensors)\u001b[39m\n\u001b[32m 2507\u001b[39m ndim = tensors[\u001b[32m0\u001b[39m].type.ndim\n\u001b[32m 2509\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m builtins.all(x.ndim == ndim \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m tensors):\n\u001b[32m-> \u001b[39m\u001b[32m2510\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[32m 2511\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mOnly tensors with the same number of dimensions can be joined. \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 2512\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mInput ndims were: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m[x.ndim\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mfor\u001b[39;00m\u001b[38;5;250m \u001b[39mx\u001b[38;5;250m \u001b[39m\u001b[38;5;129;01min\u001b[39;00m\u001b[38;5;250m \u001b[39mtensors]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 2513\u001b[39m )\n\u001b[32m 2515\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m 2516\u001b[39m static_axis = \u001b[38;5;28mint\u001b[39m(get_scalar_constant_value(axis))\n", + "\u001b[31mTypeError\u001b[39m: Only tensors with the same number of dimensions can be joined. Input ndims were: [3, 2]" + ] + } + ], + "source": [ + "from pytensor.tensor.optimize import root\n", + "\n", + "A = pt.matrix(\"A\", shape=(3, 3))\n", + "x = np.ones((3, 1))\n", + "b = pt.vector(\"b\", shape=(3,))\n", + "\n", + "eqns = pt.stack([A @ x - b])\n", + "var = pt.stack([A, b])\n", + "\n", + "soln, _ = root(eqns, variables=var)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "07f8abf3-6158-4d62-83d2-2cffe65aae91", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(10,)\n", + "(10, 1, 1)\n" + ] + }, + { + "data": { + "text/plain": [ + "Reshape{4}.0" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pytensor.tensor.math import tensordot\n", + "\n", + "a = pt.tensor(\"a\", shape=(10,))\n", + "b = pt.tensor(\"b\", shape=(10, 1, 1))\n", + "\n", + "print(a.type.shape)\n", + "print(b.type.shape)\n", + "# print(b.T.type.shape)\n", + "\n", + "tensordot(a, b, axes=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "2eee8e73-5305-4472-8f9c-58a689f9471e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "ename": "AttributeError", + "evalue": "'MarginalLaplaceRV' object has no attribute 'owner'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[31]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m model_marg \u001b[38;5;28;01mas\u001b[39;00m m:\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m \u001b[43mpm\u001b[49m\u001b[43m.\u001b[49m\u001b[43msample\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/sampling/mcmc.py:783\u001b[39m, in \u001b[36msample\u001b[39m\u001b[34m(draws, tune, chains, cores, random_seed, progressbar, progressbar_theme, step, var_names, nuts_sampler, initvals, init, jitter_max_retries, n_init, trace, discard_tuned_samples, compute_convergence_checks, keep_warning_stat, return_inferencedata, idata_kwargs, nuts_sampler_kwargs, callback, mp_ctx, blas_cores, model, compile_kwargs, **kwargs)\u001b[39m\n\u001b[32m 780\u001b[39m _log.warning(msg)\n\u001b[32m 782\u001b[39m provided_steps, selected_steps = assign_step_methods(model, step, methods=pm.STEP_METHODS)\n\u001b[32m--> \u001b[39m\u001b[32m783\u001b[39m exclusive_nuts = (\n\u001b[32m 784\u001b[39m \u001b[38;5;66;03m# User provided an instantiated NUTS step, and nothing else is needed\u001b[39;00m\n\u001b[32m 785\u001b[39m (\u001b[38;5;129;01mnot\u001b[39;00m selected_steps \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(provided_steps) == \u001b[32m1\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(provided_steps[\u001b[32m0\u001b[39m], NUTS))\n\u001b[32m 786\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m\n\u001b[32m 787\u001b[39m \u001b[38;5;66;03m# Only automatically selected NUTS step is needed\u001b[39;00m\n\u001b[32m 788\u001b[39m (\n\u001b[32m 789\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m provided_steps\n\u001b[32m 790\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(selected_steps) == \u001b[32m1\u001b[39m\n\u001b[32m 791\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28missubclass\u001b[39m(\u001b[38;5;28mnext\u001b[39m(\u001b[38;5;28miter\u001b[39m(selected_steps)), NUTS)\n\u001b[32m 792\u001b[39m )\n\u001b[32m 793\u001b[39m )\n\u001b[32m 795\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m nuts_sampler != \u001b[33m\"\u001b[39m\u001b[33mpymc\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 796\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m exclusive_nuts:\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/sampling/mcmc.py:245\u001b[39m, in \u001b[36massign_step_methods\u001b[39m\u001b[34m(model, step, methods)\u001b[39m\n\u001b[32m 243\u001b[39m methods_list: \u001b[38;5;28mlist\u001b[39m[\u001b[38;5;28mtype\u001b[39m[BlockedStep]] = \u001b[38;5;28mlist\u001b[39m(methods \u001b[38;5;129;01mor\u001b[39;00m pm.STEP_METHODS)\n\u001b[32m 244\u001b[39m selected_steps: \u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mtype\u001b[39m[BlockedStep], \u001b[38;5;28mlist\u001b[39m] = {}\n\u001b[32m--> \u001b[39m\u001b[32m245\u001b[39m model_logp = \u001b[43mmodel\u001b[49m\u001b[43m.\u001b[49m\u001b[43mlogp\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 247\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m var \u001b[38;5;129;01min\u001b[39;00m model.value_vars:\n\u001b[32m 248\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m var \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m assigned_vars:\n\u001b[32m 249\u001b[39m \u001b[38;5;66;03m# determine if a gradient can be computed\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/model/core.py:691\u001b[39m, in \u001b[36mModel.logp\u001b[39m\u001b[34m(self, vars, jacobian, sum)\u001b[39m\n\u001b[32m 689\u001b[39m rv_logps: \u001b[38;5;28mlist\u001b[39m[TensorVariable] = []\n\u001b[32m 690\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m rvs:\n\u001b[32m--> \u001b[39m\u001b[32m691\u001b[39m rv_logps = \u001b[43mtransformed_conditional_logp\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 692\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs\u001b[49m\u001b[43m=\u001b[49m\u001b[43mrvs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 693\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs_to_values\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mrvs_to_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 694\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs_to_transforms\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mrvs_to_transforms\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 695\u001b[39m \u001b[43m \u001b[49m\u001b[43mjacobian\u001b[49m\u001b[43m=\u001b[49m\u001b[43mjacobian\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 696\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 697\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(rv_logps, \u001b[38;5;28mlist\u001b[39m)\n\u001b[32m 699\u001b[39m \u001b[38;5;66;03m# Replace random variables by their value variables in potential terms\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/logprob/basic.py:570\u001b[39m, in \u001b[36mtransformed_conditional_logp\u001b[39m\u001b[34m(rvs, rvs_to_values, rvs_to_transforms, jacobian, **kwargs)\u001b[39m\n\u001b[32m 567\u001b[39m transform_rewrite = TransformValuesRewrite(values_to_transforms) \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[32m 569\u001b[39m kwargs.setdefault(\u001b[33m\"\u001b[39m\u001b[33mwarn_rvs\u001b[39m\u001b[33m\"\u001b[39m, \u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[32m--> \u001b[39m\u001b[32m570\u001b[39m temp_logp_terms = \u001b[43mconditional_logp\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 571\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs_to_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 572\u001b[39m \u001b[43m \u001b[49m\u001b[43mextra_rewrites\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtransform_rewrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 573\u001b[39m \u001b[43m \u001b[49m\u001b[43muse_jacobian\u001b[49m\u001b[43m=\u001b[49m\u001b[43mjacobian\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 574\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 575\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 577\u001b[39m \u001b[38;5;66;03m# The function returns the logp for every single value term we provided to it.\u001b[39;00m\n\u001b[32m 578\u001b[39m \u001b[38;5;66;03m# This includes the extra values we plugged in above, so we filter those we\u001b[39;00m\n\u001b[32m 579\u001b[39m \u001b[38;5;66;03m# actually wanted in the same order they were given in.\u001b[39;00m\n\u001b[32m 580\u001b[39m logp_terms = {}\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/logprob/basic.py:500\u001b[39m, in \u001b[36mconditional_logp\u001b[39m\u001b[34m(rv_values, warn_rvs, ir_rewriter, extra_rewrites, **kwargs)\u001b[39m\n\u001b[32m 497\u001b[39m node_values = remapped_vars[: \u001b[38;5;28mlen\u001b[39m(node_values)]\n\u001b[32m 498\u001b[39m node_inputs = remapped_vars[\u001b[38;5;28mlen\u001b[39m(node_values) :]\n\u001b[32m--> \u001b[39m\u001b[32m500\u001b[39m node_logprobs = \u001b[43m_logprob\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 501\u001b[39m \u001b[43m \u001b[49m\u001b[43mnode\u001b[49m\u001b[43m.\u001b[49m\u001b[43mop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 502\u001b[39m \u001b[43m \u001b[49m\u001b[43mnode_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 503\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43mnode_inputs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 504\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 505\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 507\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(node_logprobs, \u001b[38;5;28mlist\u001b[39m | \u001b[38;5;28mtuple\u001b[39m):\n\u001b[32m 508\u001b[39m node_logprobs = [node_logprobs]\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc-extras/.pixi/envs/default/lib/python3.12/functools.py:912\u001b[39m, in \u001b[36msingledispatch..wrapper\u001b[39m\u001b[34m(*args, **kw)\u001b[39m\n\u001b[32m 908\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m args:\n\u001b[32m 909\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfuncname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m requires at least \u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 910\u001b[39m \u001b[33m'\u001b[39m\u001b[33m1 positional argument\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m912\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mdispatch\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m.\u001b[49m\u001b[34;43m__class__\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkw\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m:17\u001b[39m, in \u001b[36mlaplace_marginal_rv_logp\u001b[39m\u001b[34m(op, values, *inputs, **kwargs)\u001b[39m\n", + "\u001b[31mAttributeError\u001b[39m: 'MarginalLaplaceRV' object has no attribute 'owner'" + ] + } + ], + "source": [ + "with model_marg as m:\n", + " pm.sample()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "991b7cbd-4ef3-487a-9ece-139226883502", + "metadata": {}, + "outputs": [], + "source": [ + "[2, 2, 3, 4, 2, 2, 2, 3, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "42203b08-519a-4676-9a99-34a5d92d4c5d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Initializing NUTS using jitter+adapt_diag...\n", + "Multiprocess sampling (4 chains in 4 jobs)\n", + "NUTS: [mu_param, Q, x]\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c6253c53d3124ca1add318ff3828d5c2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "ename": "ValueError",
+     "evalue": "Not enough samples to build a trace.",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
+      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
+      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[40]\u001b[39m\u001b[32m, line 46\u001b[39m\n\u001b[32m     37\u001b[39m     \u001b[38;5;66;03m# model.logp().dprint()\u001b[39;00m\n\u001b[32m     39\u001b[39m     x0, log_likelihood = get_log_marginal_likelihood(\n\u001b[32m     40\u001b[39m         x=model.rvs_to_values[x],\n\u001b[32m     41\u001b[39m         Q=Q.reshape((d, d)),\u001b[38;5;66;03m#Q_val,\u001b[39;00m\n\u001b[32m     42\u001b[39m         mu=mu_param,\n\u001b[32m     43\u001b[39m         optimizer_kwargs={\u001b[33m\"\u001b[39m\u001b[33mtol\u001b[39m\u001b[33m\"\u001b[39m: \u001b[32m1e-8\u001b[39m},\n\u001b[32m     44\u001b[39m     )\n\u001b[32m---> \u001b[39m\u001b[32m46\u001b[39m     \u001b[43mpm\u001b[49m\u001b[43m.\u001b[49m\u001b[43msample\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m     48\u001b[39m     \u001b[38;5;66;03m# print(model.free_RVs)\u001b[39;00m\n\u001b[32m     49\u001b[39m \n\u001b[32m     50\u001b[39m     \u001b[38;5;66;03m# # with pm.Model() as inla_model:\u001b[39;00m\n\u001b[32m   (...)\u001b[39m\u001b[32m     65\u001b[39m \n\u001b[32m     66\u001b[39m \u001b[38;5;66;03m# inla_model = marginalize(model, [mu_param, cov_param])\u001b[39;00m\n",
+      "\u001b[36mFile \u001b[39m\u001b[32m~/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/lib/python3.12/site-packages/pymc/sampling/mcmc.py:964\u001b[39m, in \u001b[36msample\u001b[39m\u001b[34m(draws, tune, chains, cores, random_seed, progressbar, progressbar_theme, step, var_names, nuts_sampler, initvals, init, jitter_max_retries, n_init, trace, discard_tuned_samples, compute_convergence_checks, keep_warning_stat, return_inferencedata, idata_kwargs, nuts_sampler_kwargs, callback, mp_ctx, blas_cores, model, compile_kwargs, **kwargs)\u001b[39m\n\u001b[32m    960\u001b[39m t_sampling = time.time() - t_start\n\u001b[32m    962\u001b[39m \u001b[38;5;66;03m# Packaging, validating and returning the result was extracted\u001b[39;00m\n\u001b[32m    963\u001b[39m \u001b[38;5;66;03m# into a function to make it easier to test and refactor.\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m964\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_sample_return\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m    965\u001b[39m \u001b[43m    \u001b[49m\u001b[43mrun\u001b[49m\u001b[43m=\u001b[49m\u001b[43mrun\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    966\u001b[39m \u001b[43m    \u001b[49m\u001b[43mtraces\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtrace\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43misinstance\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mtrace\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mZarrTrace\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mtraces\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    967\u001b[39m \u001b[43m    \u001b[49m\u001b[43mtune\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtune\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    968\u001b[39m \u001b[43m    \u001b[49m\u001b[43mt_sampling\u001b[49m\u001b[43m=\u001b[49m\u001b[43mt_sampling\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    969\u001b[39m \u001b[43m    \u001b[49m\u001b[43mdiscard_tuned_samples\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdiscard_tuned_samples\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    970\u001b[39m \u001b[43m    \u001b[49m\u001b[43mcompute_convergence_checks\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcompute_convergence_checks\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    971\u001b[39m \u001b[43m    \u001b[49m\u001b[43mreturn_inferencedata\u001b[49m\u001b[43m=\u001b[49m\u001b[43mreturn_inferencedata\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    972\u001b[39m \u001b[43m    \u001b[49m\u001b[43mkeep_warning_stat\u001b[49m\u001b[43m=\u001b[49m\u001b[43mkeep_warning_stat\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    973\u001b[39m \u001b[43m    \u001b[49m\u001b[43midata_kwargs\u001b[49m\u001b[43m=\u001b[49m\u001b[43midata_kwargs\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    974\u001b[39m \u001b[43m    \u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    975\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
+      "\u001b[36mFile \u001b[39m\u001b[32m~/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/lib/python3.12/site-packages/pymc/sampling/mcmc.py:1049\u001b[39m, in \u001b[36m_sample_return\u001b[39m\u001b[34m(run, traces, tune, t_sampling, discard_tuned_samples, compute_convergence_checks, return_inferencedata, keep_warning_stat, idata_kwargs, model)\u001b[39m\n\u001b[32m   1047\u001b[39m \u001b[38;5;66;03m# Pick and slice chains to keep the maximum number of samples\u001b[39;00m\n\u001b[32m   1048\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m discard_tuned_samples:\n\u001b[32m-> \u001b[39m\u001b[32m1049\u001b[39m     traces, length = \u001b[43m_choose_chains\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtraces\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtune\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m   1050\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m   1051\u001b[39m     traces, length = _choose_chains(traces, \u001b[32m0\u001b[39m)\n",
+      "\u001b[36mFile \u001b[39m\u001b[32m~/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/lib/python3.12/site-packages/pymc/backends/base.py:624\u001b[39m, in \u001b[36m_choose_chains\u001b[39m\u001b[34m(traces, tune)\u001b[39m\n\u001b[32m    622\u001b[39m lengths = [\u001b[38;5;28mmax\u001b[39m(\u001b[32m0\u001b[39m, \u001b[38;5;28mlen\u001b[39m(trace) - tune) \u001b[38;5;28;01mfor\u001b[39;00m trace \u001b[38;5;129;01min\u001b[39;00m traces]\n\u001b[32m    623\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28msum\u001b[39m(lengths):\n\u001b[32m--> \u001b[39m\u001b[32m624\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mNot enough samples to build a trace.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m    626\u001b[39m idxs = np.argsort(lengths)\n\u001b[32m    627\u001b[39m l_sort = np.array(lengths)[idxs]\n",
+      "\u001b[31mValueError\u001b[39m: Not enough samples to build a trace."
+     ]
+    }
+   ],
+   "source": [
+    "rng = np.random.default_rng(12345)\n",
+    "n = 10000\n",
+    "d = 3\n",
+    "\n",
+    "# Initialise arrays\n",
+    "mu_true = rng.random(d)\n",
+    "cov_true = np.diag(rng.random(d))\n",
+    "Q_val = np.diag(rng.random(d))\n",
+    "cov_param_val = np.diag(rng.random(d))\n",
+    "\n",
+    "x_val = rng.random(d)\n",
+    "mu_val = rng.random(d)\n",
+    "\n",
+    "mu_mu = rng.random(d)\n",
+    "mu_cov = np.diag(np.ones(d))\n",
+    "cov_mu = rng.random(d**2)\n",
+    "cov_cov = np.diag(np.ones(d**2))\n",
+    "Q_mu = rng.random(d**2)\n",
+    "Q_cov = np.diag(np.ones(d**2))\n",
+    "\n",
+    "with pm.Model() as model:\n",
+    "    y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n)\n",
+    "\n",
+    "    mu_param = pm.MvNormal(\"mu_param\", mu=mu_mu, cov=mu_cov)\n",
+    "    # cov_param = np.abs(pm.MvNormal(\"cov_param\", mu=cov_mu, cov=cov_cov))\n",
+    "    # Q = pm.MvNormal(\"Q\", mu=Q_mu, cov=Q_cov)\n",
+    "\n",
+    "    x = pm.MvNormal(\"x\", mu=mu_param, tau=Q_val)\n",
+    "\n",
+    "    y = pm.MvNormal(\n",
+    "        \"y\",\n",
+    "        mu=x,\n",
+    "        cov=cov_param_val,  # cov_param.reshape((d, d)),\n",
+    "        observed=y_obs,\n",
+    "    )\n",
+    "\n",
+    "    # model.logp().dprint()\n",
+    "\n",
+    "    # x0, log_likelihood = get_log_marginal_likelihood(\n",
+    "    #     x=model.rvs_to_values[x],\n",
+    "    #     Q=Q_val,#Q.reshape((d, d)),\n",
+    "    #     mu=mu_param,\n",
+    "    #     optimizer_kwargs={\"tol\": 1e-8},\n",
+    "    # )\n",
+    "\n",
+    "    # print(model.free_RVs)\n",
+    "\n",
+    "    # # with pm.Model() as inla_model:\n",
+    "    # log_prior = pm.logp(mu_param, mu_mu)\n",
+    "    # log_posterior = log_likelihood + log_prior\n",
+    "    # # # log_posterior.dprint()\n",
+    "    # # # log_posterior = pytensor.graph.replace.graph_replace(log_posterior, {model.rvs_to_values[x]: x0})\n",
+    "    # # # log_posterior_model = model_from_fgraph(log_posterior, mutate_fgraph=True)\n",
+    "    # # idata = pm.sample()\n",
+    "    # # draws = pm.draw(mu_param)\n",
+    "    # idata = pm.sample_prior_predictive()\n",
+    "    # print(idata.prior)\n",
+    "    # print(draws)\n",
+    "\n",
+    "    # print(inla_model.free_RVs)\n",
+    "    # log_posterior.dprint()\n",
+    "    # pytensor.graph.fg.FunctionGraph(inputs=[model.rvs_to_values[mu_param], model.rvs_to_values[x]], outputs=[log_posterior])\n",
+    "\n",
+    "# inla_model = marginalize(model, [mu_param, cov_param])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "681e14ea-3629-4cc5-bb7f-e08cad5df276",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e9c829f7-cf06-4402-b909-2a27d0dea07a",
+   "metadata": {},
+   "source": [
+    "True dataset:\n",
+    "\n",
+    "$y \\sim N(\\mu_{true}, \\Sigma_{true})$\n",
+    "\n",
+    "Model:\n",
+    "\n",
+    "$y|x, \\sigma \\sim N(Ax, \\sigma W)$\n",
+    "\n",
+    "Let $A=I$, $W=I$:\n",
+    "\n",
+    "$y|x, \\sigma \\sim N(x, \\sigma)$\n",
+    "\n",
+    "Comparing model and true data:\n",
+    "\n",
+    "$x = \\mu_{true}$\n",
+    "\n",
+    "$x|\\theta \\sim N(\\mu, Q^{-1})$\n",
+    "\n",
+    "$\\theta = (\\mu, \\Sigma_b, \\sigma)$\n",
+    "\n",
+    "Set $Q = I$ for now.\n",
+    "\n",
+    "$\\theta = (\\mu, \\sigma)$"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "id": "e344b7d0-f76e-4a28-9be9-884a2ba1f2c4",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "[autoreload of cutils_ext failed: Traceback (most recent call last):\n",
+      "  File \"/home/michaln/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/lib/python3.12/site-packages/IPython/extensions/autoreload.py\", line 283, in check\n",
+      "    superreload(m, reload, self.old_objects)\n",
+      "  File \"/home/michaln/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/lib/python3.12/site-packages/IPython/extensions/autoreload.py\", line 483, in superreload\n",
+      "    module = reload(module)\n",
+      "             ^^^^^^^^^^^^^^\n",
+      "  File \"/home/michaln/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/lib/python3.12/importlib/__init__.py\", line 130, in reload\n",
+      "    raise ModuleNotFoundError(f\"spec not found for the module {name!r}\", name=name)\n",
+      "ModuleNotFoundError: spec not found for the module 'cutils_ext'\n",
+      "]\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\u001b[1m============================= test session starts ==============================\u001b[0m\n",
+      "platform linux -- Python 3.12.10, pytest-8.4.1, pluggy-1.6.0 -- /home/michaln/Michal_Linux/git/GSoC/pymc-extras/.pixi/envs/default/bin/python\n",
+      "cachedir: .pytest_cache\n",
+      "rootdir: /home/michaln/Michal_Linux/git/GSoC/pymc-extras\n",
+      "configfile: pyproject.toml\n",
+      "plugins: anyio-4.9.0\n",
+      "collected 1 item                                                               \u001b[0m\u001b[1m\n",
+      "\n",
+      "../tests/test_inla.py::test_get_conditional_gaussian_approximation \u001b[32mPASSED\u001b[0m\u001b[32m [100%]\u001b[0m\n",
+      "\n",
+      "\u001b[32m============================== \u001b[32m\u001b[1m1 passed\u001b[0m\u001b[32m in 5.99s\u001b[0m\u001b[32m ===============================\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "!python -m pytest -v /home/michaln/Michal_Linux/git/GSoC/pymc-extras/tests/test_inla.py"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f1eb9a04-15dd-437d-bcf0-ce369feec912",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "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.11"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/pymc_extras/__init__.py b/pymc_extras/__init__.py
index cee0ffeb..6566c337 100644
--- a/pymc_extras/__init__.py
+++ b/pymc_extras/__init__.py
@@ -17,7 +17,7 @@
 
 from pymc_extras import gp, statespace, utils
 from pymc_extras.distributions import *
-from pymc_extras.inference import find_MAP, fit, fit_laplace, fit_pathfinder
+from pymc_extras.inference import find_MAP, fit, fit_laplace  # , fit_pathfinder
 from pymc_extras.model.marginal.marginal_model import (
     MarginalModel,
     marginalize,
diff --git a/pymc_extras/model/marginal/distributions.py b/pymc_extras/model/marginal/distributions.py
index 6e08352e..42ee3ff8 100644
--- a/pymc_extras/model/marginal/distributions.py
+++ b/pymc_extras/model/marginal/distributions.py
@@ -384,6 +384,7 @@ def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs):
 
     # Obtain the joint_logp graph of the inner RV graph
     inner_rv_values = dict(zip(inner_rvs, values))
+
     marginalized_vv = x.clone()
     rv_values = inner_rv_values | {x: marginalized_vv}
     logps_dict = conditional_logp(rv_values=rv_values, **kwargs)
@@ -396,7 +397,7 @@ def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs):
 
     from pytensor.tensor.optimize import minimize
 
-    # Maximize log(p(x | y, params)) wrt x to find mode x0
+    # Maximize log(p(x | y, params)) wrt x to find mode x0 # TODO args need to be user-supplied
     x0, _ = minimize(
         objective=-logp,
         x=marginalized_vv,
@@ -406,14 +407,32 @@ def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs):
         optimizer_kwargs={"tol": 1e-8},
     )
 
+    # print(op.__dict__)
+    # marginalized_rv_input_rvs = op.kwargs['marginalized_rv_input_rvs']
+    # x0 = op.kwargs['x0']
+    # log_laplace_approx = op.kwargs['log_laplace_approx']
+    # return logp - log_laplace_approx
+
+    rng = np.random.default_rng(12345)
+    d = 10
+    # Q = np.diag(rng.random(d))
+    from pymc import MvNormal
+
+    x = op.owner.inputs[0]
+    if not isinstance(x, MvNormal):
+        raise ValueError("Latent field x must be MvNormal.")
+    Q = x.owner.inputs[1]  # TODO double check this grabs the right thing
+    x0 = rng.random(d)
+
+    # x0 = pytensor.graph.replace.graph_replace(x0, {marginalized_vv: rng.random(d)})
+    # for rv in marginalized_rv_input_rvs:
+    #     x0 = pytensor.graph.replace.graph_replace(x0, {marginalized_vv: rng.random(d)})
+
     # require f''(x0) for Laplace approx
     hess = pytensor.gradient.hessian(logp, marginalized_vv)
     # hess = pytensor.graph.replace.graph_replace(hess, {marginalized_vv: x0})
 
     # Could be made more efficient with adding diagonals only
-    rng = np.random.default_rng(12345)
-    d = 3
-    Q = np.diag(rng.random(d))
     tau = Q - hess
 
     # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is
@@ -425,6 +444,7 @@ def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs):
     # marginalized_logp = logps_dict.pop(marginalized_vv)
     joint_logp = logp - log_laplace_approx
 
+    # TODO this might cause circularity issues by overwriting x as an input to the x0 minimizer
     joint_logp = pytensor.graph.replace.graph_replace(joint_logp, {marginalized_vv: x0})
 
     return joint_logp  # TODO check if pm.sample adds on p(params). Otherwise this is p(y|params) not p(params|y)

From 22d2ef1d8f8d645742e3005cb96704d051b33198 Mon Sep 17 00:00:00 2001
From: Michal-Novomestsky 
Date: Sat, 9 Aug 2025 16:15:43 +1000
Subject: [PATCH 08/21] tidied up MarginalLaplaceRV

---
 notebooks/INLA_testing.ipynb                | 942 +++++++++++---------
 pymc_extras/model/marginal/distributions.py |  90 +-
 2 files changed, 546 insertions(+), 486 deletions(-)

diff --git a/notebooks/INLA_testing.ipynb b/notebooks/INLA_testing.ipynb
index e2c5e27b..dfba8502 100644
--- a/notebooks/INLA_testing.ipynb
+++ b/notebooks/INLA_testing.ipynb
@@ -27,157 +27,167 @@
     "from pymc_extras.inference.inla import *\n",
     "\n",
     "from pymc.model.fgraph import fgraph_from_model, model_from_fgraph\n",
-    "from pymc_extras.model.marginal.marginal_model import marginalize"
+    "# from pymc_extras.model.marginal.marginal_model import marginalize"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
-   "id": "0ad97d05-f577-4793-ba6c-dd5f1300c022",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "ExpandDims{axis=0}.0\n",
-      "(1, None)\n",
-      "(1, None, 1)\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "Reshape{4}.0"
-      ]
-     },
-     "execution_count": 3,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "from pytensor.gradient import grad, hessian, jacobian\n",
-    "from pytensor.tensor.optimize import root\n",
-    "\n",
-    "x = pt.vector(\"x\")\n",
-    "var = pt.stack([x])\n",
-    "y = pt.stack([var[0], var[0] ** 2])\n",
-    "sol, _ = root(y, variables=var)\n",
-    "jacobian(sol, var, vectorize=True)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "id": "2f475324-9fba-48a1-a79a-563a5e7818c9",
+   "execution_count": 35,
+   "id": "9f8841b1-9da5-43b2-bf64-6bb93c8f4e93",
    "metadata": {},
    "outputs": [],
    "source": [
-    "rng = np.random.default_rng(12345)\n",
-    "n = 10000\n",
-    "d = 10\n",
-    "\n",
-    "# Initialise arrays\n",
-    "mu_true = rng.random(d)\n",
-    "cov_true = np.diag(rng.random(d))\n",
-    "Q_val = np.diag(rng.random(d))\n",
-    "cov_param_val = np.diag(rng.random(d))\n",
-    "\n",
-    "x_val = rng.random(d)\n",
-    "mu_val = rng.random(d)\n",
-    "\n",
-    "mu_mu = rng.random(d)\n",
-    "mu_cov = np.diag(np.ones(d))\n",
-    "cov_mu = rng.random(d**2)\n",
-    "cov_cov = np.diag(np.ones(d**2))\n",
-    "Q_mu = rng.random(d**2)\n",
-    "Q_cov = np.diag(np.ones(d**2))\n",
-    "\n",
-    "with pm.Model() as model:\n",
-    "    y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n)\n",
+    "def marginalize(\n",
+    "    model,\n",
+    "    rvs_to_marginalize,\n",
+    "    Q,\n",
+    "    temp_kwargs,\n",
+    "    minimizer_kwargs={\"method\": \"BFGS\", \"optimizer_kwargs\": {\"tol\": 1e-8}},\n",
+    "):\n",
+    "    from pymc.model.fgraph import (\n",
+    "        ModelFreeRV,\n",
+    "        ModelValuedVar,\n",
+    "    )\n",
     "\n",
-    "    mu_param = pm.MvNormal(\"mu_param\", mu=mu_mu, cov=mu_cov)\n",
-    "    # cov_param = np.abs(pm.MvNormal(\"cov_param\", mu=cov_mu, cov=cov_cov))\n",
-    "    # Q = pm.MvNormal(\"Q\", mu=Q_mu, cov=Q_cov)\n",
+    "    from pymc_extras.model.marginal.graph_analysis import (\n",
+    "        find_conditional_dependent_rvs,\n",
+    "        find_conditional_input_rvs,\n",
+    "        is_conditional_dependent,\n",
+    "        subgraph_batch_dim_connection,\n",
+    "    )\n",
     "\n",
-    "    x = pm.MvNormal(\"x\", mu=mu_param, tau=Q_val)\n",
+    "    from pymc_extras.model.marginal.marginal_model import (\n",
+    "        _unique,\n",
+    "        collect_shared_vars,\n",
+    "        remove_model_vars,\n",
+    "    )\n",
     "\n",
-    "    y = pm.MvNormal(\n",
-    "        \"y\",\n",
-    "        mu=x,\n",
-    "        cov=cov_param_val,  # cov_param.reshape((d, d)),\n",
-    "        observed=y_obs,\n",
+    "    from pymc_extras.model.marginal.distributions import (\n",
+    "        MarginalLaplaceRV,\n",
     "    )\n",
     "\n",
-    "    # x0, log_likelihood = get_log_marginal_likelihood(\n",
-    "    #     x=model.rvs_to_values[x],\n",
-    "    #     Q=Q_val,#Q.reshape((d, d)),\n",
-    "    #     mu=mu_param,\n",
-    "    #     optimizer_kwargs={\"tol\": 1e-8},\n",
-    "    # )\n",
+    "    from pymc.pytensorf import collect_default_updates\n",
     "\n",
-    "    # args = model.continuous_value_vars + model.discrete_value_vars\n",
-    "    # for i, rv in enumerate(args):\n",
-    "    #     if rv == model.rvs_to_values[x]:\n",
-    "    #         args.pop(i)\n",
-    "    # log_likelihood = pytensor.graph.replace.graph_replace(log_likelihood, {model.rvs_to_values[x]: rng.random(d)})\n",
-    "    # log_laplace_approx = pytensor.function(args, log_likelihood)\n",
+    "    from pytensor.graph import (\n",
+    "        FunctionGraph,\n",
+    "        Variable,\n",
+    "        clone_replace,\n",
+    "    )\n",
     "\n",
-    "    # pm.sample()"
+    "    fg, memo = fgraph_from_model(model)\n",
+    "    rvs_to_marginalize = [memo[rv] for rv in rvs_to_marginalize]\n",
+    "    toposort = fg.toposort()\n",
+    "\n",
+    "    for rv_to_marginalize in sorted(\n",
+    "        rvs_to_marginalize,\n",
+    "        key=lambda rv: toposort.index(rv.owner),\n",
+    "        reverse=True,\n",
+    "    ):\n",
+    "        all_rvs = [node.out for node in fg.toposort() if isinstance(node.op, ModelValuedVar)]\n",
+    "\n",
+    "        dependent_rvs = find_conditional_dependent_rvs(rv_to_marginalize, all_rvs)\n",
+    "        if not dependent_rvs:\n",
+    "            # TODO: This should at most be a warning, not an error\n",
+    "            raise ValueError(f\"No RVs depend on marginalized RV {rv_to_marginalize}\")\n",
+    "\n",
+    "        # Issue warning for IntervalTransform on dependent RVs\n",
+    "        for dependent_rv in dependent_rvs:\n",
+    "            transform = dependent_rv.owner.op.transform\n",
+    "\n",
+    "            # if isinstance(transform, IntervalTransform) or (\n",
+    "            #     isinstance(transform, Chain)\n",
+    "            #     and any(isinstance(tr, IntervalTransform) for tr in transform.transform_list)\n",
+    "            # ):\n",
+    "            #     warnings.warn(\n",
+    "            #         f\"The transform {transform} for the variable {dependent_rv}, which depends on the \"\n",
+    "            #         f\"marginalized {rv_to_marginalize} may no longer work if bounds depended on other variables.\",\n",
+    "            #         UserWarning,\n",
+    "            #     )\n",
+    "\n",
+    "        # Check that no deterministics or potentials depend on the rv to marginalize\n",
+    "        for det in model.deterministics:\n",
+    "            if is_conditional_dependent(memo[det], rv_to_marginalize, all_rvs):\n",
+    "                raise NotImplementedError(\n",
+    "                    f\"Cannot marginalize {rv_to_marginalize} due to dependent Deterministic {det}\"\n",
+    "                )\n",
+    "        for pot in model.potentials:\n",
+    "            if is_conditional_dependent(memo[pot], rv_to_marginalize, all_rvs):\n",
+    "                raise NotImplementedError(\n",
+    "                    f\"Cannot marginalize {rv_to_marginalize} due to dependent Potential {pot}\"\n",
+    "                )\n",
+    "\n",
+    "        marginalized_rv_input_rvs = find_conditional_input_rvs([rv_to_marginalize], all_rvs)\n",
+    "        other_direct_rv_ancestors = [\n",
+    "            rv\n",
+    "            for rv in find_conditional_input_rvs(dependent_rvs, all_rvs)\n",
+    "            if rv is not rv_to_marginalize\n",
+    "        ]\n",
+    "        input_rvs = _unique((*marginalized_rv_input_rvs, *other_direct_rv_ancestors))\n",
+    "\n",
+    "        output_rvs = [rv_to_marginalize, *dependent_rvs]\n",
+    "        rng_updates = collect_default_updates(output_rvs, inputs=input_rvs, must_be_shared=False)\n",
+    "        outputs = output_rvs + list(rng_updates.values())\n",
+    "        inputs = input_rvs + list(rng_updates.keys())\n",
+    "        # Add any other shared variable inputs\n",
+    "        inputs += collect_shared_vars(output_rvs, blockers=inputs)\n",
+    "\n",
+    "        inner_inputs = [inp.clone() for inp in inputs]\n",
+    "        inner_outputs = clone_replace(outputs, replace=dict(zip(inputs, inner_inputs)))\n",
+    "        inner_outputs = remove_model_vars(inner_outputs)\n",
+    "\n",
+    "        marginalize_constructor = MarginalLaplaceRV\n",
+    "\n",
+    "        _, _, *dims = rv_to_marginalize.owner.inputs\n",
+    "        marginalization_op = marginalize_constructor(\n",
+    "            inputs=inner_inputs,\n",
+    "            outputs=inner_outputs,\n",
+    "            dims_connections=[\n",
+    "                (None,),\n",
+    "            ],  # dependent_rvs_dim_connections, # TODO NOT SURE WHAT THIS IS\n",
+    "            dims=dims,\n",
+    "            Q=Q,\n",
+    "            temp_kwargs=temp_kwargs,\n",
+    "            minimizer_kwargs=minimizer_kwargs,\n",
+    "        )\n",
+    "\n",
+    "        new_outputs = marginalization_op(*inputs)\n",
+    "        for old_output, new_output in zip(outputs, new_outputs):\n",
+    "            new_output.name = old_output.name\n",
+    "\n",
+    "        model_replacements = []\n",
+    "        for old_output, new_output in zip(outputs, new_outputs):\n",
+    "            if old_output is rv_to_marginalize or not isinstance(\n",
+    "                old_output.owner.op, ModelValuedVar\n",
+    "            ):\n",
+    "                # Replace the marginalized ModelFreeRV (or non model-variables) themselves\n",
+    "                var_to_replace = old_output\n",
+    "            else:\n",
+    "                # Replace the underlying RV, keeping the same value, transform and dims\n",
+    "                var_to_replace = old_output.owner.inputs[0]\n",
+    "            model_replacements.append((var_to_replace, new_output))\n",
+    "\n",
+    "        fg.replace_all(model_replacements)\n",
+    "\n",
+    "    return model_from_fgraph(fg, mutate_fgraph=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "59f0123d-a58b-4df4-827d-dd408be5bee5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# - Will need to figure out how to get p(x | y)\n",
+    "# - dims_connections"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
-   "id": "5121ab56-7841-4ff2-b9b0-016639d2bdb2",
+   "execution_count": 36,
+   "id": "47d6057b-b459-43ee-afdb-32e63cee5e62",
    "metadata": {},
    "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "ModelFreeRV{transform=None} [id A] 'mu_param' 3\n",
-      " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id B] 'mu_param' 2\n",
-      " │  ├─ RNG() [id C]\n",
-      " │  ├─ NoneConst{None} [id D]\n",
-      " │  ├─ Second [id E] 1\n",
-      " │  │  ├─ Subtensor{:, i} [id F] 0\n",
-      " │  │  │  ├─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n",
-      " │  │  │  └─ -1 [id H]\n",
-      " │  │  └─ [0.2552323 ... .18013059] [id I]\n",
-      " │  └─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n",
-      " └─ mu_param [id J]\n",
-      "ModelFreeRV{transform=None} [id K] 'x' 8\n",
-      " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id L] 'x' 7\n",
-      " │  ├─ RNG() [id M]\n",
-      " │  ├─ NoneConst{None} [id D]\n",
-      " │  ├─ Second [id N] 6\n",
-      " │  │  ├─ Subtensor{:, i} [id O] 5\n",
-      " │  │  │  ├─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id P] 4\n",
-      " │  │  │  │  └─ [[0.081594 ... 59856801]] [id Q]\n",
-      " │  │  │  └─ -1 [id R]\n",
-      " │  │  └─ ModelFreeRV{transform=None} [id A] 'mu_param' 3\n",
-      " │  │     └─ ···\n",
-      " │  └─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id P] 4\n",
-      " │     └─ ···\n",
-      " └─ x [id S]\n",
-      "ModelObservedRV{transform=None} [id T] 'y' 14\n",
-      " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id U] 'y' 13\n",
-      " │  ├─ RNG() [id V]\n",
-      " │  ├─ [10000] [id W]\n",
-      " │  ├─ ExpandDims{axis=0} [id X] 12\n",
-      " │  │  └─ Second [id Y] 11\n",
-      " │  │     ├─ Subtensor{:, i} [id Z] 10\n",
-      " │  │     │  ├─ [[0.854741 ... 27377318]] [id BA]\n",
-      " │  │     │  └─ -1 [id BB]\n",
-      " │  │     └─ ModelFreeRV{transform=None} [id K] 'x' 8\n",
-      " │  │        └─ ···\n",
-      " │  └─ ExpandDims{axis=0} [id BC] 9\n",
-      " │     └─ [[0.854741 ... 27377318]] [id BA]\n",
-      " └─ y{[[ 0.64235 ... 56333986]]} [id BD]\n"
-     ]
-    },
     {
      "data": {
       "image/svg+xml": [
@@ -187,227 +197,197 @@
        "\n",
        "\n",
-       "\n",
+       "\n",
        "\n",
-       "\n",
+       "\n",
        "\n",
-       "cluster10\n",
-       "\n",
-       "10\n",
+       "cluster3\n",
+       "\n",
+       "3\n",
        "\n",
        "\n",
-       "cluster10000 x 10\n",
-       "\n",
-       "10000 x 10\n",
+       "cluster10000 x 3\n",
+       "\n",
+       "10000 x 3\n",
        "\n",
        "\n",
        "\n",
        "x\n",
-       "\n",
-       "x\n",
-       "~\n",
-       "MvNormal\n",
+       "\n",
+       "x\n",
+       "~\n",
+       "Multivariate_normal\n",
        "\n",
        "\n",
        "\n",
        "y\n",
-       "\n",
-       "y\n",
-       "~\n",
-       "MvNormal\n",
+       "\n",
+       "y\n",
+       "~\n",
+       "Multivariate_normal\n",
        "\n",
        "\n",
        "\n",
        "x->y\n",
-       "\n",
-       "\n",
+       "\n",
+       "\n",
        "\n",
        "\n",
        "\n",
        "mu_param\n",
-       "\n",
-       "mu_param\n",
-       "~\n",
-       "MvNormal\n",
+       "\n",
+       "mu_param\n",
+       "~\n",
+       "Multivariate_normal\n",
        "\n",
        "\n",
        "\n",
        "mu_param->x\n",
-       "\n",
-       "\n",
+       "\n",
+       "\n",
        "\n",
        "\n",
        "\n"
       ],
       "text/plain": [
-       ""
+       ""
       ]
      },
-     "execution_count": 5,
+     "execution_count": 36,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "rvs_to_marginalize = [x]\n",
-    "\n",
-    "fg, memo = fgraph_from_model(model)\n",
-    "fg.dprint()\n",
-    "rvs_to_marginalize = [memo[rv] for rv in rvs_to_marginalize]\n",
-    "toposort = fg.toposort()\n",
-    "\n",
-    "# fg.dprint()\n",
-    "# print(rvs_to_marginalize)\n",
-    "# print(toposort)\n",
+    "rng = np.random.default_rng(12345)\n",
+    "n = 10000\n",
+    "d = 3\n",
     "\n",
-    "from pymc.model.fgraph import (\n",
-    "    ModelFreeRV,\n",
-    "    ModelValuedVar,\n",
-    ")\n",
+    "mu_mu = np.zeros((d,))\n",
+    "mu_true = np.ones((d,))\n",
     "\n",
-    "from pymc_extras.model.marginal.graph_analysis import (\n",
-    "    find_conditional_dependent_rvs,\n",
-    "    find_conditional_input_rvs,\n",
-    "    is_conditional_dependent,\n",
-    "    subgraph_batch_dim_connection,\n",
-    ")\n",
+    "cov = np.diag(np.ones(d))\n",
+    "Q_val = np.diag(np.ones(d))\n",
+    "cov_true = np.diag(np.ones(d))\n",
     "\n",
-    "from pymc_extras.model.marginal.marginal_model import (\n",
-    "    _unique,\n",
-    "    collect_shared_vars,\n",
-    "    remove_model_vars,\n",
-    ")\n",
-    "\n",
-    "from pymc_extras.model.marginal.distributions import (\n",
-    "    MarginalLaplaceRV,\n",
-    ")\n",
+    "with pm.Model() as model:\n",
+    "    x_mu = pm.MvNormal(\"mu_param\", mu=mu_mu, cov=cov)\n",
     "\n",
-    "from pymc.pytensorf import collect_default_updates\n",
+    "    x = pm.MvNormal(\"x\", mu=x_mu, tau=Q_val)\n",
     "\n",
-    "from pytensor.graph import (\n",
-    "    FunctionGraph,\n",
-    "    Variable,\n",
-    "    clone_replace,\n",
-    ")\n",
+    "    y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n)\n",
     "\n",
-    "for rv_to_marginalize in sorted(\n",
-    "    rvs_to_marginalize,\n",
-    "    key=lambda rv: toposort.index(rv.owner),\n",
-    "    reverse=True,\n",
-    "):\n",
-    "    all_rvs = [node.out for node in fg.toposort() if isinstance(node.op, ModelValuedVar)]\n",
-    "\n",
-    "    dependent_rvs = find_conditional_dependent_rvs(rv_to_marginalize, all_rvs)\n",
-    "    if not dependent_rvs:\n",
-    "        # TODO: This should at most be a warning, not an error\n",
-    "        raise ValueError(f\"No RVs depend on marginalized RV {rv_to_marginalize}\")\n",
-    "\n",
-    "    # Issue warning for IntervalTransform on dependent RVs\n",
-    "    for dependent_rv in dependent_rvs:\n",
-    "        transform = dependent_rv.owner.op.transform\n",
-    "\n",
-    "        # if isinstance(transform, IntervalTransform) or (\n",
-    "        #     isinstance(transform, Chain)\n",
-    "        #     and any(isinstance(tr, IntervalTransform) for tr in transform.transform_list)\n",
-    "        # ):\n",
-    "        #     warnings.warn(\n",
-    "        #         f\"The transform {transform} for the variable {dependent_rv}, which depends on the \"\n",
-    "        #         f\"marginalized {rv_to_marginalize} may no longer work if bounds depended on other variables.\",\n",
-    "        #         UserWarning,\n",
-    "        #     )\n",
-    "\n",
-    "    # Check that no deterministics or potentials depend on the rv to marginalize\n",
-    "    for det in model.deterministics:\n",
-    "        if is_conditional_dependent(memo[det], rv_to_marginalize, all_rvs):\n",
-    "            raise NotImplementedError(\n",
-    "                f\"Cannot marginalize {rv_to_marginalize} due to dependent Deterministic {det}\"\n",
-    "            )\n",
-    "    for pot in model.potentials:\n",
-    "        if is_conditional_dependent(memo[pot], rv_to_marginalize, all_rvs):\n",
-    "            raise NotImplementedError(\n",
-    "                f\"Cannot marginalize {rv_to_marginalize} due to dependent Potential {pot}\"\n",
-    "            )\n",
-    "\n",
-    "    marginalized_rv_input_rvs = find_conditional_input_rvs([rv_to_marginalize], all_rvs)\n",
-    "    other_direct_rv_ancestors = [\n",
-    "        rv\n",
-    "        for rv in find_conditional_input_rvs(dependent_rvs, all_rvs)\n",
-    "        if rv is not rv_to_marginalize\n",
-    "    ]\n",
-    "    input_rvs = _unique((*marginalized_rv_input_rvs, *other_direct_rv_ancestors))\n",
+    "    y = pm.MvNormal(\n",
+    "        \"y\",\n",
+    "        mu=x,\n",
+    "        cov=cov,  # cov_param.reshape((d, d)),\n",
+    "        observed=y_obs,\n",
+    "    )\n",
     "\n",
     "pm.model_to_graphviz(model)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
-   "id": "7d2d4683-fc83-47a4-bca8-77085688c42f",
+   "execution_count": 62,
+   "id": "c3c1cca7-a743-4bbb-9bb7-7d10d9b1a2a1",
    "metadata": {},
    "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "Initializing NUTS using jitter+adapt_diag...\n"
+     ]
+    },
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "[mu_param, RNG(), RNG()]\n",
-      "[x, y, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0]\n",
-      "[mu_param, RNG(), RNG()]\n",
-      "[x, y, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0, MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0]\n",
-      "[x, y, MarginalLaplaceRV{inline=False}.2, MarginalLaplaceRV{inline=False}.3]\n",
-      "ModelFreeRV{transform=None} [id A] 'mu_param' 3\n",
-      " ├─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id B] 'mu_param' 2\n",
-      " │  ├─ RNG() [id C]\n",
-      " │  ├─ NoneConst{None} [id D]\n",
-      " │  ├─ Second [id E] 1\n",
-      " │  │  ├─ Subtensor{:, i} [id F] 0\n",
-      " │  │  │  ├─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n",
-      " │  │  │  └─ -1 [id H]\n",
-      " │  │  └─ [0.2552323 ... .18013059] [id I]\n",
-      " │  └─ [[1. 0. 0. ... 0. 0. 1.]] [id G]\n",
-      " └─ mu_param [id J]\n",
-      "MarginalLaplaceRV{inline=False}.0 [id K] 'x' 4\n",
-      " ├─ ModelFreeRV{transform=None} [id A] 'mu_param' 3\n",
-      " │  └─ ···\n",
-      " ├─ RNG() [id L]\n",
-      " └─ RNG() [id M]\n",
-      "ModelObservedRV{transform=None} [id N] 'y' 5\n",
-      " ├─ MarginalLaplaceRV{inline=False}.1 [id K] 'y' 4\n",
-      " │  └─ ···\n",
-      " └─ y{[[ 0.64235 ... 56333986]]} [id O]\n",
-      "\n",
-      "Inner graphs:\n",
-      "\n",
-      "MarginalLaplaceRV{inline=False} [id K]\n",
-      " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id P] 'x'\n",
-      "    ├─ *2- [id Q]\n",
-      "    ├─ NoneConst{None} [id D]\n",
-      "    ├─ Second [id R]\n",
-      "    │  ├─ Subtensor{:, i} [id S]\n",
-      "    │  │  ├─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id T]\n",
-      "    │  │  │  └─ [[0.081594 ... 59856801]] [id U]\n",
-      "    │  │  └─ -1 [id V]\n",
-      "    │  └─ *0- [id W]\n",
-      "    └─ Blockwise{MatrixInverse, (m,m)->(m,m)} [id T]\n",
-      "       └─ ···\n",
-      " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id X] 'y'\n",
-      "    ├─ *1- [id Y]\n",
-      "    ├─ [10000] [id Z]\n",
-      "    ├─ ExpandDims{axis=0} [id BA]\n",
-      "    │  └─ Second [id BB]\n",
-      "    │     ├─ Subtensor{:, i} [id BC]\n",
-      "    │     │  ├─ [[0.854741 ... 27377318]] [id BD]\n",
-      "    │     │  └─ -1 [id BE]\n",
-      "    │     └─ MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.1 [id P] 'x'\n",
-      "    │        └─ ···\n",
-      "    └─ ExpandDims{axis=0} [id BF]\n",
-      "       └─ [[0.854741 ... 27377318]] [id BD]\n",
-      " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0 [id X]\n",
-      "    └─ ···\n",
-      " ← MvNormalRV{name='multivariate_normal', signature='(n),(n,n)->(n)', dtype='float64', inplace=False, method='cholesky'}.0 [id P]\n",
-      "    └─ ···\n"
+      "[0. 0. 0.]\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "Multiprocess sampling (4 chains in 4 jobs)\n",
+      "NUTS: [mu_param, x]\n"
      ]
     },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "d82c728c1d5a40f9b0a224da7885c2f5",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 7 seconds.\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "array([[,\n",
+       "        ,\n",
+       "        ],\n",
+       "       [,\n",
+       "        ,\n",
+       "        ]], dtype=object)"
+      ]
+     },
+     "execution_count": 62,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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kuYNS1VqTKi5YbrJH//4R9lsNt15551tP/AlacCAAXr44Ydls9n09NNPd/j9AlyNr0CrRSvzyvTaxoJzfk3//v31/PPP69vf/rZGjx6twED6/wAAeKNP95yQJE3PSfLZE/UXUjtNz3E2CHccq1JVQ0unM1A7AQAAT7BoTb7e31msoACLnr15jJKjvO/aWUdru6G9oiU5b5wH0L1ohgEdlJ+fL4vFopkzZ6q+vl4/+tGP1KdPH4WFhWnMmDF677332l77xhtvaMKECYqIiFBKSoruueceNTY2SpIq6lv09rZCSdLXRiXqF7/4hYYPH67w8PC22cFvv/12uxnef/993X777Ro8eLCio6MVERGhkSNH6te//rWam5tPe/2iRYtksVj085//XAUFBbrxxhuVlJSksLAwjRs37pTMXc09//j6668/7bmvfOUrktSpz7/ctSj1dx/mqrzu9O8ZAAB4hq6qnSTps33OEYnTMiOondqRFhOmnORIGYa05mB5t2UEAAD+qytrO7e6urrTaruxE6fqf578uyTp4csHn3JayhdruyFprmZYMc0woLtxqx9wnlpaWnTxxRfr4MGDmjRpkurq6rRixQpdc801+vDDD7Vz5049+OCDGj9+vC655BKtXLlSzzzzjMrLy/XKK6/otQ0FarY5NCDKrju/Mk979uxRenq65s6dq4aGBq1du1bXXHONfvOb35y2/PKOO+5QfX29hg4dquHDh6umpkYbNmzQww8/rM8++0wff/yxAgJOv1s6Pz9f48ePV2hoqKZNm6aSkhKtXbtWV199tT744ANdcsklXfrPqKqqSgUFzpNbo0ePPu353r17KzExUUeOHFF1dbViYmI6/N4tR3dIBRt0qKZOC/a+qz8+cBtzkQEA8GAXWjuV1zVrx7Fq2esr9Zs7r1Puvr3UTu3UTtNzkpR3ok4r9pe23TwkSUuXLtW2bdvU1NSk3r17a968edROAACg0y60tnMrKSnR7NmzT7kuVlNXrxWrVsuxYY0mfe0u3Trl8lM+2xdru8wo52MdPRlGbQdcAANAhxw+fNiQZEgyZs6caVRUVLQ99+KLLxqSjOzsbCM+Pt5YsWJF23OFhYVGcnKyIcnYtz/PmPTrT43MhxYbo6fMMiQZDz74oNHS0tL2+oMHDxr9+/c3AgICjO3bt5+S4a233jLq6upOeaympsa44oorDEnGSy+9dMpz7lySjLvvvttobW1te+6pp54yJBnTp08/7XvNzMxs+7qO/nX48OG2r9++fbshyYiLizvjP89Ro0YZkowdO3ac8TUn+9nPfnbGz77uuuuM2traDr/Hb37zmw59JgAA6LyuqJ0OHjxovLut0Mh8aLGROHgitdNZaqel+0qMzIcWG1N+85nhcDionQAAQJfqqtrObd68eafVdve8tsXo9Z3njdCEXn5T2y1Zts7IfGixMfCRJYbN7jjj67uitgP8HSfDgPMUEBCgv/3tb4qL++KY9i233KIHH3xQBw4c0E9/+lNNnz697blevXrppptu0pNPPqm/vL5YxfU5Cq89qq1rPteUKVP029/+VhaLpe31WVlZ+v3vf6+rr75azz///Cm7Ia6++urT8kRFRenJJ5/U4sWL9c477+iWW2457TXu9zx578P3v/99Pfroo1q3bp1aWloUHBzc9tz111+vsrKy8/rnEhkZ2fb3dXV1kqTw8PAzvj4iIuKU155Ldna2nnjiCc2bN0+ZmZm6/5+r9Z/3P1Htipf03//+V3a7XW+99dZ5ZQYAAN3vQmqnFStWaG/kGLWUHFLZ3vXUTjpz7TSxX7yCA6wqrGrU4bL602qnyspKrVixQg8++CC1EwAA6LQLre2ysrK0bds2ffDBB6fUdu9uL9I724oUGp+mx377O933rZv9oraLCrQrPDhADS12Zw2XHNnu66ntgAtHMww4T3379lV2dvYpj1mtVmVmZqq0tFRz58497Wv69+8vSfp08z5pUI76txzSXkkLFiw45WKO27Rp0yRJGzduPO25vLw8LVmyRAcOHFB9fb0cDocMw2h7rj0zZ85UUFDQKY8FBgYqKytLmzdvVnl5udLSvhin88QTT5zln8C5ufO09719+TUddfPNN5/yv3910wytOS6VZ4xQzT/v1dtvv601a9ZoypQp5x8YAAB0mwupnYqKirTKmqHG/K2SqJ3OJjw4UOP6xmnNwXKtzCvTrV+qnSIiInTjjTdq1qxZGj58OLUTAADolAup7YqLiyVJn3zyiaQvaruiqkY98tZOSdJds7J1y5gE3fct/6jtAqwWDUqN0paCKu0prjljM+zL18Wo7YDzRzMMOE/p6entPu6+o6O9593PHS2rUaLVokQ55wA/9NBDeuihh874WSffhWIYhu6//349+eST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mzJQp7Kzs42QkBBDkvHVV19VHU9PTzcSExMNScb8+fOr/XgPPPCAIcm47LLLjJKSkqrj+fn5xuDBgw1JxpNPPnncfV588UVDktGqVSvjbx/PN+KmzDbipsw2np8xz4iJiTEkGcuXLz/3Fwug0SssLDRuuOEG47XXXjOWLVtm/Oc//zEkGXfcccdJz39l3s6qz5QXf9xuOJ3O426/9957DUlGr169jIyMjKrjixcvNvz9/Q0fHx9j3759dfqaADQ+ZtZP329KM+KmzDYCOg4zHvvHy0ZhYeFxjzV79mzDbrcbkowff/zxHF8pAHd0unrqncV7jLgps412T8w1dmcUVOvxqKcAoPbrw1NxOBxGbGysIcmIvfZZI27KbGPRTtdn78GDB43NmzefcJ+8vDxjxIgRhiRjypQp55wBwNmbuWK3EdDpPCPygjuNb39aeMbrWWdC/eWeWCaxjk2bNk15eXkaN26cLr/88qrj0dHRev755yXprEauLFq0SJI0ZcoU+fj4VB0PCgrSgw8+KElVI5Yr/ec//5EkXTjpfr2z0TVl+7GL2+vha0bqiSeekCT93//939m+NABuKCAgQB988IH+8Ic/qH///vL19T3t+X8c2UaPjG4nSXp9/i49/d1WOZ2uCcdlZWV69913JUmvvfaaIiMjq+43ePBg3X333SotLdUrr7xSNy8GQKNlVv10uLBUj8/cJEl68qU39fc/P6CAgIDjHmvMmDG6+eabJUkzZsyowasD4O5OV09NHhivQYnhKil36oHP1qv8DBu9U08BgEtt14en8ssvv+jgwYMKCI2UvUVXDUoM15A2rs/epk2bqlOnTifcJzg4WE8//bQkaf78+eecAcDZG9enlS6+9+/y73GJfsgIOuP1rNOh/nJfNMPq2OzZsyVJEyZMOOG2MWPGyNfXVz///LNKSqq3ifKxF3BOJSwsrOr7vLw87d69W5L0XUYTSdI957XW7UNdy5kNHz5ckvTDDz+orKysWhkA4Fh3D0/UM+NcvxC891uyHv5yoyocTm3btk3FxcXy8fHRgAEDTrhf5efPrFmz6jMugEbArPrpyVlbdLioTO1jgvTHkW1OeW63bt0kSQcPHqzW8wNAJavVohev7KZgX7s2pOadce9V6ikAcKnt+vBUPvroI0mSre0QWSxWTRndvlr3s9lskiRvb+9zen4ANWOxWPTXsZ1ks1o0Z1OatqcX1PixqL/cF82wOrZx40ZJUs+ePU+4zdvbW507d1ZJSYl27NhRrccbNWqUJNdMrtLS0qrjBQUFevHFFyVJkyZNqjpeVFRU9b3VN1C3D03QQxe0qzpW2Tg7cuSIdu7cWd2XBQDHuWFAvKZe3U02q0VfrU3VPZ+sVXZeviQpJCREFovlhPtUfv7s2bNHBQU1L1IAuB8z6qe2gy/RnE1psh+9UO1jt53y8fbscW2kHhMTU70XBADHaBrip2fGd5bkmlm/fn/uKc+t/H2OegqAp6vt+vBkjhw5opkzZ0qSAjqepzFdmqpr8yZnvF9xcbH+/ve/S5IuuuiiGj8/gHPTMTZYkwfGS5Jmrkut8eNQf7kvmmF1KD8/X7m5uZKk5s2bn/ScyuMpKSnVesyHHnpIQ4cO1cyZM5WQkKDLL79cY8eOVatWrZSUlKR33nmn6oKPYRj6ZH22ZHH9Z762g5/+fFH74/4n3rdvX9X3ycnJZ/sSAaDKZT2a643resrbZtWPWw7puQWuGROZmZkqLi4+4fxjP3+O/R6AZzOjfpr67zf1dYbrF5p7z09U52Yhp3ys3NxcffDBB5KkcePGVfdlAcBxxnVvpku7xcrhNPTAZ+tVXFZx0vMql+WhngLgyeqiPjyZb775RgUFBfKKjJd/TIIeurDdSc/LycnR5MmTNXnyZI0ZM0YtW7bU7NmzNW7cOP3pT3+q8fMDOHcPjGqrmGBfHS6s+Qpo1F/ui2ZYHSosLKz63t/f/6TnVO5Dcey5pxMYGKgffvhB1113nQ4ePKiZM2fqu+++0+HDh9W/f3/16tVLkuR0Gnpm9jb9a9E++TRtK0my7Pr1hG729OnTq76nkw3gXF3YKUbv3dxHQb52bS8OkHdwhAzDqLpwfCw+fwCcjBn106+HA5VbXK7OzYJ1z3mJp32su+66S5mZmerfv78uu+yyar4qADjRM+M6KSbYV3uzivTPudtPek5iYqJiY2OppwB4tLqoD0+m8nM2oNP5umlQvFpFBJz0vKKiIr3//vt6//33NXfuXB0+fFgTJkzQW2+9JT8/vxo/P4BzF+hj1z8u71z194yC0tOcfXLUX+6LZlgdMgyjVs45VkpKivr27asffvhBH3zwgTIyMpSRkaH3339fS5Ys0eDBg/XrkqW6d8Zavbt0ryTptj+4RqW89NJLeumll3To0CEdPHhQzzzzjKZNmya73S5Jslr55wDg3A1sHaGv7hqoZk38FND3CknSgw89rPfee0/Z2dnau3ev7r33Xv300098/gA4QX3XT/MXLtKsZ2+TI32nXrqyu7xsp/48eu655/Tpp58qLCxMH3/88UmXzACA6mri760XruwqSfpw+T4t3JFxwjkWi0V//vOfJUkPP0w9BcAz1UV9+HuZmZmaN+9nyWJV896j9IcRp94/tnnz5jIMQ06nUykpKXrnnXe0ZMkSde3aVWvXrj2nHADO3fnto9UnPlSStHz34VPOwD8V6i/3ZTc7QGM3efLkE46NHz9e48ePV1BQUNWx4uJiBQcHn3Bu5VTLwMDAaj3fpEmTtHnzZn3zzTfHLc1z4403KjAwUFdccYUun3Sngq58Tl42154X47qPUbxXvh599FE99NBDeuihh6rud91112nv3r367bffFBoaWt2XDQCn1TY6SDPvGaSb/L20JDddBau/1U033XTcOVOmTNHHH3+s1NRUPn8AD9NQ6qfzLpmgJt8lqfDLZ+W9+kO1i3nglI/x/vvv67HHHlNAQIDmzJmjhISEaj03AJzOkDaRmjwwXu/9lqxHvtyoH+8fqtAA7+POueeee7R79269+uqr1FMA3FZ914e/N+29D+VwVMg3vocev3Kggn29zngfi8WiFi1a6Oabb1bXrl3Vv39/3XTTTVq/fj2DpgCTje3eTD9IKigt1z/mbtOz47uc1f2pv9wTzbBz9P77759wLD4+XuPHj1dwcLBCQkKUl5en1NRUdezY8YRzU1Ndm/m1bNnyjM+1f/9+LVy4UD4+Prr00ktPuL3TgBGy2r2UvWeLYuxOvX3TAA1sHSFJevDBBzV+/Hh9+eWX2rNnj4KDg3XhhRdq5MiRVZu/d+rU6axeOwCcTnSwrz6/c6DuCfLVvCUjdSRpubqFOTSwUyuNHz9eHTt21AsvvCBfX18uKgMepiHUT06noQe/2CBrqz6y2r21d+t6lZSUyNfX94THmDVrlm655RZ5eXnp66+/Vv/+/c/m5QLAaT16UXstTsrU7swiPf7NJv17Ys/jLqJaLBZNnTpVN910k7755hulpqYqIiKCegqAW6nP+vBkXvvvu5KktoMu0pW9W5z1/Xv37q127dpp48aN2rt3L5/JgMn8vGxV33+0PEV94sM0rnuzat+f+ss90Qw7R2eaht2tWzctWrRIa9euPeGHdXl5uTZv3iwfHx+1a3fyTTmPVfmDPSAg4IQpmPO2HtIDn62X7D5SRbn+e1WHqkZYpdatW2vKlCnHHdu0aZMOHTqkxMRENWtW/Q8EAKiOQB+73pnUW0+E+OrTVa2ULGl4/3j16NVBP8ydI6fTqcGDB1dNLwfgGRpC/fTu0r1auTdbAb7eCgoMUF5ujnJzc6sGCVVauHChrr76aknSxx9/rAsuuKBarxEAqsvXy6ZXru6hy95Yqrmb0vXZqv26pu+JF3O7du2qrl27Hnfsu+++o54C4Bbqsz78vRnzVih99xZZvHz0r8fulM1as1ldERGu63CZmZlcIAcaiE6xIUqXNOWrjWobHaQOTU+cWXo61F/uhUUt69iYMWMkSV9++eUJt82ePVslJSUaMWLESUch/17lxZnKNUol16jmqfN26rYPVisnfb+cJYXyDwhQ/47x1cr38ssvS5Juv/32ap0PAGfLbrPqn5d30cMXun4pee+3ZN34zko9/yKfPwBOrq7rp21p+Xr+xx2SpNu7uxphAQEBVRcwKq1Zs0Zjx45VWVmZpk2bpgkTJpzT6wKAU+nSPER/uqCtJOnJWVu0YX9ute43depUSdRTANxfbdaHxyopd+jR//u3JKnTwJEa0vHsZ4VJUn5+vtatWyeLxaJWrVrV6DEA1L5uzUM0pE2ESsqduuPDNcorLj/nx6T+arxohtWxW2+9VcHBwZo1a5a+/vrrquMZGRl65JFHJEl/+tOfTrhf+/bt1b59ex04cKDqWKtWrao60XfccYd2p2Zo8nur9OovSXKWFMpn+TuSpMvGjz+uK11UVKTt27cf9/hOp1MvvPCC3nvvPbVr10733Xdf7b1oAB5nxIgRat++vVauXHnc8YyMDKWkpMhiseie8xL13xt6yd/m1Jy3/qElixaq36AhuvLKK01KDaChqsv6KfVQlu7+eK3KKpwa1NJPs994WpJrT4pj66cdO3booosuUkFBgV599dWT7mMBALXpq2fuUO4H96hg/zbd+dEaZRWWSvpfPXWssrIy/fGPf9SCBQt03nnnUU8BcHu1WR8e69VfknRwzTxJ0t8evOu0Gd544w1t3LjxhOMHDhzQxIkTVVBQoDFjxigqKqrarwtA3bJYLHrtmh5qHuqnlOxi3fHRapWUO6puP9P1rGNRfzV+FuNM85Bxzr766itdddVVMgxDw4YNU0REhH7++Wfl5ubqvvvu06uvvnrCfSrXiN+7d6/i4+Orjq9YsUIjR45UYWGh7P4h8mraVlaLZM3cpYK8HMXHx2vp0qWKjY2tuk9ycrJatWqlzp07q02bNrLZbFq5cqVSUlIUHx+v+fPnM2oFQJW7775ba9euleRa3mHPnj2Kioo67nNi+fLlx90nPj5e+/bt04IFCzR8+PCq4wsXLtT555+vnj17qlWrVqqoqNDiJUt1OCtT3tGtFXfdP/Tq5CG6qEvTenltABqPuqqffIOayBLVRj52q6yZu5Sdffik9VOPHj20fv16RUZG6uKLLz5pxvbt2+vRRx+t3RcOwC2cSz3V/c6pyglpowEJ4frwlr5asnjRCfXUb7/9poyMDPXo0UPz5s1TeHh4vb4+ADBDbdaHkrQuJUeXPPGODn74sMIiopSRflA2m+2Ex6g0fPhw/frrr+rYsaPat28vLy8v7d+/X2vWrFFpaak6deqkefPmqWlTfr8FzHC6+utImUNJGYWKuv5Fje4Uo39f11M2q+WsrmdRfzV+NMPqydKlS/Xss89q+fLlKisrU4cOHXTPPffopptuOun5p/phXVrh0F8++EX/ee1llezbIGfhYXl72ZXQqpXGjh2rhx9+WGFhYcc9Vn5+vqZMmaJFixZp//79cjgcatWqlSZMmKCHHnpIgYGBdfa6ATQ+lQX+6fz+R8epiof9+/frySef1NKlS3XgwAFZrVa1a9dOl024SpubDNSy5DxJ0n3nJ+r+kW1lreHa7ADcU23VT5K0e/du3fLAE1q6eKEcBa76qXXCqeunys+10xk2bJgWLlxY05cHwI2dSz314Vdz9M/1VhWVOXTr4Faa1C3opPXUxIkTde+998rb27suXwoANCi1VR/ml5RrzGuLtf7Tl1S4bq4eeOCBqq1ETmXOnDn6+uuvtXz5cqWlpamgoEAhISHq3LmzrrjiCt12221nvUwjgNpTnfqrzWNzVeZw6tq+LfWPyzqrVatWZ3U9i/qrcaMZ1ois2ZetKV9t0q6MQknSxH4t9ZcxHeXnfepRKwDQUFU4nPrn99v1zhLXHj4jO0Rr6tXdFOTrZXIyAO5o0c5M3fTeKjmchp68pKNuHsyseAAN1/eb0nTXx66Rzc+M76wb+seZnAgA3IdhGLrv0/X6bsNBNWvip7l/HKIQP34PBTzB95vSdPcna2UY0nX9WuqZcZ0ZmO1BaIY1AtlFZXp53g59vCJFhiFFBHrr2fGdNboz064BNH5frknVYzM3qazCqTZRgfrvDb2UEMmMVQC1Z3t6vib8Z5kKSyt0WY9mevmqblWjhAGgoXrtlyS9PG+nrBbpzet76YJOMWZHAgC3MG3xHj07Z5tsVos+v6O/esWFnflOANzG56v3a8pXG2UY0uU9mun5CV1lt1nNjoV6QDOsASt3OPXBsn169eedyi+pkCRN6NVcT4zpoCb+TMUE4D7WpeTojg/XKKOgVIE+dj13RRdd0jX2zHcEgDPYm1Wkq/67TJkFperXKkwf3NJXPnZm1QNo+AzD0GMzN2nGyv3ysVv1yW39uGALAOdo0c5MTZ6+Uk5D+uulHTV5EKsFAJ5o1voD+tPnG+RwGhrdKUavXNNdvl78nujuaIY1QA6nobmb0jT1553ak1kkSerQNFh/uaSDBraOMDkdANSNjPwS3TtjnVbuzZYk3TggTo+P6cBFawA1tj+7WFf/d5kO5pWofUyQPr29PwOKADQqFQ6nbv9wjeZvz1CQj10f3tpP3Vs0MTsWADRKG1Nzde1by1VU5tCVvZrr+QldWS0A8GA/bknXHz5ZpzKHU33iQ/X2jb35fdHN0QxrQBxOQ3M2pen1X5KUdHRfsIhAbz10QTtd2buFbKxfCsDNVTicenneTr2xcLckqUuzEL1xXU+1CPM3ORmAxmZbWr4mvbtSGQWlah0ZoM/uGKCIQB+zYwHAWSsuq9Dk6au0cm+2gnzt+uiWfupGQwwAzkrSoQJd/dZyZReVaWDrcE2/qQ8DLwHot91ZuuPDNSooqVBCZIDem9xXLcO5BuWuaIY1AHnF5fpybao+Wr5Pe7NcM8GCfe26dUiCbhoUryBfNvEE4FkWbM/QA5+vV25xuYJ87XphQlf2SQRQbQt3ZOgPM9apoKRC7aKD9MEtfRUd7Gt2LACosaLSCt00fZVWJrsaYtMn91HveJZMBIDq2Jiaq0nvrlROcbm6NQ/Rx7f1V6CP3exYABqIHekFumn6Sh3MK1Gov5f+PbGnBiayOps7ohlmos0H8vTR8n36Zv0BlZQ7Jf2vCTZ5ULyCaYIB8GAHco/oD5+s1dqUXEnSlb2a66mxnfilBcApOZyG3liwSy//vFOGIfWND9Pbk3orxI+aCkDjV1RaocnTV2pVco687Va9dGU3XdqNPVYB4HTmbz+k+2asV2Fphbo1D9F7N/VVaADLoAE4XnpeiW7/cLU2pubJZrXosYs76OZB8Syl6mZohtWz/dnF+nbDQX234aC2pxdUHW8XHaQbBsRpfI9mXOgFgKPKHU699NNO/XfRbhmG1CLMTy9f1V19GAkN4HeSDhXoka82at3RBvrEfi311KUdWf4GgFs5UubQHz9dp5+2HpIkPTK6ne4a1poLNQDwO06nof/8ulsv/rRDhiENSAjX25N6c80NwCmVlDv02Neb9PW6A5KkK3o2198v6yxfL36ndBc0w+pBZkGp5mw8qG83HKya4SBJXjaLLuwUoxsHxKtPfCi/wADAKazYc1h/+nyDDuQekcUi3TmstR4Y2VbedqvZ0QCYLKeoTK/NT9KHy/apwmkoyMeuJy/tqCt7tzA7GgDUCYfT0LNztmr60mRJ0qiO0XpxQjeF+DMLFgAk10D0h77YoBV7syW5Bkn99dJO/P4I4IwMw9D0pcn6+9xtcjgNdWseojdv6KWmIX5mR0MtoBlWR/KOlOvHLen6bsNBLd2VJefRd9licY1GGdstVqM7x6iJP1OzAaA6CkrK9fR3W/XlmlRJUoemwXr+iq7q0jzE5GQAzJCeV6K3F+/RjJUpKi5zSJJGdojWM+M78YsKAI/w0fJ9+tt3W1XmcKp5qJ9eu7aHerYMNTsWAJimtMKhaYv36l/zd+lIuUP+3jY9dWlHXd2npdnRADQyS3dl6Z5P1iq3uFzhAd564cquOr99tNmxcI5ohtWiknKHftmWoVnrD2jhjkyVOZxVt3Vr0URju8Xqkq5N2cAdAM7BD5vT9OevNymnuFxWi3TjgHg9eEFbBbHPIuD2SiscWrA9Q1+tPaAF2zNUcXS0UafYYD16UXsNaRNpckIAqF+bD+Tp7o/XKiW7WFaLdMvgVnpgVFv5e7MMGADP4XQa+nFLup7/cYf2ZhVJkvq2CtMLE7oqLjzA5HQAGqv92cW648M12pqWL0maPDBej17UnmUTGzGaYeeowuHU4l1Z+m79Qf24JV1FR0cmS1KbqECN6x6rS7vF8sMXAGpRZkGpnp2zVbPWH5QkxQT76q9jO+rCTjEsOQu4GcMwtG5/rr5em6rvNqQp70h51W19W4XpnvMSNbRNBP/vA/BY+SXlemrWFs08ur9FdLCPHrmwvS7r0UxWK5+NANxXhcOp7zen61/zd2nHoQJJUmSQjx6/uIPGdY+lPgRwzkrKHXr+hx16d+leSVL7mCC9dFU3dYpllaLGiGZYDRiGobUpufp2/QHN3pimw0VlVbc1a+Knsd1jNbZbrNrHBPGDFwDq0KKdmfrLrM3ad7hYkjSkTYT+fFEHdYwNNjkZgHO1P7tYM9cd0Mx1B6pG+Equ5vf4Hs10ec9mahsdZGJCAGhY5m8/pKe+3aL92UckSZ2bBesP57fRqA7RNMUAuJXMglJ9tipFH69IUVpeiSQpyMeumwbF67ahCawaAqDWLdiRoYe/2KCswjLZrBbdOqSV7h/RVn7ezBJrTGiGnYVdGQWatf6gZq0/qJTs4qrj4QHeGtO1qcZ1j1XPlqE0wACgHpWUO/Sv+bv030W7Ve4wZLFIl/VopgcvaKdmTdg3CGhMikorNHdTmr5Yk6qVRzc8lyQ/L5su6hyjy3s214DW4bJxURcATqqk3KHpS5P17wW7VFhaIUlqGx2oW4ck6JKuTVk+EUCjVblawAe/JWvOpjSVO1yXM8MDvHV9/zjdPKiVQvxpggGoO5kFpXrq282auyldktQizE/PjOus4e2iTE6G6qIZdgbpeSX6dsMBzVp/UFsO5lcdD/C26cJOMRrbPVaDEyNkt1lNTFk/MjMzzY4A4BxFRrrvfjr7DhfphR93aPbGNEmSt92qSQPidMew1ooI9DE5HYBTMQxDa/bl6PPV+zVnY1rVktMWizSwdbgu79FcozvHKMCn8V7ApYYC3EtjqKeyCkv17pK9+nDZPhUcbYoF+dg1tnusxnVvpl5xoQwsANAoZBaUatb6A/pidWrVUoiS1KNlE904IE4Xd2kqH3vjm5lBfQicnYZUf83bekhPztpcNTN1UGK4Hr6wvbq3aGJuMJwRzbCTOJRfou83pWnu5nStSs5W5Ttkt1o0vF2kxnZvplEdoj1uGiQz3oDGzxM+8jfsz9Vz32/Xsj2HJblmlFzfv6VuG5qgqCBfk9MBqHQov0RfrU3Vl6tTteeYZRDjwv11Ve8WuqxHM8W6yexOaijAvTSmeirvSLk+WZGiGStTjlvdJDLIRxd2itYFHWPUKy60UQ84AOB+yiqcmr89Q1+u2a8FOzLlcLo+d33sVl3aLVY3DohT1+ZNzA15jqgPgbPT0OqvwtIKTZ23Ux8sS66aqTq8XaQmDYzXsDaRLFHdQNEMO+pg7hF9vzld329K0+p9Ocfd1jc+TON6xOrizk0VGuBtUkLz8YMaaPw85SPfMAwt3JmpV+bt1IbUPEmuX5yu7N1ckwbEqw37DAGmKKtw6pdth/TFmlQt3JGho9c15Odl05iuTXVV7xbqE+9+S0672+sBPF1jrKecTkPL9xzWl2tTNW/rIRWUVFTdZrNa1Dk2WH3iw9SleYjaRgcpITKgUc60ANC4bTmYpy/XpGrW+oPKLiqrOt69RRNd2bu5LukaqxA/91gKkfoQODsNtf7an12sV35O0sx1qVW/38aH+2t8j2Ya06Up158aGI9thhmGoW1pBfp1Z6Z+2pqudSm5x93eKy5UF3dpqtGdY9hz5ih+UAONn6d95BuGoV93ZurVX5KO+5wf2DpcNw6I14gOUfLygGVuAbNtS8vXF6tT9c36A8dd2OgdF6qrerfQxV2bKtCNZyVQQwHupbHXU2UVTi3dnaUfNqVrya4sHcg9csI5NqtFLcP8FRXko6hgX0UF+SjEz0u+Xlb5etnka7fJbrPIbrPKy+r6ardZ5GU9+tVmkY/dpib+XgoP8PG4VVUAVF9WYam+23BQX6xO1da0/21PEhnko8t7NtOEns3d8mIy9SFwdhp6/ZWcVaQPl+/T56v3HzfoKCEyQP1ahatfqzD1aRVGn8FkHtUMyykq0+JdWVq0M1OLdmYqo6C06jaLReoTF6aLusToos5NFRPCUlq/xw9qoPHzoI/84xiGoWV7Duv935I1b+uhqtE64QHeurRbrC7r0Uxdm4fwOQfUospZ99+sO6BNB/KqjkcF+eiKXs11Za/mSogMNDFh/eGzBXAv7lZPHcg9otXJ2VqdnKMd6QXanp6v/GMu4tQGPy+bYkJ81SLMX3Fh/ooL91fb6CC1jwlSZJAPn5OAhzlS5tC8bYf0zboD+nXn/5ZB9LZZNbJjlK7s1UJD2kTI7sYDF/ncA85OY6m/issq9P2mdM3dlKZFSZlVSyhWCg/wVmJUoNpGB6ltdKASo4KUGBWoiEBvPhfqgds2wxxOQ7syCrU2JUdr9+VobUqOdmcWHXeOn5dNA1qHa3i7SF3YKUbRwTTATofNPYHGryFtOGqWA7lH9NHyffpidaqyCv83KKJ1ZIDGdI3VyA5R6hwbwvrOwFlyOA1tS8vXkl1Z+mFzutbvz626zctm0cgO0bqqt/tf2DgZaijAvbh7PWUYhjIKSrUns0gZBSXKLChVRkGpCkoqVFruUEmFQyXlTpU7XH8qHIbKnYYqqr53fS2tcCinqFxlDudpny/U30vtYoLUPiZY7WKCXH+ig9jHDHAzDqehFXsO6+t1B/TD5nQVlv6v6d6lWYgm9Gqusd1iPWZ7EupD4Ow0xvor70i5Vuw5rFXJ2Vq5N1ubD+ZXNf9/L8TPS4lRgUqMDHR9jQpU68hANQ/14/pULWrUzbDSCocy8kuVlleitLwjOphboqSMAu1IL9CujEKVVpxYdLePCdLQtpEa1jZSveNDWQcdADxUhcOpxbuyNHPtAf24Jf24nxlRQT46v32U+ieEq3d8qJqH+puYFGh4DMNQZmGptqUVaFtavtbsy9GKPYePm0lQOev+4i4xGtu9mcI85MIGAOB/DMNQYWmFsovKdDC3RPsOF2lfdrGSs4q041CBkrOKdIprQmrWxE8JkQFqHRlY9bVlmL+ig33lbfesQRVAY1XucGrl3mzN23pIP25JV1peSdVtzZr46bIezTS+RzMlRnnGagEAPNuRMod2ZRRq56EC7cwoUNKhQiVlFCg154hO1aHxsVvVOjJQ7Zu6ZtS3jwlW+6ZBigxkZn1NmNoMS8s7ohd+3CGn05DTkByGIafTkOPo351G5feur8VlDhWWVqiotEKFJRUqKD390g3+3jZ1a95EPeOaqGfLUPVoGcqFGADACQpKyvXjlkOatzVdi5OyVFzmOO722BBf9Y4PU9fmIWoXE6S20UGKYkkfNBIHc49oxsoUGUdrK0Our6r8uyE5DcmQ63vjmHMqb5MM5R+p0KH8Eh0qKNGh/FKVnWTQUaCPXX3iQ3V++yhd2ClGUcy6BwCcRkm566LQ9vQC7UjP1/b0Am1PL1DmMVsanEx4gLdiQnwVHeyrYF+7An3tCvTxUpCvXT52q6wWi2xWi6wWyWq1yGqxyGm4rjMYR687VF5zqDw+ODFCnZuF1NMrB9yTYRg6kHtEq5KztWB7phbsyDhu75xgX7vGdHUtU987LpTZDgAgV5NsT1ahdmcWaVdGoXZnFGpXRqH2ZhWdcoZ9WID3/5pjMUFq3zRIbaKC2Kf1DExthu08VKALpi46p8fwtlvVNMRXMcG+ahriq4TIwKplFVqG+fODFQBwVkorHFq+J1uLdmZq9b4cbTmQp4qTDFkO9rWrWai/mjXxVdMQPzVt4qvwAG8F+NgV4GNXoI9dfl62oxdiXBdjLBbX2vCGYajCaajC4RrsUeGs/Or8398d/zvevmmQWnvI3kqofetScnTZG7/V+uNaLFKriAB1bBqsLs1C1D8hXJ1igz1uCUQAQO3LKSrT7sxC7cks0u5M18WhPZmFSs05csZlF2vqmfGddUP/uDp5bLi/w4WlWr4nW952q3yO/nF9b5Ovl1UBPnb5e9vk722XzU2uUzmchlJzipV0qFC7Mgu15WC+VidnHzf7S3I1r0d0iNLIDtEa2jZSvl5cqAWA6nA4De3PLtaOQ66V8HakF2hbev4pZ9ZbLVJ8eMDRWWTBahsdpOahfmoa4quwgPrZk8zpNFRc7lBxaYWKyhwqKq1Q8dGvRWUV6tEyVM2a+NV5jlMxtRmWU1Smz1fvl81qkcVikc0i10XDoxcObRbX9zarZLVY5OdlU6CvXUE+Xgr0tSvEz0uh/l6MzAcA1JnisgqtT8nVquQcbU/PP+OSPnXhsYvb6/ahrevvCeFWUnOK9faiPbJYLLJYXDWVRa6R8hZJOvbY0XMsv/+7pAAf+9FR+D6KDvZVZJAPy00DAOqVYRjKKS5Xel6J0vOPKCPftZdZQeXqMSWuPcocTqNqRnTlyjOV1xWsx/w8tFZ+tVp0WY9mGpQYYfZLRCP12+4sTXx7RbXO9fOyKcDH1Rjz97ZVNcoCvO3y93F9DfCxK8DbJn8fu3y9rK7rY8f+27VW1mnH/Ds+WthVzvI3js78r5wRqaPHKmf/u84x/ve16pjrnNIKp4pLK6ouahaXOZR7pFwZBaXKzC9RZmGpyh0n/lJks1rUOTZY/VuH64KO0ereItRtGoAA0BCUlDuUdKhQ29LztT2tQDsO5WtbWoGyi8pOeR9vm1UxR5tiQb52Bfm6BnEH+ngpwMdWVSNVzqq3WKQKh6GyCqfKHE6VljtcXyucKil3qKi0ssHlUHFZhYpKXV9/v9LS771ydXeN79Gstt+SamvUe4YBAGCGknKHkg8X6WCua7/KtLwjSsstUe6R8qrlfCtHv1QuMVe1FI/TkM1qkc1qld3qWsLHbjv69ffHj36d2K+lxnU3r1gAAAAAcGob9ufq73O3qazCdaGwtMJR9X1JmUNFZRX1Opiuvngf3csmMSpQbaMC1SsuVN1bNpG/t93saADgUSr39d6RXqDtaa5lp5MyCpSWV3LG5afrgtWi4wZ5+B8dBHLXsNY6r31UveepRDMMAAAAAAAAqCPG0ZlWVctFHTOKvupr2f+WlTp2eakj5Y6qfV0r97j7396uxvH74RmuC5AWWY7O/nd9b6lcsl3HrwJw7KoBlqMzyypXBfA9OoPNz8vu+uptU5Cvl6KCXKsEVH5l1hcANGxlFU5lFJQoLa9EOUVlKiytUGFphQpKXF+LSyuO30vV6frebjt22V+rvG2u710/H1wzmF1bhbgaXcc2v3y9rA1yNT+aYQAAAAAAAAAAAHBb7HAOAAAAAAAAAAAAt0UzDAAAAAAAAAAAAG6LZhgAAAAAAAAAAADcFs0wAAAAAAAAAAAAuC2aYQAAAAAAAAAAAHBbNMMAAAAAAAAAAADgtmiGAQAAAAAAAAAAwG3RDAMAAAAAAAAAAIDbohkGAAAAAAAAAAAAt0UzDAAAAAAAAAAAAG6LZhgAAAAAAAAAAADcFs0wAAAAAAAAAAAAuC2aYQAAAAAAAAAAAHBbNMMAAAAAAAAAAADgtuzVOckwDJWVldV1FgAAUM+8vb1lsVjMjgFRbwEA4K6otxoO6i0AANxTdeqtajXDysrK9Nxzz9VKKAAA0HA8+uij8vHxMTsGRL0FAIC7ot5qOKi3AABwT9WptyyGYRhneiAzR86kp6frvffe0+TJkxUTE2NKBnfG+1u3eH/rHu9x3eL9rVsN4f1lpHLDUd16qyH8u/EUvNf1i/e7/vBe1y/e7/rTUN9r6q2GwxNnhjXU/y8aC96/muO9qzneu3PD+1dzjfm9q7WZYRaLxbRRTN7e3lVfGUlV+3h/6xbvb93jPa5bvL91i/cXx6puvcW/m/rDe12/eL/rD+91/eL9rj+81zgTM69vmYX/L84N71/N8d7VHO/dueH9qzl3f++sZgcAAAAAAAAAAAAA6kqDb4YFBgZq2LBhCgwMNDuKW+L9rVu8v3WP97hu8f7WLd5f1AT/buoP73X94v2uP7zX9Yv3u/7wXgMn4v+Lc8P7V3O8dzXHe3dueP9qzt3fu2rtGQYAAAAAAAAAAAA0Rg1+ZhgAAAAAAAAAAABQUzTDAAAAAAAAAAAA4LZohgEAAAAAAAAAAMBt0QwDAAAAAAAAAACA26IZBgAAAAAAAAAAALfVaJphRUVF+uijj3TVVVepbdu28vPzU5MmTTRs2DDNmDHD7HhuY9GiRXrooYd03nnnKSQkRBaLRZMnTzY7VqOzatUqXXzxxQoNDVVAQID69u2rTz75xOxYbuOjjz7SHXfcod69e8vHx0cWi0Xvvfee2bHcwoEDB/TKK6/oggsuUMuWLeXt7a2YmBhdccUVWrFihdnxGr3c3Fzdd999GjBggGJiYuTj46NmzZrp/PPP11dffSXDMMyOiEaE2qj+USfVDeqm+kH9VH+op+oPtRVwdqgfzw21YPVQ29UMtVrNUXvVnKfVUnazA1TX4sWLdcMNNyg8PFwjRozQFVdcoYyMDH399deaOHGifvvtN73++utmx2z03n33Xb3//vvy9/dXy5YtlZ+fb3akRmfhwoW68MIL5e3trWuuuUYhISH6+uuvdd111yk5OVmPPfaY2REbvSeeeEL79u1TRESEmjZtqn379pkdyW28/vrr+r//+z+1bt1ao0aNUlRUlJKSkvTNN9/om2++0YwZM3TVVVeZHbPRysrK0rvvvqv+/ftr/PjxCgsLU0ZGhr777jtNmDBBt912m9566y2zY6KRoDaqf9RJtY+6qf5QP9Uf6qn6Q20FnB3qx3NDLXhm1HY1R61Wc9ReNedxtZTRSKxfv974+OOPjbKysuOOp6enG3FxcYYkY+XKlSalcx+rVq0yNm/ebFRUVBjLli0zJBmTJk0yO1ajUV5ebrRu3drw8fEx1q5dW3U8Pz/f6NSpk2G3242dO3eamNA9zJs3z0hOTjYMwzD++c9/GpKM6dOnmxvKTXz11VfGokWLTji+aNEiw8vLywgLCzNKSkpMSOYeKioqjPLy8hOO5+fnGx07djQkGZs3bzYhGRojaqP6R51Uu6ib6hf1U/2hnqo/1FbA2aF+PDfUgqdHbXduqNVqjtqr5jytlmo0yyR269ZNEydOlJeX13HHo6Ojdccdd0iSfv31VzOiuZXevXurU6dOstlsZkdplObPn6/du3dr4sSJ6tGjR9XxoKAg/eUvf1FFRYWmT59uYkL3MHLkSMXFxZkdwy1dfvnlGjJkyAnHhwwZovPOO0/Z2dnatGmTCcncg81mk91+4qTsoKAgXXjhhZKkXbt21XcsNFLURvWPOql2UTfVL+qn+kM9VX+orYCzQ/14bqgFT4/a7txQq9UctVfNeVot1WiaYadT+UP8ZP/hgPq0cOFCSdIFF1xwwm2Vxygs0VjxWVt3SkpKNH/+fFksFnXs2NHsOHAD/P+KxoC6CZ6Iz+f6QW0FnD0+n3CuqO3QEPHZVjPuWks1+n8FDodDH3zwgSwWi0aOHGl2HHi4pKQkSVKbNm1OuC00NFQRERFV5wCNSUpKin7++WfFxMSoS5cuZsdp9HJzc/XKK6/I6XQqIyNDc+fO1f79+/XUU0+d9PMDOBvURmgsqJvgaain6g61FXBuqB9RG6jt0NBQe1Wfp9RSjb4Z9pe//EWbNm3SzTffrM6dO5sdBx4uLy9PkhQSEnLS24ODg5WamlqfkYBzVl5erhtuuEGlpaV6/vnnWRKiFuTm5urpp5+u+ruXl5deeOEFPfjggyamgrugNkJjQd0ET0I9VbeorYBzQ/2I2kBth4aE2uvseEotVe/LJEZERMhisVT7T+UU25N566239M9//lM9evTQq6++Wn8vooGrzfcYgGdzOp26+eabtWjRIt1222264YYbzI7kFuLj42UYhioqKrR371797W9/0+OPP64rrrhCFRUVZsdDPaM2ql/USQDqG/VU3aO2gqehfqw5akHA/VF7nT1PqaXqfWbYtddeq4KCgmqfHxMTc9Lj06dP15133qkuXbpo3rx5CgwMrK2IjV5tvcc4e5WjXypHw/xefn7+KUfIAA2NYRi67bbb9NFHH+n666/Xm2++aXYkt2Oz2RQfH69HH31UNptNjzzyiN5++23dddddZkdDPaI2ql/USQ0HdRM8AfVU/aK2gqegfqw5asG6Q22HhoDa69y4ey1V782w119//Zwf491339Vtt92mjh076pdfflF4eHgtJHMftfEeo2Yq11BNSkpSr169jrstJydHWVlZGjhwoBnRgLPidDp16623avr06br22mv13nvvyWqt98nEHuWCCy7QI488ooULF7pNkYHqoTaqX9RJDQd1E9wd9ZS5qK3gzqgfa45asO5Q28Fs1F61yx1rqUb3r+Hdd9/Vrbfeqvbt22v+/PmKjIw0OxJQZdiwYZKkn3766YTbKo9VngM0VMcWD1dffbU+/PBD1lauBwcPHpQk2e2NfjtP1DNqIzRW1E1wZ9RT5qO2Ak6N+hF1gdoOZqL2qn3uWEs1qmbYO++8c9wP66ioKLMjAccZMWKEEhIS9Mknn2j9+vVVxwsKCvTMM8/Ibrdr8uTJpuUDzsTpdOqWW27R9OnTdeWVV+qjjz6ieKhF69evP+mSEdnZ2XrsscckSRdddFF9x0IjRm2Exoy6Ce6Keqr+UFsBZ4/6EXWF2g5mofaqOU+rpSyGYRhmh6iO+fPna+TIkTIMQ3fcccdJ1+zt3r27xo8fX//h3MiSJUs0bdo0SVJmZqbmzp2r1q1ba/DgwZKk9u3b69FHHzUzYoO3YMECXXjhhfLx8dG1116r4OBgff3119q7d6+effZZPf7442ZHbPSmTZumJUuWSJI2bdqktWvXatCgQUpMTJQkjR8/ns+CGvrrX/+qp59+WoGBgfrjH/940tEf48ePV/fu3es/nBu4//77NW3aNJ133nmKi4tTQECA9u3bpzlz5qiwsFBXXHGFPv/8c6bxo1qojeofdVLto26qP9RP9Yd6qv5QWwFnh/rx3FALnhm1Xc1Rq9UctVfNeVwtZTQS06dPNySd9s+kSZPMjtnonel9HjZsmNkRG4UVK1YYo0ePNkJCQgw/Pz+jd+/exkcffWR2LLcxadKk0/47feqpp8yO2Gid6b2VZEyfPt3smI3W4sWLjcmTJxvt27c3goODDbvdbkRFRRmjR482PvnkE8PpdJodEY0ItVH9o06qG9RN9YP6qf5QT9Ufaivg7FA/nhtqweqhtqsZarWao/aqOU+rpRrNzDAAAAAAAAAAAADgbLnJ/DYAAAAAAAAAAADgRDTDAAAAAAAAAAAA4LZohgEAAAAAAAAAAMBt0QwDAAAAAAAAAACA26IZBgAAAAAAAAAAALdFMwwAAAAAAAAAAABui2YYAAAAAAAAAAAA3BbNMAAAAAAAAAAAALgtmmGAh7v11ltlsVg0atQoGYZxwu1PPvmkLBaLunTpotLSUhMSAgAANG7UWwAAAHWLegvAmViMk306APAYhYWF6tatm/bs2aOpU6fq/vvvr7ptxYoVGjRokGw2m1auXKlu3bqZFxQAAKCRot4CAACoW9RbAM6EmWGAhwsMDNSHH34om82mP//5z9qyZYskqbi4WDfccIMcDoeeeeYZCgUAAIAaot4CAACoW9RbAM6EZhgADRw4UI888ohKSkp0/fXXq6ysTH/605+UlJSkoUOH6qGHHjI7IgAAQKNGvQUAAFC3qLcAnA7LJAKQJJWXl6tfv35at26dRo0apXnz5ik4OFgbN25UXFyc2fEAAAAaPeotAACAukW9BeBUaIYBqLJ161b16tVLJSUlkqT33ntPkyZNMjkVAACA+6DeAgAAqFvUWwBOhmYYgCplZWXq0qWLdu7cqZCQEKWmpiowMNDsWAAAAG6DegsAAKBuUW8BOBn2DANQ5fHHH9fOnTtltVqVl5enBx54wOxIAAAAboV6CwAAoG5RbwE4GZphACRJixYt0ssvvyx/f3/NmzdPTZo00bRp0/Tdd9+ZHQ0AAMAtUG8BAADULeotAKdCMwyA8vPzNWnSJDmdTr3wwgs6//zz9e9//1uSdOuttyozM9PkhAAAAI0b9RYAAEDdot4CcDo0wwDovvvuU3Jysi644ALdfffdkqSJEyfq6quvVkZGhm6//XaTEwIAADRu1FsAAAB1i3oLwOlYDMMwzA4BwDwzZ87U5ZdfrtDQUG3evFmxsbFVt+Xk5Khz5846ePCg3n33Xd10000mJgUAAGicqLcAAADqFvUWgDOhGQZ4sEOHDqlz587KysrSjBkzdM0115xwzk8//aTRo0crMDBQGzduVHx8fP0HBQAAaKSotwAAAOoW9RaA6qAZBgAAAAAAAAAAALfFnmEAAAAAAAAAAABwWzTDAAAAAAAAAAAA4LZohgEAAAAAAAAAAMBt0QwDAAAAAAAAAACA26IZBgAAAAAAAAAAALdFMwwAAAAAAAAAAABui2YYAAAAAAAAAAAA3BbNMAAAAAAAAAAAALgtmmEAJElz587VyJEjFRYWpoCAAPXs2VOvv/66nE6n2dEAAAAatb179+rtt9/Wbbfdpm7duslut8tisejZZ581OxoAAECjZxiGlixZoocfflj9+/dXkyZN5O3trdjYWF1xxRVasGCB2REBNAAWwzAMs0MAMNdzzz2nP//5z5KkhIQEBQYGavPmzXI6nRo7dqxmzpwpq5XeOQAAQE3cf//9evXVV084/swzz+iJJ54wIREAAID7+OWXXzRy5EhJktVqVWJiogICApSUlKTCwkJJ0hNPPKFnnnnGzJgATMbVbcDDLVu2TI899pisVqs++eQT7d69Wxs2bNDatWsVHR2tb7/9Vi+//LLZMQEAABqtiIgIXXLJJfrb3/6m77//XldccYXZkQAAANyGYRhKTEzUG2+8oaysLO3YsUNr167V4cOHqwZ/P/vss5o9e7bJSQGYiZlhgIcbM2aM5s6dq9tvv13//e9/j7vtk08+0XXXXafw8HClpaXJy8vLpJQAAADuY/LkyXr//feZGQYAAFAL8vPz5e/vL7vdftLbL774Yn3//fcaO3asZs2aVc/pADQUzAwDPFh+fr5+/vlnSdItt9xywu1XXnmlgoODdfjwYdZXBgAAAAAAQIMTHBx8ykaYJI0aNUqStHPnzvqKBKABohkGeLB169aprKxMvr6+6tmz5wm3e3l5qU+fPpKkFStW1Hc8AAAAAAAA4JyUlJRIkvz8/ExOAsBMNMMAD5aUlCRJatmy5SlH0CQkJBx3LgAAAAAAANAYGIahL774QpI0aNAgk9MAMBPNMMCD5eTkSJJCQ0NPeU7lbZXnAgAAAAAAAI3B22+/rXXr1snb21v333+/2XEAmIhmGODBKqeJe3t7n/IcHx8fSdKRI0fqJRMAAAAAAABwrtauXas//vGPkqRnn31WrVu3NjkRADPRDAM8mK+vrySprKzslOeUlpZKYl1lAAAAAAAANA579+7VJZdcopKSEk2cOFEPPfSQ2ZEAmIxmGODBqrMEYnWWUgQAAAAAAAAagvT0dI0aNUppaWkaM2aM3nvvPVksFrNjATAZzTDAg7Vp00aSlJKSooqKipOes2fPnuPOBQAAAAAAABqi7OxsjRo1Srt379awYcP0xRdfyMvLy+xYABoAmmGAB+vRo4e8vLxUUlKitWvXnnB7eXm5Vq1aJUnq169ffccDAAAAAAAAqqWwsFAXX3yxNm/erD59+ui7775j2w8AVWiGAR4sODhYI0eOlCS98847J9z+xRdfKD8/X+Hh4Ro+fHg9pwMAAAAAAADOrLS0VOPGjdOKFSvUqVMn/fDDDwoKCjI7FoAGhGYY4OEef/xxWSwWTZs2TTNmzKg6vmHDBv3pT3+SJD3yyCPy9vY2KyIAAAAAAABwUg6HQ9dcc43mz5+v1q1ba968eQoLCzM7FoAGxmIYhmF2CADm+vvf/64nnnhCkpSQkKDAwEBt3rxZTqdTY8aM0axZs2Sz2UxOCQAA0DgtXbpU48aNq/p7YWGhSktL5e/vf9zSPevWrVOLFi3MiAgAANBozZgxQxMnTpTk2vM+KirqpOc1bdpUX3zxRX1GA9CA2M0OAMB8jz/+uLp166apU6dqzZo1Sk9PV5cuXXTTTTfp3nvvpREGAABwDsrLy3X48OETjhcXF6u4uLjq7w6Hoz5jAQAAuIXS0tKq75OSkpSUlHTS8+Li4uorEoAGiJlhAAAAAAAAAAAAcFvsGQYAAAAAAAAAAAC3RTMMAAAAAAAAAAAAbotmGAAAAAAAAAAAANwWzTAAAAAAAAAAAAC4LZphAAAAAAAAAAAAcFs0wwAAAAAAAAAAAOC2aIYBAAAAAAAAAADAbdEMAwAAAAAAAAAAgNuiGQYAAAAAAAAAAAC3RTMMAAAAAAAAAAAAbotmGAAAAAAAAAAAANwWzTAAAAAAAAAAAAC4LZphAAAAAAAAAAAAcFs0wwAAAAAAAAAAAOC2aIYBAAAAAAAAAADAbdEMAwAAAAAAAAAAgNuiGQYAAAAAAAAAAAC3RTMMAAAAAAAAAAAAbotmGAAAAAAAAAAAANwWzTAAAAAAAAAAAAC4LbvZAQAgNadYczelaVVyjnYeKlCFw1CAj02dY0M0oHW4LukaKz9vm9kxAQAAal1phUO/bMvQ4qRMbdifp4LSchmG1DoyUKM6RuviLk0VFuBtdkwAAIAGrbisQquTc7QtLV/b0vK1L7tYGfmlMgxDgb52JUQEqkvzEPVo0UR9WoXJy8YcEcDTWAzDMMwOAcDzlDucmrspTZ+t2q/fdh8+7blNQ3z1woRuGtwmop7SAQAA1C2n09BXa1P14k87dCi/9JTn+XnZdH3/lrpreCJNMQAAgGMcKXPo+81p+n5zuhYnZaqk3Fmt+4UFeOvSrk11Ze8W6twspI5TAmgoaIYBqFcl5Q59uSZVb/66W6k5R6qOD0gI1/nto9S5WYj8vG3KKSrTupQcfbX2gA7kus7744g2emBUW7OiAwAA1Ir92cX646frtDYlV5IUHeyjMV1i1T8hTBFBPnI6Da1KztF3Gw5qa1q+JCkqyEevXdtD/RPCTUwOAABgvqRDBfp4RYq+WpuqgpKKquPNmvipe4sm6tA0SK0jAxUV7Cu71aK8I+XakV6gDam5Wr7nsLIKy6ruc3GXGD18YXu1iggw46UAqEc0wwDUi7IKp2asTNG/F+xSRoFr9HN4gLduHBCvK3o1U/NQ/5Per7isQv+cu10fLt8nSZoyur3uGt663nIDAADUpvnbD+n+T9crv6RCAd423TeijSYPipeP/cQloQ3D0MKdmXp29lbtziyS1SL9dWwn3Tggvv6DAwAAmMjpNDR/e4beWbJXy/b8b4WhlmH+Gt+jmS7sFK2OTYNlsVhO+zgVDqeW7MrSl2tSNWdTmgxDslstumlQvB68oJ18vdimA3BXNMMA1Cmn09C3Gw7qpXk7tD/bNcOraYivbh+aoGv6tKz2XmD//XW3/vn9dknSy1d10+U9m9dZZgAAgLrwxer9mvLVRjkNqVuLJvr3xB6nHBB0rOKyCj3xzWZ9vfaAJOnBUW117/mJZ7zYAwAA0NgVl1XoqzWpendpsvZmFUmSbFaLRnaI0nX94jQ4MUJWa81qou3p+fq/77drwY5MSVJCRICmXt1d3Vo0qa34ABoQmmEA6kTlSObnf9ihbUeX94kM8tF9I9ro6t4t5G0/+41Kn/t+u978dbf8vW2ae98QxTOFHQAANBIfLt+nv3yzWZI0oVdz/eOyLmdVDxmGoak/J+m1X5IkSU+M6aBbhyTUSVYAAACzpeeV6P1lyfpkRYryjpRLkoJ97bq2X0tNGhCv2CZ+tfZcC7Zn6NGvN+pQfqm8bBY9MaajbhwQx8AjwM3QDANQ69bvz9U/527Tir3ZkqQgH7vuHN5aNw2Kl7+3vcaP63Aaum7aci3fk63z20fp3cl9aisyAABAnfluw0Hd9+k6GYZ086BWemJMhxqPYH5j4S49/8MOWSzS2zf01siO0bWcFgAAwDxbDubprUV7NGdjmiqcrsvW8eH+umlQK03o1VwBPjW/rnQ6ecXlmvLVRv2wJV2SdEnXpnphQrdqr2gEoOGjGQag1mQVlur5H7br89WpkiRvu1WTBsTp7uGJCg3wrpXn2JNZqAtfWaRyh6H3buqj4e2iauVxAQAA6sJvu7M06d2VKncYunFAnJ4e2+mcRhkbhqHHv9msT1akyN/bpi/uHKBOsSG1mBgAAKD+JWcV6cWfdmj2xrSqY/1ahemWwa00okO0bDUcSHQ2DMPQO0v26rnvt6vCaahvfJimTe6tYF+vOn9uAHWPZhiAc1bhcOqj5fv00rydKiipkCRd3rOZHrygnZrV4rT1Ss/O3qppS/aqdWSAfrh/qLxsZ7/kIgAAQF3bd7hI4/69VLnF5RrTpaleu7ZHrVzIKXc4dfN7q7Q4KUtNQ3z1/R+HqIl/7Qw8AgAAqE85RWV6ed5OzViZUjUT7NJusbpjaII6NzNnwM+KPYd16werVVBSoY5Ng/X+zX0VGeRjShYAtYdmGIBzsnJvtp6ctVnb0wskSZ2bBevpsZ3VKy60zp4z70i5zntxobKLyvTChK66sneLOnsuAACAmigqrdBlbyzVzkOF6tY8RJ/dMUC+XrW3zE7ekXJd9u+l2pNVpAs7RevN63uxrwUAAGhUvt+Upr/M2qyswjJJ0rC2kXpkdLsGMet9y8E8TXp3pbIKy9QqIkAf3tJXzUP9zY4F4BzQDANQI4WlFfrn3G36eEWKJKmJv5cevrCdrunTsl6mrv/319365/fblRARoHl/GlYvzwkAAFBdf/56o2as3K/oYB99e+9gRQf71vpzbD6Qp8veWKpyh6G/X9ZZ1/WLq/XnAAAAqG3lDqeenb1V7y/bJ0lqExWop8d10sDWESYnO97erCJdP22FDuQeUUywrz66ta8So4LMjgWghlhbDMBZW77nsEa/sqiqEXZt3xZa8OBwXdcvrt6aUtf1j1OIn5f2ZBVp7qa0M98BAACgnvyy7ZBmrNwvi0V65eoeddIIk6TOzUI0ZXR7SdLf52zT/uziOnkeAACA2lJUWqHJ01dWNcLuHt5as+8b3OAaYZLUKiJAX901UG2iApWeX6Jr3lqhvVlFZscCUEM0wwBUm2EYmrZ4jya+vVypOUfUrImfPrm1n/55eVeFBtTvPhWBPnbdPKiVJOnfC3aJSa4AAKAhOFxYqilfbZIk3Tq4lQa0Dq/T57t5UCv1TwhTcZlDU77aSE0EAAAarOKyCt303iot3XVYAd42vXVDLz0yur187LW3lHRtiwnx1ed3DFCHpsHKKizVdW8v14HcI2bHAlADNMMAVEtJuUMPfbFRz87ZJqchXd6zmX58YKgGJpo3cmfywHj5e9u0Pb1Aq/flmJYDAACg0hPfbFZWYanaRQfpwQva1fnzWa0W/d8VXeXrZdVvuw/r01X76/w5AQAAzlaFw6nbP1ijlXuzFeRj18e39dcFnWLMjlUtoQHe+vCWvkqIDNDBvBLd8t4qFZZWmB0LwFmiGQbgjPJLynXjuyv11dpUWS3SXy7pqJeu7KZAH7upuUL8vXRp11hJ0oyjSzYCAACY5Zdth/T95nTZrRa9fHU3+XrVzyjnuPAAPXS08fb8D9uVV1xeL88LAABQXS/8uENLdmXJ39um92/pq+4tmpgd6axEBProo1v6KTLIR9vTC/THGevkcDIjH2hMaIYBOK3sojJNfHt51cid92/uq1sGt5LFUj97g53JNX1bSJLmbErjwg8AADBNSblDf/1uiyTpliGt1Ck2pF6ff/LAeLWNDlROcble+WVnvT43AADA6fywOU3/XbRHkvTChG7q2TLU5EQ1E9vET9Nu7C0fu1W/bM/Qc99vMzsSgLNAMwzAKRUe3dR084F8hQd4a8bt/TWkTaTZsY7TvUUTtY8JUmmFUzPXpZodBwAAeKg3f92t/dlHFBPsq/vOb1Pvz2+3WfXkJZ0kSR8s26ekQwX1ngEAAOD3MgtK9ejXrv1UbxvSSmO6NjU50bnp1qKJXrqqmyTp7cV79d2GgyYnAlBdNMMAnFRZhVN3frhGG1PzFOrvpc/u6K/Ozep3hHN1WCwWXdu3pSTps9U0wwAAQP1LOVysNxbuliQ9cUkHBZi0lPTgNhG6oGO0HE5Df5u9VYbB0j0AAMA8hmHoL99sVm5xuTo2DdYjo9ubHalWXNI1Vvec11qS9NjXm7Q/u9jkRACqg2YYgBM4nYYe/GJD1VrO02/qq8SoILNjndLYbrGyWy3alpavXRmMggYAAPXrH3O3qazCqYGtwzWmi7mjnR8f00HeNqsWJ2Vp4Y5MU7MAAADP9uOWdP2wxbWf6gtXdpWXzX0uRT8wsq16tmyigtIK3ffpOpU7nGZHAnAG7vMJBKDW/OfX3fpuw0F52Sx68/peDX5T09AAbw1pEyFJ+m5DmslpAACAJ1m/P1c/bEmXxSI9dWkn0/dVjQsP0ORB8ZKk53/cIScbuwMAABOUVTj1j7nbJUl3Dmtd7/up1jW7zapXr+mhIF+71qXkauo89mwFGjqaYQCO89vuLL300w5J0t/GddbQtg1rj7BTubRbrCTpu40HWRIIAADUmxd+dF3kubxHc7WLaRgz6e8a1lpBPnZtS8vXnE0MFAIAAPXvo+X7lJJdrMggH901vLXZcepEizB/PXd5V0mu/WM3puaaGwjAadEMA1Alp6hM981YL6chTejVXNf0aWF2pGob1TFa3nar9mQWaWtavtlxAACAB1i6K0tLdx2Wt82q+0e2MTtOldAAb902NEGS9PK8nSzbAwAA6lV+Sblen58kybWcoFn7qdaHMV2bamy3WDkNacpXm6i7gAaMZhiAKn/9bouyCkuVGBWoZ8Z1Nn2Zn7MR5Oul89tFSZJmb2QENAAAqHuv/uK6yDOxX0u1CPM3Oc3xbh7cSuEB3tqbVaSv1qSaHQcAAHiQD35LVk5xuRKjAnVV7+Zmx6lzT17aUU38vbQtLV/TFu81Ow6AU6AZBkCSa1PTWesPymqRXryym/y8bWZHOmsXdYmRJM3besjkJAAAwN2t3JutlXuz5W2z6o5hCWbHOUGgj113n5coydW0Kyl3mJwIAAB4giNlDr27NFmSdO95ibLb3P/yc0Sgj54Y01GS9K/5ScooKDE5EYCTcf9PIwBnVFRaoadmbZEk3T60tbq3aGJuoBoa3i5KdqtFuzIKlZxVZHYcAADgxv61YJckaULv5moa4mdympO7rl9LxYb4Ki2vRB8t32d2HAAA4AE+XZWi7KIytQjz0yVdm5odp95c3qOZurVooqIyh17+aafZcQCcBM0wAPrXgl1Kzy9RizC/BrXfxdkK8fNS31ZhkqSftzE7DAAA1I0N+3O1aGembFaL7hrWcDeE9/Wy6Y9Ha7v/LNyt4rIKkxMBAAB3Vu5w6u1FeyRJdwxt7RGzwipZrRY9eUkHSdJnq/dr60H2swcaGs/5RAJwUnsyCzVtsatQeeqSTvL1anzLIx5rRIdoSTTDAABA3amcFTaue2yD2yvs9y7v2Vwtwvx0uKhMM1buNzsOAABwYz9vPaSDeSUKD/DWhF7uv1fY7/WKC9OYrk1lGNJLP+0wOw6A36EZBni4f36/XeUOQ+e1i9SIDlFmxzlnI4++hlXJOcorLjc5DQAAcDe7Mgo1b+shWSzS3cMTzY5zRl42a1XO//66m73DAABAnflgmWtZ5mv6tmj0g61r6sFRbWW1SL9sz9D6/blmxwFwDJphgAdbnZyteVsPyWqRHh/TURaLxexI5ywuPEBtowPlcBpauDPD7DgAAMDNfLAsWZI0on20EqMCzQ1TTVf0bK7YEF9lFJTqi9XMDgMAALVvV0aBlu05LKtFmtgvzuw4pkmIDNTlPV2z4qbOY+8woCGhGQZ4KMMw9Nz32yVJV/dp0Wgu5lRH5VKJ87ayVCIAAKg9BSXl+mpNqiRp8sB4c8OcBW+7VXcOd+1t9p+Fu1VW4TQ5EQAAcDcfLU+R5Lom06yJn8lpzHXf+W1ks1r0685MrU3JMTsOgKNohgEeauGOTK3elyNfL6v+OKKt2XFq1cijzbBfd2RysQcAANSaL9ekqqjMocSoQA1KDDc7zlm5qncLRQX56GBeib5em2p2HAAA4EZKKxxV9cX1/T13VlilluH+urxHM0nSW7/uMTkNgEo0wwAPZBiGXv0lSZI0aUC8YkJ8TU5Uu7q3aKKIQG8VlFZoVXK22XEAAIAbcDqNqn0wJg2Ia3TLS/t62XT70ARJ0hsLd6vCwYAhAABQO+Zvy1B+SYWahvhqSGKE2XEahMq668et6UrOKjI5DQCJZhjgkRYnZWn9/lz5ell165AEs+PUOpvVoqFtIyVJi3ZmmpwGAAC4g0VJmdqbVaQgH3vVPhCNzcR+LRUe4K2U7GJ9u+Gg2XEAAICb+HrdAUnSuO7NZLU2rgFDdaVNdJDObx8lw5CmLWF2GNAQ0AwDPIxhGHp9vmtW2MS+cYoM8jE5Ud0YdrQZ9ivNMAAAUAsqZ4VN6N1cAT52k9PUjL+3XbcMaSVJ+teCXXI4DZMTAQCAxi6nqEwLd2RIki7v2czkNA1L5eywL1anKre4zOQ0AGiGAR5mbUqOViXnyNtm1R3D3G9WWKXBiRGyWKTt6QU6lF9idhwAANCIpeeVVF3kaez7YNw4IF4hfl7ak1mkuZvSzI4DAAAaudkbD6rcYahTbLDaRgeZHadB6dcqTJ1ig1Va4dSXa9izFTAbzTDAw0xbvFeSa7ROdLB77RV2rPBAH3VpFiKJpRIBAMC5+XpdqpyG1DsuVK0jA82Oc04Cfey6edDR2WHzd8nJ7DAAAHAOKpdevqwHs8J+z2Kx6Lp+roFUn6xIkWFQdwFmohkGeJCUw8X6cUu6JOnmwa1MTlP3hrY5um9YUpbJSQAAQGNlGIa+WO0ayXtV7xYmp6kdkwfFK8jHrh2HCvTT1kNmxwEAAI3UofwSrd6XI0ka07WpyWkaprHdYxXoY9eerCIt233Y7DiAR6MZBniQd5fuldNw7aflCVPXh7VzNcMWJ2WyJwYAAKiRNftytDerSH5eNl3sJhd5Qvy8NGlgvCTp9flJjFIGAAA18sPmdBmG1LNlEzUN8TM7ToMU6GPX+B6xkqSPV6SYnAbwbDTDAA+Rd6Rcn6/eL0m6dYj7zwqTpO4tmijIx67c4nJtOpBndhwAANAIVdZPF3dpqkAfu8lpas8tg1vJ39umLQfztXAHS0oDAICzN+fo/qMXd3GPAUN1ZWJf11KJ87YeUl5xuclpAM9FMwzwEJ+uTFFxmUPtooM0ODHC7Dj1wstm1cDEcEnsGwYAAM5ecVmF5mx0XeS5qndzk9PUrtAAb93Q33VhhtlhAADgbGUUlGhVcrYk6SKaYafVMTZY7WOCVOZwau7mNLPjAB6LZhjgARxOQx8s2yfJNQrYYrGYnKj+DG3rWirxV5phAADgLM3dlK6iMofiwv3Vt1WY2XFq3S1DWsnbbtXalFwt28MeFgAAoPp+PLpEYvcWTdSsCUsknsn4Hs0kSTPXHTA5CeC5aIYBHmDRzkwdyD2iED8vje0ea3acejW0jasZtn5/rvKOMBUdAABU36z1rosVl/do7paDiaKCfHVtnxaSpH/N32VyGgAA0Jj8b4nEGJOTNA5ju8XKYpFW7s1Wak6x2XEAj0QzDPAAH69wzQqb0Ku5fL1sJqepX37OYvnuWaiMua+pZ4/ustvtslgs+vTTT82OBgAAGrDMglIt3ZUlSRrnxoOJbh/WWl42i37bfVhr9mWf8rysrCxNmzZNt99+u7p3p6YCAMCTZRaUauXeo0skdmaJxN87Wd3ULNRfTbPWSpK+3XDQ5ISAZ3KfHaABnNTB3COavz1DknRt35Ymp6l/S5Ys0Y4vXpQkFZqcBQAANB5zN6XJaUhdm4coPiLA7Dh1plkTP13eo7k+W71f/5q/S9Nv6nvS85YsWaLbbrutntMBAICG6Odth6rqpBZh/mbHaXBOVTf1iQ/VrAJp5toDumtYa7dceQBoyJgZBri5z1btl9OQ+ieEKTEq0Ow49S46OlrjJt6k8IvvV/f739ENN9xgdiQAANAIVI7YHdvNfWeFVbpreGtZLdKCHZnafCDvpOdER0fr7rvv1vTp07V582ZqKgAAPNgv21yDrkd1iDY5ScN0qrqpW4sm8rZblZRRqK1p+SanBDwPM8MAN1bhcOrTVSmSpIn94kxOY44BAwbok1591P3pecpxOFVU5jA7EgAAaOBSc4q1Zl+OLBbpkq7u3wyLjwjQ2G6x+mb9Qf1r/i69eUOvE84ZMGCABgwYUPV3q5VxlQAAeKKSckfVUtLnd4gyOU3DdKq6yd/brpEdojR3U7q+XX9QnWJDzIoIeCR+gwEameTkZFksFg0fPlxFRUX605/+pBYtWsjPz089e/bUd999V3XuX199R+v/dbf2v3yFbrugh+677z4dOXLkhMcsLCzU3/72N3Xp0kX+/v4KDg7WsGHD9M0335w0w5w5c3TzzTerQ4cOCg4OVkBAgLp166Z//OMfKi0tPeH89957TxaLRX/961+VkpKiiRMnKjIyUn5+furdu/dxmeuCv7ddPeOaSJIyCk7MBwAAPM/paqqB/fqoeNcK9Y0PU0yIr7744gv17dtXAQEBio6Odsua6p7zEiVJP2xJ185DBTV+HAAA4H6OrZvmb0rRgR/eVNqbN6l365gTrkV5Qt10LsZ0cQ20+nFLugzDMCUD4KlohgGNVFlZmUaMGKEPP/xQ3bt3V//+/bVhwwZddtll+vnnnzV16lT945G7ZLHY1L73YDkcDr3++uu69dZbj3ucQ4cOqV+/fnrqqaeUk5OjUaNGqV+/flqzZo0uu+wyPffccyc89y233KIvvvhCISEhGj16tIYMGaL9+/fr8ccf18UXXyyH4+Szr5KTk9WnTx8tXbpUgwcPVo8ePbRmzRqNHz9eP/30U528T5WGtIl0vd78kjp9HgAA0LicrKbav2u7Mr/+uxLK9mjq1KmaOHGi7Ha7LrjgAretqdpEB2l0pxhJ0qu/JNXoMQAAgHsrKyvTbdeOU9GWBWrZpsNJr0V5Qt10Loa3i5S33arkw8XaeYjd7YF6ZQBoVPbu3WtIMiQZw4cPN7Kzs6tumz59uiHJSExMNJqEhhkx1z1nxE2ZbezNLDQOHDhgREVFGZKM3bt3V93noosuMiQZjzzyiFFWVlZ1fPfu3Ubr1q0Nm81mbNiw4bgMM2fONAoLC487lp+fb1xyySWGJOP9998/7rbKXJKMP/zhD0Z5eXnVba+88oohyRgyZMgJrzUuLq7qftX9s3fv3pO+b+tTcoy4KbONJt1GGpKMGTNmnPnNBgAAbutUNdWujAIj/OL7DUlGQuvWRlhYmLFo0aKq+3lKTfXDsg0nPM6xJk2aRE0FAICHOLZuCm7VzWj+x0+NX7alG4Zx/LUoT62bTnUtqtLv66Zb3ltpxE2Zbbwyb+dp7wegdrFnGNBI2Ww2vf322woNDa06duONN+qRRx7Rrl27NPK6u5XUvLMGJ0YoPiJAUoCuu+46TZ06VYsWLVJCQoLWr1+v77//XgMHDtRzzz0ni8VS9VgJCQl66aWXNH78eE2bNk2vvfZa1W3jx48/IU9QUJCmTp2q2bNna9asWbrxxhtPOKfyMe32/3303HPPPXr66ae1fPlylZWVydvbu+q2CRMmKCsr66zel8DAwJMe79wsRCF+XspyMAUdAAD8z+9rqh82pyug8/kqXPy+9uzerSeffFJDhgypOj82Ntata6oVe7O1P7tY01em68L+Xat1HwAA4BlsNpsCR92jgKBgDWwdIen4a1GeVjdVOtW1qFO5oFOMft6WoR+3pOuPI9uc1X0B1BzNMKCRio+PV2Ji4nHHrFar4uLilJmZqf1+rh+m1/VrWXV769atJUlpaWmSpHnz5kmSxo0bd1zxUWnw4MGSpFWrVp1wW1JSkubOnatdu3apqKhITqezaq3jpKSTL60zfPhweXl5HXfMbrcrISFBa9as0eHDh9W0adOq21588cXTvANnx2a1aFBiuHbX2iMCAAB38Pua6ofN6bJYrGrWvIX2bHMt2/N77lxTJWcVaeTLv2r5wXKt3Jutvq3Cqn1fAADg3kKjm8krNFaDEyPk62WTdPy1KE+rm2pqZIdo2awWbU3L1/7sYrUI86/z5wRAMwxotJo1a3bS4wEBAZKkAluQYoN8NLJj9Am3VW4smpycLEmaMmWKpkyZcsrnOnZEjGEYeuihhzR16tRTbvRZUHDyTdebN29+0uOVI2hOtuFpbRqcGKkP6vQZAABAY3NsTZWaU6xNB/JktUgx4SHao5PXXO5cU8VHBOiqPi30yYoUvfDjdn1+x4CTXqgCAACex/B3DZI5v330cccrayNPq5tqKizAW33jw7Rsz2H9vO2QbhrUqt4zAJ6IZhjQSJ3pooTFYtGVvZrLy2Y95TmVm4sOGTJECQkJpzwvIiKi6vvPPvtML7/8spo3b65XXnlFAwYMUGRkpLy8vFRWViYfH59TFiZneyHloYceOuup6S+++OJxeY81pM3/jh8pqzirxwUAAO7p2Prkh83pkqQ+8WE6tMx6wu2n4m411ZEyh+wxY7QqWVq4I1PntY86q+cDAADuqbC0QoGSzj9FbeCJdZN0+mtRp3J++ygt23NYC3dk0gwD6gnNMMDNlFY4q76/uk+L055bOTpmwoQJuu+++6r1+DNnzpQk/ec//9Ell1xy3G179uw5m6hn9OWXX2rfvn1ndZ+//vWvpyxAWoT5K9DHriJJSRlFtZAQAAC4kx+3uJphozvH6P2zuJ871lQPvTtJX+wo1fM/7tCwtpGyWpkdBgAApPYxQYoJ8a3x/d2xbjrdtahTGd4uUn+fu03L9hzWkTKH/LxtZ3V/AGfv1FNGADRKGQUlkqTecaGKCw847bkjR46UJH3zzTfVfvycnBxJUosWJzbaPv/882o/TnUkJyfLMIyz+hMfH3/ax4wK9pEk7UjPr9WsAACgccsoKNHqfa4658JOMWd1X3esqR67aqiCfOzalpavOZvSajUPAABovIa1izyn+7tj3XSma1EnkxgVqGZN/FRW4dSyPWc3Ew1AzdAMA9xIhcOpzALXWseXdos94/n9+/fXiBEjtGDBAj3wwAMqLCw87nan06mffvpJS5YsqTrWtm1bSdJbb7113BT0xYsX64UXXqiNl1GnooNco5e2p598LWkAAOCZftpySIYhdWvRRLFN/M7qvu5YU4UGeOu2oa6li16et1PlDucZ7gEAANyV0/m/WmVYm3Nrhrlj3VQTFotFw482FhdszzQ5DeAZaIYBbmThjkyVHV0mcXCb6k3P/vjjj9W1a1e98soriouL04gRI3TNNddoyJAhiomJ0YUXXqjVq1dXnX/fffcpICBAb7zxhjp37qxrr71WQ4cO1bBhw3TnnXfWyes6V/3796/6s+63+ZKknXOnqWefvurfv7/uvvtukxMCAACzVS6ReFHns5sVVskda6qbB7dSeIC39mYVacbKlONqqjlz5kiS/vKXv1Qdo6YCAMA97cp0DSi2WS3qFR96zo/njnXT71WnbjqvnWvvtQU7Mk655xmA2sOeYYAb+XRVStX3PvbqrTUcHR2t5cuX680339Rnn32mVatWqaysTE2bNlWPHj00btw4XXXVVVXnt23bVqtWrdKUKVO0YsUKffvtt2rXrp3++9//6rbbbtOLL75Y66/rXK1YseKEYxU5aVq32rXkj69vzde6BgAAjV9+SbmW7T4s6eyXSKzkjjVVoI9d949qq798s1mv/JykdSepqXbt2qVdu3ZJoqYCAMBdrdzrWqYw2Ner2tebTscd66bfO9m1qN/XTf/P3l2H112f/x9/fc45cdcmjTRN3d0VKy5Dhg4YE9gG23fO9Dv5ToCx3zY2xpxtuDtF20Ld3dtI08bdkyO/P845gUJLLcn7yPNxXVzXFusrG0nf531/7vv+zdA0RdptKqtv14HqVg3NjO/vmEBYsTyUnYGQUNHYodm/fkduj/T2NxbwF+gnuP/NPXrg3f26dMJAPXD9JAYcFEwAAKLQSURBVNNxAACAYa9uLddXHtuowow4vfvNhabjBBSny63zf/eeDlS36o4FQ3T3hSNNRwIAAP3sur+u0uqDdfrpZWN0y+wC03FCymf+sUbv76vRDy8epc/PKzQdBwhpjEkEQsRT6w/J7ZGmF6RSCDuBuUO9IyRX7K85au41AAAIT+/sqpQknTtqgOEkgcdht+n7F42SJP1zRZHK6tsMJwIAAP2ppdOpDSXezrAFw89sXxg+buGHRiUC6FsUw4AQ4HZ79OS6Q5Kk62fkGU4T+Cblpyg20q661i7tLG8yHQcAABjkcnt6Lh/OGZlpOE1gOntkpmYVpqnL6dZ9b+wxHQcAAPSjVQdq1e3yKD81VgXpcabjhJyFI7wFxrVFdWrrchpOA4Q2imFACHh/f40ON7QrMdqhC8dmm44T8CIdNs0sTJMkLd9fYzgNAAAwaWNpverbupUUE6Epg858IXwosixLP7h4lCxLenHzEW051GA6EgAA6Cfv7a2WRFdYXylMj1NOcoy6XR6tK643HQcIaRTDgBDwxNpSSdKVk3MVHXHmi0zDgX9U4vJ9FMMAAAhnb/tGJC4ckSGHnZdHxzM2J0mfmpQjSfrFq7vE6mkAAMLDMl8xbD7FsD5hWZZmD/E+sL3yAHdUQF/i1R4Q5KqbO/XWTu8lznXTGZF4suYN8xbD1hbXqaPbZTgNAAAw5d1dvhGJ7As7oW8tGqEoh01ri+v0pu/8CQAAQldxTatK69oUYbc0y1ewQe+bPdRXDNtfazgJENoohgFB7pkNZXK6PZqYl6yRWYmm4wSNoZnxGpAYpS6nW+uK60zHAQAABpTWtmlfVYvsNovRPydhYHKMvjCvUJL069d3q9vlNpwIAAD0pff2ebvCpgxKUXyUw3Ca0DV7iPeB7e1HGtXY1m04DRC6KIYBQczl9uiR1SWSpBum5xtOE1wsy9Lcod5LL0YlAgAQnvwjEqcVpCgpJsJwmuBwx8IhSo+PVFFNqx71nUMBAEBoem+v976EEYl9a0BitIZkxMnjkVYdpDsM6CsUw4Ag9tbOSh1uaFdKbIQumzjQdJyg4x+V+D7FMAAAwtI7u73FsHMZkXjS4qMc+vp5wyVJv39nnxrbeXoZAIBQ5HS5tdpXmJk3lGJYX5vj222/ir1hQJ+hGAYEsYdXFkmSrp+er+gIu+E0wcd/0NhZ3qTq5k7DaQAAQH9q7ujWmoPeUcnsCzs1107N09DMeNW3devBJftNxwEAAH1gS1mjWjqdSo6N0JiBrOXoa7N9O9lWHKAzDOgrFMOAILWrvEmrD9bJbrN008xBpuMEpYyEqJ4D3Xt7qw2nAQAA/em9vTVyuj0qzIjT4PQ403GCisNu0/cvGilJ+teKYh2qazOcCAAA9LYV+70dSnOGpMtmswynCX0zC9NkWdL+qhZVNXWYjgOEJIphQJB6eEWxJOmCMVkamBxjNkwQO2tEpiRpyZ4qw0kAAEB/ese3L+yckZmGkwSns0Zkas7QNHW53LrvjT2m4wAAgF623F8M803VQd9Kjo3seWB7Jd1hQJ+gGAYEobrWLr2w+bAk6bNzCsyGCXJnjfTOvX5vb7WcLrfhNAAAoD+43J6eB2EYkXh6LMvS9y8aJcuSXtpyRJsPNZiOBAAAeklrp1ObSuslSXMphvWbOUO8/1v7u/IA9C6KYUAQemJdqTqdbo3NSdSUQSmm4wS1iXkpSo6NUFOHUxtLG0zHAQAA/WBTab3q27qVFBOhqZylTtuYgUm6anKuJOkXr+6Ux+MxnAgAAPSGtUV16nZ5lJcao/y0WNNxwsZM396wtcV1hpMAoYliGBBknC63/ruqRJJ06+zBsizmNp8Ju83SguHe7rB3dzMqEQCAcODvCps/PEMOOy+JzsS3Fo1QdIRN64rrGTsNAECI8I9IpCusf00ZlCKbJZXUtqmikb1hQG/jlR8QZN7YUanyxg6lx0fq0gnZpuOEhLN9u0KWcoEDAEBYWLK7WpJ01ogMw0mCX1ZStG6ZVSBJ+s0be+V20x0GAECwW8G+MCMSoyM02rc3jO4woPdRDAOCzMMriyRJN0zPV5TDbjhNaJg/LEOWJe2uaNaRhnbTcQAAQB+qaurQzvImSd7OMJy5OxYMUXyUQzvLm7R4R4XpOAAA4AxUNXdod0WzJGn2EIph/W16gW9UYlGt4SRA6KEYBgSR7Ycbta64Xg6bpRtnDjIdJ2SkxEVqUl6yJDHeBwCAELd0r7crbHxuktLjowynCQ0pcZH63NzBkqTfvrVXLrrDAAAIWqsOeIswYwYmKjUu0nCa8DN9cKokaV1RveEkQOihGAYEkX+tKJYkXTw+WwMSo82GCTH+UYn+sUkAACA0Ldvj/bt+IV1hverz8wYrOTZC+6ta9MKmw6bjAACA07R8n29f2DC6wkyYVpAiSdpT2az61i7DaYDQQjEMCBI1LZ16ecsRSdKtswvMhglBC0d4i2Er9teoo9tlOA0AAOgLTpdb7+/zFsMW+P7uR+9IiI7QHQuGSJL+uGQ/3WEAAAQhj8fTsy9sLvvCjEiLj9LQzHhJ0jr2hgG9imIYECQeX1OqLpdbE/KSNSk/xXSckDNmYKIyE6LU3u3S2iIOGwAAhKJNhxrU1OFUcmyEJvpGJKP3fGbmICXHRqioplWvby83HQcAAJyigzWtOtLYoUiHTdMKUk3HCVv+UYncTwG9i2IYEAS6nG79d3WJJOm2OQVmw4Qoy7J0lu8J8Xd3szcMAIBQtNS3G3TesAzZbZbhNKEnLsrRM8HgwSUH5PHQHQYAQDDxd4VNHZSi6Ai74TTha4a/GEZnGNCrKIYBQeD17eWqau5URkKULhybbTpOyDrLtzfs7V2VXN4AABCClvr2hZ01gn1hfeXW2QWKjbRrZ3mTlu1lFysAAMHEvy9sDiMSjfJ35W0/3KiWTqfhNEDooBgGBIGHVxZLkm6aMUiRDn5s+8r84emKcthUVt+uXeXNpuMAAIBeVNXcoR1HmiRJ84dTDOsrybGRumF6viRvdxgAAAgOTpdbqw7WSmJfmGkDk2OUlxojt0faUFJvOg4QMrhVBwLc5kMN2lTaoEi7TTfMyDcdJ6TFRjp6Lsfe2FFhOA0AAOhNy3xdYeNzk5QeH2U4TWj7/LxCRdgtrS2u03rG+wAAEBS2HW5Uc4dTidEOjc1JMh0n7Pm7w9axNwzoNRTDgAD38IoiSdIlE7KVkcDFTV9bNHqAJOnNnZWGkwAAgN601DeybyFdYX0uKylaV07KlST9Y3mR4TQAAOBk+PeFzR6Szm7VANCzN4xiGNBrKIYBAayqqUOvbiuXJH129mDDacLDuaMGyGZJu8qbdKiuzXQcAADQC5wut973FcMWjMg0nCY8fHZugSRvt31ZPWcqAAAC3XJfMWzOMEYkBoLpg9MkeSdGdXS7DKcBQgPFMCCAPbKmVN0uj6YMStG4XFrU+0NKXKSm+56+YVQiAAChYfOhBjV1OJUcG6GJecmm44SFkVmJmj0kTW6P9N9VJabjAACAT9DW5dTGkgZJ7AsLFAVpscpIiFKXy60thxpMxwFCAsUwIEB1Ol16bI334uCzcwrMhgkz54/JkiS9uYNRiQAAhIKlvn1h84ZlMPanH902xzvZ4PG1pWrrchpOAwAAjmddcb26XG7lJMeoIC3WdBxIsixL0/17w9jBCvQKimFAgHp1a7lqWrqUlRjdU5xB/1jk+997XUmdalo6DacBAABnauneKknsC+tvZ4/M1KC0WDV1OPXcxsOm4wAAgONYvs/74NDcoemyLB4cChRTC1IkeYuVAM4cxTAgAHk8Hv1rRbEk6TOzBinCzo9qf8pJjtHYnER5PNI7u+gOAwAgmFU1d2j74SZJ0nyKYf3KZrN0y6wCSdK/VhTJ4/GYDQQAAI5p+f5aSewLCzTTfJ1hG0vq5XJzjgLOFDfsQADaWFqvbYcbFemw6frp+abjhKXzR3u7w95gVCIAAEHtvb3eZfDjcpKUkRBlOE34uWZqruKjHDpQ3apVB2tNxwEAAB9R09KpXeXeB4dmD0kznAYfNjIrQfFRDjV3OrW7osl0HCDoUQwDApC/K+yKiQOVGhdpNkyY8o9KXL6/Ri2d7LgAACBYLdnjHZF41gi6wkxIiI7Q5RMHSpIeW1NqOA0AAPiolQe8D6uMyk5UejwPDgUSh92mSfnJkqT1jEoEzhjFMCDAlDe26/XtFZKkW2cPNpwmfA0fEK+CtFh1Od1asrvKdBwAAHAanC633t/r3YGxYESm4TThyz/p4I0dFaplHysAAAFlxT5vF/3coXSFBaLpvlGJ64rrDCcBgh/FMCDAPLK6RC63RzMGp2r0wETTccKWZVm6cFy2JOnVreWG0wAAgNOx+VCDmjqcSo6N0MS8ZNNxwtbYnCRNyE1St8ujZzaUmY4DAAB8PB6Plu/3FsPmDGVfWCCa+qFiGPtXgTNDMQwIIB3drp7xMZ+dU2A2DHTJeG8xbMmeKkYlAgAQhJbu8XaFzRuWIbvNMpwmvPm7wx5fW8pFDgAAAaKktk2HG9oVYbc0fXCq6Tg4hol5yYqwW6ps6lRZfbvpOEBQoxgGBJCXNh9RfVu3cpJjdO6oAabjhL3R2YkqTI9Tp9Ott3dWmo4DAABO0dK93lHHC4ezL8y0SycMVHyUQ8W1bVrl200CAADM8neFTc5PUWykw3AaHEtMpF1jc5IkMSoROFMUw4AA4fF49K+VxZKkm2cNksPOj6dplmX1dIe9svWI4TQAAOBUVDV3aPvhJknSfIphxsVFOXT5xIGSpMfWlhpOAwAAJGnFfv++MEYkBrJp7A0DegW37UCA2FBSr13lTYqOsOnaaXmm48Dn4vHeS5tle6vV2N5tOA0AADhZ7+31Xu6My0lSRkKU4TSQPhiV+OaOSjW2ca4CAMAkl9ujlb5u7bnDKIYFsqmDUiRJ64rrDScBghvFMCBAPOrbFXbZhIFKjo00nAZ+I7ISNCwzXt0uj95iVCIAAEFj6R7viMSzRtAVFijGDEzUyKwEdbnceomuewAAjNp+uFGN7d1KiHZonG8MHwLTVF9n2P6qFtW1dhlOAwQvimFAAKhr7dKrW8slSTfOGGQ4DT7qEl93GKMSAQAIDk6XW+/trZYkLRiRaTgN/CzL0tVTciVJz2woM5wGAIDw5t8XNqswjVUdAS41LlJDM+MlSesZlQicNn7TAQHgmQ2H1OVya1xOkibkJZuOg4+4ZIJ3b9jyfTWq5wkcAAAC3uZDDWrqcCo5NkITOVsFlCsm5chhs7TlUIP2VTabjgMAQNha5RuROHtImuEkOBnTCryjEteXMCoROF0UwwDD3G5Pz4jEG2fkG06DYxmSEa9R2Ylyuj16Y0eF6TgAAOAElu7xdoXNG5Yhu80ynAYflh4fpbNGerv16A4DAMCMTqdL63wdRnOGsi8sGEzzjUpcR2cYcNoohgGGrThQo5LaNiVEOXTZxIGm4+A4Lhnv7Q57xTfOEgAABK6le737whYOZ19YIPKPSnxu02E5XW7DaQAACD+bShvU6XQrPT6qZ/weApu/GLatrFHtXS7DaYDgRDEMMOzR1d6usCsn5yg20mE4DY7HXwxbeaBGtS2dhtMAAIDjqWru0PbDTZKkBSMohgWis0ZkKjUuUtXNnXpvX7XpOAAAhB3/iMRZQ9JkWXTRB4PclBhlJUbL6fZo86EG03GAoEQxDDCorrVL7+yulCRdz4jEgDYoLU7jcpLk9kivb2dUIgAAgWqZb0Ti+NwkpcdHGU6DY4l02HTZBO9EhBc2HTGcBgCA8MO+sOBjWZam+veGMSoROC0UwwCDXtp8WN0uj8bmJGpkVqLpODgBf3fYy1u4tAEAIFAt3esthjEiMbBdMSlHkvTWzkq1dTkNpwEAIHy0dTm16VC9JIphwcY/KnEtxTDgtFAMAwx6duNhSdJVk3MNJ8HJuNhXDFtbXKeKxg7DaQAAwEc5XW697yuGLRiRaTgNPsmE3CQNSotVe7dLb+2sNB0HAICwsb64Xt0uj3KSY5SfGms6Dk6Bvxi2saSevavAaaAYBhiyp6JZ2w43ymGzesbEILDlpsRqyqAUeTzSq9vKTccBAAAfsflQg5o6nEqOjdDEvGTTcfAJLMvS5b4z8Eub6boHAKC/rDrIvrBgNSIrQQlRDrV2ubS7otl0HCDoUAwDDHl2Y5kk6eyRmUpjn0XQuNTXHfYSoxIBAAg4S/ZUSZLmD8uQ3cblTqC7bKK3GLZsb7XqW7sMpwEAIDys9O0Lm1XIiMRgY7dZmjzIuzdsHaMSgVNGMQwwwOly6/lNvhGJUxiRGEwuHj9QNkvacqhBJbWtpuMAAIAPWbrHty9sBPvCgsHQzASNzk6U0+3Ra9vpugcAoK81dXRrW1mDJG9nGILP9MHeUYnri+sNJwGCD8UwwID399eourlTKbEROot9FkElIyFKs4ekS5Je2cqlDQAAgaKquUM7jjRJkuYPpxgWLC73dYe9yKhEAAD63NqDdXJ7pMHpcRqYHGM6Dk7D1A91hnk8HsNpgOBCMQwwwL8X4bIJAxXp4Mcw2Fw6wTcqkUsbAAACxjJfV9j43CSlM4I6aFzq2xu2rrhORxraDacBACC0fXhfGILThLxkRdgtVTV3qrSuzXQcIKhwCw/0s45ul97aWSnpgz0JCC4XjMlWhN3Snspm7WFhKQAAAeGDEYl03QeTgckxmj44VR6P9MpWHjQCAKAvsS8s+EVH2DU+N1mStI5RicApoRgG9LOle6rU0ulUTnKMJuWlmI6D05AUG6EFvvFLL2/h0gYAANOcLrfe38e+sGDFqEQAAPpeXWuXdpV7R0rPpBgW1KYW+EYlFtUZTgIEF4phQD97eYt3z9Ql47Nls1mG0+B0+Uf6vLTlCDOaAQAwbNOhBjV1OJUSG6EJvidlETwuGpsth83SjiNN2l9F1z0AAH1htW9E4ogBCcpIYKR0MJs2KFWStK6EYhhwKiiGAf2otdOpd3Z7RyReMp4RicHsvNEDFBNhV2ldm7aWNZqOAwBAWFu6p0qSNG9Yhuw8bBR0UuIie7ru2ckKAEDfWHWAfWGhwt8ZdrC6VbUtnYbTAMGDYhjQj97eVamObrcK0mI1NifRdBycgdhIh84Z5d1J8hKjEgEAMOqDfWGMSAxW/l26dN0DANA3Vh6okUQxLBQkx0Zq+IB4SewNA04FxTCgH/lHJF46YaAsi6eWg91lvlGJr2w9IpebSxsAAEwob2zXjiNNsiz1dBch+Jw7aoCiHDYV17ZpVzmjEgEA6E2VTR06UN0qy5JmDqYYFgqmFnhHJa4vZlQicLIohgH9pKmjW+/t9T61zIjE0LBgRIYSoh2qbOrUOg4fAAAY8fYu74jEyfkpSotn/0Wwioty9BQzF28vN5wGAIDQ4h+ROHZgkpJiIwynQW+YXuDfG0ZnGHCyKIYB/WTJ7ip1udwakhGnEVkJpuOgF0Q57LpgTJYkRiUCAGDKO7u8+1jPHTXAcBKcqQvHec9Vr2+vMJwEAIDQ4i+GzWZEYsjw7w3bcbhRbV1Ow2mA4EAxDOgnb+70XtSc7yueIDT491u8vq1c3S634TQAAISX1k6nVvoud8717fJE8Dp75ABF2C3tq2rR/qoW03EAAAgZKw+yLyzU5CTHKDspWk63R5tLG0zHAYICxTCgH3Q6XVrmW+x+3mieWg4lswrTlBYXqfq27p4nrQAAQP94f1+Nupxu5afGamhmvOk4OENJMRGaMzRdEqMSAQDoLYcb2nWorl12m9WzZwrBz7IsTfOPSixmVCJwMiiGAf1g1YFatXQ6lZkQpQm5yabjoBc57DadP9Y/0odLGwAA+pN/ROI5ozJlWZbhNOgNF45lVCIAAL1pbZF/X1ii4qMchtOgN03zjUpkjz1wciiGAf3gLd+IxHNHD5DNxkVNqLlobLYk6Y0dlXIyKhEAgH7hcnv07u4qSdJ57AsLGeeNzpLdZmnHkSaV1raZjgMAQNBbW+QtlMwoZERiqPF3+m0srec+CjgJFMOAPuZ2e3qKYYsYkRiSZhSmKiU2QnWtXVrL0zgAAPSLzYcaVNvapYRoh6YNZuRPqEiNi9QM3/+fi3fQdQ8AwJlac9B7TzGdEYkhZ8SABCVEO9TW5dKOI02m4wABj2IY0Me2Hm5UVXOn4qMcLCoNURF2W88uuNe3MdIHAID+4B+RuGB4hiLsvKwJJYxKBACgd1Q1d+hgTassSz37pRA6bDar5yGiVQfZYw+cCK8agT725g7vi/gFIzIU5bAbToO+cuE476jExTsq5HJ7DKcBACD0vbPLNyKRzvuQc/6YLFmWtKm0QeWN7abjAAAQtPwjEkdmJSopNsJwGvSFWUPSJUkrD1AMA06EYhjQxxiRGB7mDElXQrRD1c2d2lBSbzoOAAAh7VBdm/ZUNstus7RweKbpOOhlmYnRmpLvXQj/Bt1hAACctp59YYyUDllzhnqnUK0rqlOXk71hwCehGAb0oaKaVu2rapHDZmnhCC5qQlmk44NRia9tY78FAAB96W3fiMSpg1J4yjlEXeAblfiW7/9rAABw6vz7wiiGha7hmQlKi4tUe7dLmw81mI4DBDSKYUAfemun90nWWUPSlBTDRU2ou2isb1Ti9gq5GZUIAECf8Y9IPHcUnfehyv+Q0ZqDdWps7zacBgCA4FPf2qU9lc2SpOkUw0KWzWZp1hBvd9jKAzWG0wCBjWIY0Ife3skui3Ayd1i64qMcqmjq0OayBtNxAAAISU0d3VpT5N2JcC5nrJA1KC1OwzLj5XR7tHRPlek4AAAEnbXF3q6woZnxSouPMpwGfWm2f2/YfvaGAZ+EYhjQR5o6urWh1Ls76ixGJIaF6Ai7zhnl/f/6ta2MSgQAoC8s21OtbpdHhRlxGpweZzoO+pC/2Pn2LophAACcKvaFhQ//3rBNh+rV1uU0nAYIXBTDgD6yYl+NXG7vRU1eaqzpOOgnF35ov4XHw6hEAAB62+Id3jHUi0ZnGU6CvuafrrB0TxUL4QEAOEX+YhgjEkNffmqscpJj1O3yaH1xvek4QMCiGAb0kaV7qiVJC4fTFRZO5g3LUKTdppLaNh2objEdBwCAkNLR7dKS3d4uIf8DKAhdE3OTlR4fqeYOZ8+FHgAAOLGmjm7tONIoSZoxOM1wGvQ1y/pgb9gK9oYBx0UxDOgDHo9Hy/Z6i2ELRmQYToP+FBfl0EzfAYSRPgAA9K739larrculgUnRGp+bZDoO+pjNZumckf5RiZWG0wAAEDw2lNTL7ZEGpcUqKynadBz0A/+oxFUH2BsGHA/FMKAP7KlsVkVTh6IjbMxmDkPn+vaGvUsxDACAXrV4u3dE4vljs2RZluE06A/+vWFv7WQENQAAJ2vNQfaFhZvZQ9IlSdsON6qxrdtwGiAwUQwD+oB/ROLMwjRFR9gNp0F/O3uktxi2vqRO9a1dhtMAABAaupzunu6gC8dmG06D/jJ3aLqiI2w63NCuXeXNpuMAABAU1hZ5u4OmMyIxbAxIjNaQjDh5PNLqIrrDgGOhGAb0gWU9+8IYkRiOclNiNTIrQW6PtHQv3WEAAPSGVQdr1dThVHp8lKYMSjEdB/0kJtKuuUO9Z2pGJQIAcGJtXU5tLfPvC6MzLJz4u8MYlQgcG8UwoJe1dDq1vsTbjr5wRKbhNDDlHN+oRPaGAQDQOxZvL5cknT9mgOw2RiSGk/NG+89VFMMAADiRTaUNcro9GpgUrdyUGNNx0I/8e8OW768xnAQITBTDgF62Yn+Nul0eDUqLVUF6nOk4MOScUd79Fu/tqVaX0204DQAAwc3l9ujNHYxIDFdnjxwgy5K2ljWqsqnDdBwAAALamoPerqAZhWnsWA0zswrTZbOk/VUtOtLQbjoOEHAohgG9bNleRiRCmpCbrLS4SDV3OrWuuM50HAAAgtraojrVtnYpOTZCMwoZ9xNuMhKiND43WdIH48gBAMCxrSny3kFMZ0Ri2EmKjdDEvGRJ0nt7OTMBH0UxDOhFHo+n5wX6ghEUw8KZ3Wb1jMlcuodRiQAAnAn/iMTzRg1QhJ2XMOHI/6DZEs5VAAAcV0e3S5sONUiiGBau5vvOTO/toxgGfBSvJIFedKC6RYcb2hXpsGlmYZrpODDMXxB9by+zmgEAOF1ut0eLd1RIki4cl2U4DUxZ6DtXLd9Xo24XI6gBADiWrWWN6nK6lR4fpUJWd4QlfzFs+b4aOTkzAUehGAb0In/RY3pBqmIjHYbTwLR5Q9NlWdKeymZVNLLfAgCA07G2uE6VTZ1KiHZoztB003FgyPjcZKX6RlBvLKk3HQcAgIDUsy9scCr7wsLUhNxkJcVEqKnDqS1ljabjAAGFYhjQi1bs9xbD5g7jogZSSlxkz34LZjUDAHB6XtpyRJJ04dgsRTnshtPAFLvN0nzfGXsJe8MAADimtb6d5exYDV92m6W5vgfIuIsCjkYxDOgl3S63VvuewJnLU8vwWeC7tFnGrGYAAE5Zt8ut17d594VdNiHHcBqYxj5WAACOr9vl1gZf9zT7wsLb/OG+Yhh3UcBRKIYBvWTLoQa1drmUHBuh0dmJpuMgQCz40H4Ll9tjOA0AAMFl+b4a1bd1Kz0+SrOGsI813M0fniHLknZXMIIaAICP2n64UW2+e6nhmQmm48Ag/96wLYca1NjWbTgNEDgohgG9ZLlvROKcIemy2ZjLDK8JuclKiHaosb1bW8oaTMcBACCovLj5sCTpkvHZsnO+CnupcZGa4BtBTXcYAABHW1PkHZE4rSCVe6kwl50Uo2GZ8XJ7PrivBEAxDOg1K/d7RySy2B0f5rDbNG8Ys5oBADhV7V0uvbmzUpJ02cSBhtMgUCz0dd0vZW8YAABHWesrhs1gRCIkLfB1hy3hASKgB8UwoBe0djq1sdQ7l5l9Yfio+cO8BxCKYQAAnLx3dleqrculvNQYTcpLNh0HAeIs396w5ftr1O1yG04DAEBgcLk9WtdTDGO0NKSzR3nPTEt2V8nN2g5AEsUwoFesLaqT0+1RXmqM8tNiTcdBgPHPat7MrGYAAE7a8xu9IxIvHT9QlsWoH3iNy0lSWlykWjqdWl9cbzoOAAABYVd5k5o7nYqPcmj0QPbYwzsuMyHKodrWLtZ2AD4Uw4Be4J+/S1cYjmVgcoyGZMTJ7ZHWFNWajgMAQMCrbOroGely1ZRcw2kQSGw2q+dBo6V7GfsDAID0wb6wqQUp7FmFJCnCbtN833jpd3dzZgIkimFAr1jhK4axLwzHM3uI99+NlQcohgEAcCLPbCiT2yNNK0jRkIx403EQYPx7w97by0J4AAAkaa3vwVtGJOLDzhnpHZX49i6KYYBEMQw4Y1XNHdpd0Szpg4IH8FGzh3gPpCsPcGkDAMAn8Xg8enr9IUnSp6fmGU6DQOR/AG1XeZOqmzsNpwEAwCy326O1vs6w6YNTDadBIFk4IlM2y3tmOtLQbjoOYBzFMOAMrfJ1+owZmKjUuEjDaRCoZhZ6i2F7K1u4tAEA4BOsKapTcW2b4qMcunh8tuk4CEDp8VEa49uH4p/QAABAuNpf3aL6tm7FRNg1LifJdBwEkNS4SE3OT5HEqERAohgGnLHl+xiRiBNLiYvU6Gzvpc2qg4xKBADgeJ5a5+0Ku3RCtmIjHYbTIFDNHeY9e7+/j2IYACC8rfHdMUwelKxIB1e9ONrZo7yjEt/ZVWk4CWAevyGBM+DxeHqeRvWPwQOOx//vyCpGJQIAcExNHd16bXu5JEYk4pPNH+bdG/b+vmp5PB7DaQAAMGeNb0Qi+8JwLOeMHCBJWnGgVm1dTsNpALMohgFnoLSuTUcaOxRht5jLjBOaPdS/N4zOMAAAjuWlzUfU0e3W8AHxmpiXbDoOAtiUQSmKcthU1dypvZUtpuMAAGCEx+PpKYZxL4VjGT4gXjnJMepyurVyP/dRCG8Uw4Az4N8XNiE3mTE+OKFpBamy2yyV1LaprL7NdBwAAALOU+u9IxI/PTVPlmUZToNAFh1h1wzfTtb391UbTgMAgBnFtW2qbu5UpN3Gg0Q4JsuydK5/VCJ7wxDmKIYBZ8C/+2kWIxJxEhKiIzQ+17vMlu4wAACOtqu8SVvLGhVht/SpSTmm4yAIzBvK3jAAQHjz7wubmJes6Ai74TQIVGeP8o5KfHd3JeOlEdYohgGnyePxaLW/GFZIMQwn54O9YRTDAAD4sCfXebvCzh01QGnxUYbTIBjMG+4thq0pqlWn02U4DQAA/W+tf19YISMScXwzBqcqNtKuyqZO7TjSZDoOYAzFMOA0FdW0qrLJ24o+eVCK6TgIEnOGeC9tVh6o4WkcAAB8Op0uvbD5sCTp09PyDKdBsBgxIEEZCVHq6HZrQ3G96TgAAPQ79oXhZERH2DXX11H/zi5GJSJ8UQwDTpN/ROLEfFrRcfImD0pRpMOmyqZOHaxpNR0HAICA8NbOSjW0dSs7KVrzh2WYjoMgYVnWB6MS9zMqEQAQXsrq23S4oV0Om6UpPKSNEzjXNyrxnd2VhpMA5lAMA06Tf8wdIxJxKqIj7JqS7z2ksjcMAAAv/4jEq6fkym6zDKdBMPGPSnx/X7XhJAAA9C//iMSxOUmKjXQYToNAt3Ck94GzrWWNqmzqMJwGMINiGHAavPvCvIeOWUMohuHUfLA3jCeYAQAoq2/Tcl9XzzVTGJGIUzPH1xm240iTals6DacBAKD/rPHdS81gRCJOQmZCtCbkJUuS3t3NqESEJ4phwGnYX9WimpZORTlsmpSfbDoOgsxMXzFsbVEde8MAAGHvmQ1l8ni8D4vkp8WajoMgk5kQrZFZCfJ4pBV03QMAwsiaIu/fezMKKYbh5Jw7MlOS9M4uRiUiPFEMA07Dat++sCmDUhTlYF8YTs343CRFOmyqaelibxgAIKy53R49vb5MknTtNLrCcHrmDfN2hy1nVCIAIExUNnWouLZNNkuaWkAxDCfnHN/esOX7a9TR7TKcBuh/FMOA07DqIPvCcPqiHHZN8rWm+2d8AwAQjlYcqNHhhnYlRjt0/pgs03EQpOYN8+7AeH9fDV33AICw4H9Ie/TARCVGRxhOg2AxKjtBA5Oi1dHt1or9rO5A+KEYBpwit/uDfWEz2ReG0+Sf6U0xDAAQzp5cd0iSdMWkHEVH0G2P0zN9cKoiHTaVN3boQHWL6TgAAPS5NUX+fWHcS+HkWZbV0x329i72hiH8UAwDTtHeqmbVtXYpJsKuCbnJpuMgSE0f/MHeMAAAwlF9a5fe3OHdV/DpqYxIxOmLjrBrum9E1Pv7eMoZABD61vg6w/wP2gIn69zR3mLYu7sr6ahH2KEYBpyiVb7F3FMLUhTp4EcIp2fyoGQ5bJYON7SrrL7NdBwAAPrdC5sPq8vl1piBiRqbk2Q6DoLcXN/eMIphAIBQV93cqQPVrbIsb3c0cCpmFqYqLtKuyqZObT/cZDoO0K+4yQdOkb8YNpN9YTgDsZGOnos/usMAAOHG4/H0jEi8dhpdYThz83zFsNUHa9XldBtOAwBA3/HfIYwYkKDk2EjDaRBsohz2nn2rb+2qNJwG6F8Uw4BT4HZ7euYyz2JfGM4Qe8MAAOFq2+FG7a5oVqTDpssn5JiOgxAwKitRaXGRautyaVNpvek4AAD0mTVFPKSNM3POqExJ0jsUwxBmKIYBp2BXRZMa27sVF2nXOMb54AxNpxgGAAhT/q6wC8dmKSk2wnAahAKbzdKcod7usBX7GZUIAAhdaw567xDYF4bTddbITFmWtONIk8ob203HAfoNxTDgFPhHJE4bnKoIOz8+ODNTB6XKsqSDNa2qau4wHQcAgH7R3uXSS5uPSJKuncqIRPSeub5i2PsUwwAAIaqutUt7KpslsS8Mpy89PkqT8pIlSe/sqjIbBuhH3OYDp2D1QVrR0XuSYiM0MitRkrSuiHE+AIDw8Pr2cjV3OpWXGsOZCr1qjm9v2JZDDWrq6DacBgCA3uefLDMsM15p8VGG0yCYnTt6gCRGJSK8UAwDTpLrw/vCuLhBL/lgb1it4SQAAPQP/4jET0/Jk81mGU6DUJKTHKPC9Di5PR9MdAAAIJT494XNKKQrDGfm3FHeYtiKA7Vq63IaTgP0D4phwEnacaRRzR1OJUQ5NGZgouk4CBH+sQZr2BsGAAgDxTWtWlNUJ5slXT0113QchKC5w9gbBgAIXR/sC+MhbZyZYZnxykuNUZfTreX7ODchPFAMA06Sf0Ti9MGpcrAvDL1kWoG3GLanslkNbV2G0wAA0LeeWu/tCps/PEPZSTGG0yAUzfHtDeNSBwAQahrburWrokkSnWE4c5Zl6ZyR/lGJ7A1DeOBGHzhJ/lErs4bw9A16T0ZClAoz4uTxSOuL2RsGAAhdTpdbz2wokyRdOzXPcBqEqllD0mSzpIM1rTrc0G46DgAAvWZdcZ08HqkwPU6ZCdGm4yAE+EclvrO7Sm63x3AaoO9RDANOgtPl1jpfoYJF7+htPXvDihmVCAAIXe/vq1FVc6dS4yJ1ju+FN9DbEqMjNCEvWZK0gu4wAEAIYV8Yetv0walKiHKopqVTW8oaTMcB+hzFMOAkbDvcqJZOp5JiIjQ6m31h6F3sDQMAhAN/V9gVE3MU6eBlCPrOPP+oRPaGAQBCiP/OgH1h6C2RDpvmj8iQxKhEhAdehQInYdWH9oXZbJbhNAg1030H2e2HG9Xa6TScBgCA3tfY1q23dlZKkq6akmM4DUKdf2/Yiv01jPwBAISE5o5ubT/cKInOMPSuc0dlSpLe3lVpOAnQ9yiGASehZ18YIxLRB3KSY5STHCOX26ONpewNAwCEnpe3HlGXy62RWQkaMzDJdByEuEn5KYqNtKu2tUu7K5pNxwEA4IytK66T2yPlp8YqOynGdByEkIXDM2WzpN0VzSqrbzMdB+hTFMOAE+h2ubXety9s1hCKYegbPXvDGJUIAAhB/hGJV0/JNZwE4SDSYes5Wy3fX204DQAAZ27Ffu9D2nOGci+F3pUSF6mpg7znpiV7ODchtFEMA05ga1mD2rtdSomN0IgBCabjIESxNwwAEKoOVLdo86EG2W2WLp/IiET0jzk9e8NqDScBAODMrfRNLJo9JN1wEoSiBb69Ycv2sDcMoY1iGHAC/hGJMwvT2BeGPuMvhm0+1KCObpfhNAAA9J5nfV1hC4dnKCMhynAahIt5w7yXOmuLajlbAQCCWm1Lp3aVN0liYhH6xkJfMWzlgVp1Ojk3IXRRDANOYNVB374wDhzoQ4PT45SREKUup1tbDjWYjgMAQK9wuT16ftNhSdJVjEhEPxo+IF4ZCVHq6HazkxUAENT891IjsxKUHs+DReh9o7MTlZkQpbYul9YVcW5C6KIYBnyCTqfrg31hhRTD0Hcsy2JUIgAg5Kw8UKPyxg4lxUTonFGZpuMgjFiWpbn+UYn7agynAQDg9DEiEX3Nsqye7rCljEpECKMYBnyCzaUN6nS6lR4fqaGZ8abjIMTN7CmGsdsCABAa/CMSL5swUFEOu+E0CDf+vWEr9lMMAwAEr5W+v8fmDOUhbfSdhSO8D64toRiGEEYxDPgEqw96O3RmFKbJstgXhr41w9d9uKGkXl1Ot+E0AACcmeaObi3eUSGJEYkww98ZtvVwoxraugynAQDg1B1uaFdxbZvstg+myQB9Yc7QdNltlg5Ut+pQXZvpOECfoBgGfIJVB71P3zAiEf1haEa8UmIj1NHt1rbDDabjAABwRl7fVqGObreGZMRpQm6S6TgIQ1lJ0RqaGS+P54MRUwAABBN/V9j43CQlREcYToNQlhQToSn5KZKkpXurDacB+gbFMOA4Orpd2ljaIEmaNYRiGPqezcbeMABA6HjGNyLxqim5dNjDmHnDvN1h7+/jUgcAEHz8D3PMYV8Y+sEC396wZYxKRIiiGAYcx8ZS76i6zIQoFabHmY6DMDFjsLfwuuYgxTAAQPAqrW3T2uI6WZb0qUk5puMgjM0f7r/UqZbH4zGcBgCAk+fxeLTc1xk2m31h6Adn+faGrdhfq45ul+E0QO+jGAYcx2rf0zezhrAvDP1nRqG3M2x9cZ2cLvaGAQCC07MbvV1hc4emKzspxnAahLOZg9MU6bDpSGOHDlS3mI4DAMBJ21XerOrmTsVG2jVlUIrpOAgDo7ITNCAxSu3dLq0r5iFthB6KYcBxrDroLYbNZF8Y+tHIrEQlRjvU2uXSjiNNpuMAAHDK3G6PntvkLYZdPSXXcBqEu5hIu2b4xlAv21tjOA0AACdvmW9v0+whaYpy2A2nQTiwLEsLfF31S/cwYhqhh2IYcAxtXU5tPtQgyXvoAPqL/ai9YSx6BwAEn7XFdTpU1674KIcWjc4yHQfQ/GG+UYksgwcABJFle717m/wjf4H+sNA3KnEpe8MQgiiGAcewvrhe3S6PcpJjlJ8aazoOwgx7wwAAwezZDd6usIvHZSsmkqeYYZ5/Gfyag+y/AAAEh5ZOp9YX10tST6cO0B/mDE2X3WbpQHWrDtW1mY4D9CqKYcAxrGRfGAzyd4atLa6Ty82idwBA8Gjrcuq1beWSpKunMiIRgWFYZryyEqPV6XRrbREPGwEAAt+qA7Vyuj0qSIvVoLQ403EQRpJiIjQl37ujju4whBqKYcAx+PeFMSIRJowZmKj4KIeaO5zaXcHeMABA8HhjR4Vau1walBarqSx6R4D48P4LRiUCAIKBf0QiXWEwYeFI9oYhNFEMAz6iqaNb28oaJHk7w4D+5rDbNMV3gcioRABAMHnGNyLxykm5dNcjoPj3rbxHMQwAEOA8Hk9PEYJ9YTDBX4RddbBWnU5GTCN0UAwDPmLtwTq5PdLg9DhlJ8WYjoMwNaPQOypxTVGt4SQAAJycIw3tPaOmr5ycYzgNcLS5Q9Nls6R9VS060tBuOg4AAMdVVNOqsvp2RdptmlnIQ9rof6OzE5WREKW2Lpc2+HbXAaGAYhjwER/eFwaYMmOw99+/tUV1crM3DAAQBJ7fdFgejzRjcKryUmNNxwGOkhQboYl5yZLoDgMABDb/SN9pg1MUF+UwnAbhyLIszRuWLklato9zE0IHxTDgI/z7wmbx9A0MGp+bpJgIu+rburWvqsV0HAAAPpHH49GzvhGJV0/JNZwGOLaeUYlc6gAAAtjbuyolSQuHZxpOgnDWs2+VvWEIIRTDgA+pa+3SrvImSaIVHUZFfHhvGKMSAQABbmNpgw7WtComwq4Lx2WbjgMck/9S5/19NXK63IbTAADwcY3t3T27w88bPcBwGoSzecMyZFnS7opmVTZ1mI4D9AqKYcCHrPZ1hY0YkKCMhCjDaRDuZvr2hq3cTzEMABDYnt3o7Qq7cGyW4hnngwA1PjdZqXGRau5wan0J+y8AAIFn6Z4qOd0eDcuMV0F6nOk4CGOpcZEan5MkiRHTCB0Uw4APWXmgRhL7whAY5gz1zmdeeaBGLvaGAQACVEe3Sy9vOSJJuooRiQhgdpulhSO83WHv+EZQAQAQSN7c6f37ia4wBIIPRkzXGE4C9A6KYcCHrDrg2xdGMQwBYFxOkhKiHWrqcGr74UbTcQAAOKa3dlaqucOpgUnR7FxFwDtnpPdy8Z3dVYaTAABwtE6nq2c/06IxWYbTAB8eMV3NQ9oICRTDAJ/Kpg4dqG6VZUkzB3ORA/McdlvPpeLy/TyFAwAITP4RiVdOzpXNZhlOA3yy+cPT5bBZOljdqqKaVtNxAADosepArVo6ncpMiOoZTweYNDEvWQnRDjW0dWsbD2kjBFAMA3z8XWFjByYpKTbCcBrAa+4w76jEFRTDAAABqKqpo2eHwJWTcwynAU4sITpCM3x7WRmVCAAIJG/5RiSeO3oADxghIDjsNs31rfDwdy0CwYxiGODDvjAEIv/esPXF9WrvchlOAwDA0V7YfFhujzQ5P1mFGfGm4wAnpWdU4i5GJQIAAoPb7dHbu9gXhsDzwd4wimEIfhTDAJ9VB9kXhsBTmB6n7KRodbncWl9SZzoOAAA9PB6PntngHZF41ZRcw2mAk3fOqExJ0rriOjW2dxtOAwCAtKWsQZVNnYqLtGs291IIIP5i2KbSejW2cW5CcKMYBkg6VNemQ3XtctgsTStINR0H6GFZVk93GHvDAACBZPvhJu2tbFGkw6ZLxg80HQc4aYPS4jQkI05Ot6dnzCcAACa9srVcknTOqAGKctgNpwE+kJMco6GZ8XJ7pBUHuJdCcKMYBuiDfWET8pIVH+UwnAY4mn8+M3vDAACB5NmN3q6wRaMHKCmGfasILueO8o6genc3oxIBAGa53R696iuGXTqBB4wQeBb4usPYG4ZgRzEM0IdGJBbSio7AM3uo99/LHUeaVNfaZTgNAABSl9OtFzcflsSIRASns0d6RyUu2VMlp8ttOA0AIJytL6lXRVOHEqIdmj883XQc4GM+vDfM4/EYTgOcPophCHsej0crfW2+zGVGIMpMiNaIAQnyeD7oYgQAwKR3d1epvq1bGQlRmjeUSxsEnymDUpQUE6GGtm5tLG0wHQcAEMZe3nJEknT+mCxGJCIgzRicqiiHTeWNHdpX1WI6DnDaKIYh7B2saVVlU6ciHTZNHpRiOg5wTOwNAwAEEv+IxE9NypHDzksKBB+H3aaFI7xPOb+zq9JwGgBAuOp2ufXaNkYkIrBFR9g1wzdNi32rCGa8ckXYW+nrtJmcn6zoCJ7AQWCaO8x76GBvGADAtNqWTi3x7Vm6ajIjEhG8zhvt3Ru2eEcFI38AAEYs3VOt2tYupcdHMq0IAa1nbxjFMAQximEIe6t9xbDZQxjxg8A1fXCaHDZLpXVtKq5pNR0HABDGXtpyRE63R+NykjQiK8F0HOC0nTUiU1EOm0pq27S7otl0HABAGHp6/SFJ3m77CLrtEcAW+PbZrSmqU3uXy3Aa4PTwWxZhze32aNVBfzGMJ3AQuOKjHJpWkCpJWrqnynAaAEC48ng8enKd99Lmqsk5htMAZyYuytGzEP717RWG0wAAwk1NS6fe9XXbXzM1z3Aa4JMNyYhXTnKMupxurS5inz2CE8UwhLVdFU2qa+1SbKRd43OTTccBPpF/r8VSWtIBAIZsO9yo3RXNinTYdMUkimEIfheMyZIkLd5ebjgJACDcvLDpsJxujybkJmn4ALrtEdgsy9J8X3cYe8MQrCiGIawt3+fdvzSzME2RDn4cENjOGpkpSVp1oJaWdACAEf6usAvGZCk5NtJwGuDMnTtqgBw2S3srW3SgusV0HABAmPB4PHpmQ5kk6Wq6whAk2BuGYMftP8La8v3eYticoewLQ+AblultSe90urX6IC3pAID+1d7l0kubj0iSrpvGpQ1CQ1JshGb7XgssZlQiAKCfbD/c1NNtf9n4gabjACdl9tB02W2WDla36lBdm+k4wCmjGIaw1dHt0tqiOknSvGEUwxD4LMvqGZW4hL1hAIB+9tq2cjV3OpWXGqOZhexaRej4YFQixTAAQP94ar232/78MVlKio0wnAY4OYnREZqcnyxJem8f3WEIPhTDELY2ltSr0+lWZkKUhmXGm44DnJSzRnhHJb67u0oej8dwGgBAOPGPSLx2ap5sNstwGqD3LBozQDbLuxOvrJ6nnAEAfauxvVvPbvSOSKTbHsFm/jDvQ9rsDUMwohiGsPW+b0Ti3KHpsiwudBAcZg9NU6TdprL6dh2objUdBwAQJg5Wt2htcZ1slnT1FC5tEFrS46M0rSBVEt1hAIC+98TaUrV1uTQyK0Gzh9Btj+CywDexaMX+WnW73IbTAKeGYhjC1gr2hSEIxUY6NKPQe1mzlFGJAIB+8tR679PLC0dkKisp2nAaoPddMJZRiQCAvud0ufXvlcWSpNvmDubhbASdsQOTlBoXqZZOpzaVNpiOA5wSimEIS/WtXdp2uFGSNDeI94WtXr1al19+udLT0xUdHa3hw4frhz/8odraTn68y7nnnivLsmRZlioqPv7iv6OjQ1/5yleUnp6uuLg4XXbZZSopKTnm12psbFRWVpauv/76U/5eiouLZVmWCgoKPvHjbr31VlmWpYcffviYb/f/Y7PZlJSUpIKCAl166aW69957VVlZecpfNxB9eFQiAAB9rdvl1jMbvMWwT08N/q4wzk8ff3s4nJ9OxF8M21Bar8qmDsNpAACh6vXtFTrS2KH0+EhdNmGg6TinjfPUx98eLucpm83SPN9d6rK93EshuFAMQ1haeaBWHo80LDNeAxKD8+nmRx99VHPnztVLL72kgoICXXTRRero6NAvfvELzZ49W83NzSf8Gg8//LDeeeedT3wS6Wtf+5oefPBBDRo0SPPmzdMrr7yiiy66SC6X62Mf++Mf/1itra36zW9+c0bf25mYM2eObrnlFt18881atGiRcnNz9c477+i73/2u8vPzdc899wT9rq1zRnmLYWuL6tTY1m04DQAg1C3ZXaWalk6lx0f2/B0UrDg/HVs4nJ9OJDspRpPzk+XxSK9tKzcdBwAQgjwej/6+vEiSdNPMQYqOsBtOdHo4Tx1bOJ2nPtgbVmM4CXBqKIYhLC337wsL0q6wsrIyff7zn5fL5dI///lPrV+/Xs8995z27duna665Rlu2bNF3vvOdT/wa1dXV+ta3vqVFixYpPz//mB9TXl6uf/7zn7rwwgu1fv16LV68WD//+c+1c+dOPf/880d97Pbt2/Xggw/qRz/6kXJycnrtez1Vn//85/Xwww/r4Ycf1tNPP63ly5ertrZWf/jDH+RwOHT33XfrBz/4gbF8vWFQWpxGDEiQ0+3REkYlAgD62FPrD0mSrpqcqwh78L584Px0fOFwfjoZl/qe0H9pyxHDSQAAoWhDSb22HGpQpMOmm2YOMh3ntHCeOr5wOk/NG+69T912uFE1LZ2G0wAnL3hfzQJnYPn+aknS3CDdF/bwww+ro6ND5513nj772c/2vD0qKkp/+tOfFBsbq3/84x+qra097tf4n//5H7W2turBBx887sds375dTqdTN998c8/TOrfddpskafPmzUd97J133qkhQ4bo61//+hl8Z30jJiZGd911l1599VXZ7Xb96le/0pYtW0zHOiOLxgyQJL25k70WAIC+U9HYoSV7vOema4J8RCLnp1MTiuenE7l4fLZslrSptEGH6k5+zBMAACfjgXf3S5KunJSj9Pgow2lOD+epUxOq56nMhGiNzk6UJC3fR3cYggfFMISd0to2Haprl8NmaUZhmuk4p2XDhg2SpIULF37sfRkZGRo9erS6u7v12muvHfPz33jjDT322GP6wQ9+oCFDhhz3z6mvr5ckpaSk9LzN/5/r6up63vbYY49p2bJleuCBBxQREXHK309/WbhwYc/86AceeMBwmjOzaLR3r8XSPdXq6P74iAAAAHrD42tL5XJ7NH1wqoZmxpuOc0Y4P52eUDo/nUhmQrRm+l4fvLyV7jAAQO/ZfKhBy/ZWy26z9OWFQ03HOW2cp05PKJ6nFozwjkpctrfacBLg5FEMQ9h539cVNjk/RfFRDsNpTk9ra6ukow8FH5aamipJx3zapK2tTXfccYdGjhx5wtZ1f7v6vn37et62d+9eSdKgQd6W/paWFn3729/WVVddpfPOO+8Uv5P+d91110mSlixZYjjJmRmbk6jspGi1dbm0Yj9P4QAAel+3y60n1pVKUtCO8vkwzk+nL1TOTyfjMv+oxM0U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",
+      "text/plain": [
+       "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(mu_mu)\n", + "\n", + "with model as m:\n", + " idata = pm.sample()\n", + "\n", + "az.plot_posterior(idata)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "93dbf1e3-0242-4da8-aa2f-62c5541f14cc", + "metadata": {}, + "outputs": [ { "data": { "image/svg+xml": [ @@ -417,226 +397,310 @@ "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "cluster10\n", - "\n", - "10\n", + "cluster10000 x 3\n", + "\n", + "10000 x 3\n", "\n", "\n", - "cluster10000 x 10\n", - "\n", - "10000 x 10\n", + "cluster3\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "mu_param\n", - "\n", - "mu_param\n", - "~\n", - "MvNormal\n", + "y\n", + "\n", + "y\n", + "~\n", + "MarginalLaplace\n", "\n", - "\n", + "\n", "\n", - "y\n", - "\n", - "y\n", - "~\n", - "MarginalLaplace\n", + "mu_param\n", + "\n", + "mu_param\n", + "~\n", + "Multivariate_normal\n", "\n", "\n", "\n", "mu_param->y\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 6, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "output_rvs = [rv_to_marginalize, *dependent_rvs]\n", - "rng_updates = collect_default_updates(output_rvs, inputs=input_rvs, must_be_shared=False)\n", - "outputs = output_rvs + list(rng_updates.values())\n", - "inputs = input_rvs + list(rng_updates.keys())\n", - "# Add any other shared variable inputs\n", - "inputs += collect_shared_vars(output_rvs, blockers=inputs)\n", - "\n", - "inner_inputs = [inp.clone() for inp in inputs]\n", - "inner_outputs = clone_replace(outputs, replace=dict(zip(inputs, inner_inputs)))\n", - "inner_outputs = remove_model_vars(inner_outputs)\n", - "\n", - "marginalize_constructor = MarginalLaplaceRV\n", - "\n", - "_, _, *dims = rv_to_marginalize.owner.inputs\n", - "marginalization_op = marginalize_constructor(\n", - " inputs=inner_inputs,\n", - " outputs=inner_outputs,\n", - " dims_connections=[\n", - " (None,),\n", - " ], # dependent_rvs_dim_connections, # TODO NOT SURE WHAT THIS IS\n", - " dims=dims,\n", - " # x0=x0,\n", - " # marginalized_rv_input_rvs=marginalized_rv_input_rvs\n", + "model_marg = marginalize(\n", + " model,\n", + " [x],\n", + " Q=Q_val,\n", + " temp_kwargs=[n, y_obs],\n", + " minimizer_kwargs={\"method\": \"BFGS\", \"optimizer_kwargs\": {\"tol\": 1e-8}},\n", ")\n", - "\n", - "new_outputs = marginalization_op(*inputs)\n", - "for old_output, new_output in zip(outputs, new_outputs):\n", - " new_output.name = old_output.name\n", - "\n", - "model_replacements = []\n", - "for old_output, new_output in zip(outputs, new_outputs):\n", - " if old_output is rv_to_marginalize or not isinstance(old_output.owner.op, ModelValuedVar):\n", - " # Replace the marginalized ModelFreeRV (or non model-variables) themselves\n", - " var_to_replace = old_output\n", - " else:\n", - " # Replace the underlying RV, keeping the same value, transform and dims\n", - " var_to_replace = old_output.owner.inputs[0]\n", - " model_replacements.append((var_to_replace, new_output))\n", - "\n", - "print(inner_inputs)\n", - "print(inner_outputs)\n", - "print(inputs)\n", - "\n", - "print(outputs)\n", - "print(new_outputs)\n", - "\n", - "fg.replace_all(model_replacements)\n", - "fg.dprint()\n", - "\n", - "model_marg = model_from_fgraph(fg, mutate_fgraph=True)\n", - "pm.model_to_graphviz(model_marg)" + "pm.model_to_graphviz(model_marg, var_names=[\"y\"])" ] }, { "cell_type": "code", - "execution_count": 93, - "id": "793248a1-8088-41fc-9dbd-c58e596e0df7", + "execution_count": 66, + "id": "f6594a85-f833-49cb-8dfc-395615f97490", "metadata": {}, "outputs": [ { - "ename": "TypeError", - "evalue": "Only tensors with the same number of dimensions can be joined. Input ndims were: [3, 2]", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mTypeError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[93]\u001b[39m\u001b[32m, line 8\u001b[39m\n\u001b[32m 5\u001b[39m b = pt.vector(\u001b[33m'\u001b[39m\u001b[33mb\u001b[39m\u001b[33m'\u001b[39m, shape=(\u001b[32m3\u001b[39m,))\n\u001b[32m 7\u001b[39m eqns = pt.stack([A @ x - b])\n\u001b[32m----> \u001b[39m\u001b[32m8\u001b[39m var = \u001b[43mpt\u001b[49m\u001b[43m.\u001b[49m\u001b[43mstack\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mA\u001b[49m\u001b[43m,\u001b[49m\u001b[43mb\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 10\u001b[39m soln, _ = root(eqns, variables=var)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/tensor/basic.py:2977\u001b[39m, in \u001b[36mstack\u001b[39m\u001b[34m(tensors, axis)\u001b[39m\n\u001b[32m 2973\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mconcatenate\u001b[39m(tensor_list, axis=\u001b[32m0\u001b[39m):\n\u001b[32m 2974\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Alias for `join`(axis, *tensor_list).\u001b[39;00m\n\u001b[32m 2975\u001b[39m \n\u001b[32m 2976\u001b[39m \u001b[33;03m This function is similar to `join`, but uses the signature of\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m2977\u001b[39m \u001b[33;03m numpy's concatenate function.\u001b[39;00m\n\u001b[32m 2978\u001b[39m \n\u001b[32m 2979\u001b[39m \u001b[33;03m Raises\u001b[39;00m\n\u001b[32m 2980\u001b[39m \u001b[33;03m ------\u001b[39;00m\n\u001b[32m 2981\u001b[39m \u001b[33;03m TypeError\u001b[39;00m\n\u001b[32m 2982\u001b[39m \u001b[33;03m The tensor_list must be a tuple or list.\u001b[39;00m\n\u001b[32m 2983\u001b[39m \n\u001b[32m 2984\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m 2985\u001b[39m \u001b[38;5;66;03m# Check someone did not make the common mistake to do something like:\u001b[39;00m\n\u001b[32m 2986\u001b[39m \u001b[38;5;66;03m# c = concatenate(x, y)\u001b[39;00m\n\u001b[32m 2987\u001b[39m \u001b[38;5;66;03m# instead of\u001b[39;00m\n\u001b[32m 2988\u001b[39m \u001b[38;5;66;03m# c = concatenate((x, y))\u001b[39;00m\n\u001b[32m 2989\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(tensor_list, \u001b[38;5;28mtuple\u001b[39m | \u001b[38;5;28mlist\u001b[39m):\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/tensor/basic.py:2817\u001b[39m, in \u001b[36mjoin\u001b[39m\u001b[34m(axis, *tensors_list)\u001b[39m\n\u001b[32m 2815\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m tensors_list[\u001b[32m0\u001b[39m]\n\u001b[32m 2816\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m2817\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_join\u001b[49m\u001b[43m(\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43mtensors_list\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/graph/op.py:293\u001b[39m, in \u001b[36mOp.__call__\u001b[39m\u001b[34m(self, name, return_list, *inputs, **kwargs)\u001b[39m\n\u001b[32m 249\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__call__\u001b[39m(\n\u001b[32m 250\u001b[39m \u001b[38;5;28mself\u001b[39m, *inputs: Any, name=\u001b[38;5;28;01mNone\u001b[39;00m, return_list=\u001b[38;5;28;01mFalse\u001b[39;00m, **kwargs\n\u001b[32m 251\u001b[39m ) -> Variable | \u001b[38;5;28mlist\u001b[39m[Variable]:\n\u001b[32m 252\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33mr\u001b[39m\u001b[33;03m\"\"\"Construct an `Apply` node using :meth:`Op.make_node` and return its outputs.\u001b[39;00m\n\u001b[32m 253\u001b[39m \n\u001b[32m 254\u001b[39m \u001b[33;03m This method is just a wrapper around :meth:`Op.make_node`.\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 291\u001b[39m \n\u001b[32m 292\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m293\u001b[39m node = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mmake_node\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 294\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m name \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 295\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(node.outputs) == \u001b[32m1\u001b[39m:\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pytensor/pytensor/tensor/basic.py:2510\u001b[39m, in \u001b[36mJoin.make_node\u001b[39m\u001b[34m(self, axis, *tensors)\u001b[39m\n\u001b[32m 2507\u001b[39m ndim = tensors[\u001b[32m0\u001b[39m].type.ndim\n\u001b[32m 2509\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m builtins.all(x.ndim == ndim \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m tensors):\n\u001b[32m-> \u001b[39m\u001b[32m2510\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[32m 2511\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mOnly tensors with the same number of dimensions can be joined. \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 2512\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mInput ndims were: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m[x.ndim\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mfor\u001b[39;00m\u001b[38;5;250m \u001b[39mx\u001b[38;5;250m \u001b[39m\u001b[38;5;129;01min\u001b[39;00m\u001b[38;5;250m \u001b[39mtensors]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 2513\u001b[39m )\n\u001b[32m 2515\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m 2516\u001b[39m static_axis = \u001b[38;5;28mint\u001b[39m(get_scalar_constant_value(axis))\n", - "\u001b[31mTypeError\u001b[39m: Only tensors with the same number of dimensions can be joined. Input ndims were: [3, 2]" + "name": "stdout", + "output_type": "stream", + "text": [ + "[0. 0. 0.]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Initializing NUTS using jitter+adapt_diag...\n", + "Multiprocess sampling (4 chains in 4 jobs)\n", + "NUTS: [mu_param]\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "179173d67a5b43bc95d64d67d2165304", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 13 seconds.\n"
      ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "array([,\n",
+       "       ,\n",
+       "       ], dtype=object)"
+      ]
+     },
+     "execution_count": 66,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAABsMAAAIKCAYAAAB2sjG8AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAA43BJREFUeJzs3Xd4nNWZ/vF7inqvVrNky91yr+ACNi50TA0JyYaSRjYQEkIgWdhN2WSTLBAC+S0bNgWHBEhCEpppBmOwDe69Wy6yLcnqvUsz7++PmRE2brIt6Uz5fq6LK2Rm9M4tS1hH73PO89gsy7IEAAAAAAAAAAAABCG76QAAAAAAAAAAAABAX6EYBgAAAAAAAAAAgKBFMQwAAAAAAAAAAABBi2IYAAAAAAAAAAAAghbFMAAAAAAAAAAAAAQtimEAAAAAAAAAAAAIWhTDAAAAAAAAAAAAELQohgEAAAAAAAAAACBoUQwDAAAAAAAAAABA0KIYBgAAAAAAAAAAgKBFMQwAAAAAAAAAAABBi2IYAAAAAAAAAAAAghbFMAAAAAAAAAAAAAQtimEAAAAAAAAAAAAIWhTDgHNgs9lks9kkSS+//LJmzJih2NhYDRgwQLfffrvKysq6X/vss89q8uTJiomJUXp6uu6++27V19efdM0f/vCHstls+uEPf3jK91y8eLFsNpvuuOOO8859/DUaGxt1//33a9CgQYqMjFR+fr4efvhhtbS0nPJj3333Xd1zzz0aP368kpOTFRkZqSFDhujrX/+6jhw5csqPueOOO2Sz2bR48WIdOnRId9xxh7Kzs+V0Ors/T5fLpVdffVV33XWXCgoKlJCQoOjoaI0aNUoPPvigqqqqTnntOXPmyGaz6YMPPtC2bdu0aNEipaamKj4+XvPnz9eGDRu6X7ty5UpdccUVSk5OVlxcnK6++mrt2bPnvP8cAQBA32O9xXoLAAD0LdZbrLeAUEQxDDgPv/71r3XjjTfq6NGjGjp0qOrr6/Xcc89p3rx5amtr03333ae77rpLdXV1Gjx4sGpra/XMM89o0aJFsizLWO729nZdeuml+tWvfqXY2FgNGzZMRUVF+q//+i/NmzfvlAuGK6+8Uk8//bTKysqUl5enYcOGqby8XL/5zW80adIk7dq167Tvt3fvXk2aNEl/+ctflJGRoWHDhnUvto4dO6brr79ef/zjH1VbW6uhQ4cqLy9PRUVFevTRRzV16lSVl5ef9tpr167VRRddpBUrVmjQoEGy2+1atmyZLrvsMu3cuVMvvfSSLrvsMm3evFmDBw+W2+3Wm2++qUsuueSM1wUAAP6B9RbrLQAA0LdYb7HeAkKKBaDHJFmSrJiYGOuFF17ofvzo0aPW0KFDLUnW9ddfbyUkJFjvvfde9/Pbtm2zkpOTLUnWm2++ecI1f/CDH1iSrB/84AenfM9nn33WkmTdfvvt553bdw2n02llZ2dbW7Zs6X5u+/bt1sCBAy1J1gMPPHDSxz7zzDNWSUnJCY+1tLRYP/3pTy1J1pw5c076mNtvv92SZDkcDuu6666zqquru59rbW21LMuy6urqrMWLF5/wnGVZVm1trXXPPfdYkqw77rjjpGtfeumlliQrLCzMuv/++6329nbLsiyrra3NWrRoUXemxMRE6/HHH7dcLlf3dadNm2ZJsh588MGe/tEBAIB+xnrLg/UWAADoK6y3PFhvAaGFYhhwDnyLhfvuu++k55555pnu55944omTnv/e975nSbK++c1vnvB4fy4WJFn//Oc/T3r+tdde614ENTQ09Pi6s2bNsiRZxcXFJzzuWyxkZGRYTU1N55V54MCBVnR0tNXZ2XnC477FwsSJEy23233Cc3v37u3+PBctWnTSNd9++21LkjVu3LjzygQAAPoe660Tsd4CAAC9jfXWiVhvAaHB2dMTZAA+8aUvfemkxyZMmND973fddddJz0+cOFGSdPDgwT7LdTbZ2dlatGjRSY9fc801ys3N1ZEjR/TRRx/piiuuOOH5DRs26O9//7t27dql+vp6uVwuSVJhYaEkadu2bcrOzj7pujfddJNiYmLOmOn999/X66+/rn379qmxsVFut1uSVF9fr5aWFhUWFmrUqFEnfdydd97ZfSTdZ/jw4YqOjlZLS8spv0b+8DUAAAA9w3qL9RYAAOhbrLdYbwGhhGIYcB6GDBly0mNpaWnd/xsfH3/a55uamvo23BmMGDFCdvvJowJtNptGjBihI0eOaN++fd2LBcuydM899+jpp58+43VrampO+fipfsj7dHR06NZbb9Urr7xyXtc+1ddAklJTU3XkyJEzfo1Mfg0AAEDPsN46EestAADQ21hvnYj1FhDcTv5bA8BZRUdHn/SYbxfHqZ47/nnL4IDR9PT00z43YMAASVJjY2P3Y3/605/09NNPKyYmRk8//bQKCwvV0tIiy9NiVZ///OclSZ2dnae85pl2zfz85z/XK6+8ooyMDD333HMqKipSW1tb97Vnzpx5xmuf7c/5TF8jAADg/1hvsd4CAAB9i/UW6y0glHAyDDDsbIuI5ubmXnuvysrK0z5XUVEhSYqLi+t+7Pnnn5ckPf744/ra17520sccPXr0vLP4rr148WJdfvnlvXptAACA47HeYr0FAAD6Fust1luAv+NkGGCYb3fJ6X6Q79+/v9fea+/evd09i49nWZb27t0rydOX2KeoqEiSNGPGjJM+prOzU7t37z7vLGe6dnV1tUpKSs772gAAAMdjvcV6CwAA9C3WW6y3AH9HMQwwLD8/X5K0fv36k55rbm7WX/7yl157r+LiYr3++usnPf7GG2/o8OHDiomJ6T6+LUlRUVGSpPLy8pM+5tlnnz3jTpyzOdO1H3/88e4hpgAAABeK9RbrLQAA0LdYb7HeAvwdxTDAsLlz5yoyMlIbNmzQ//3f/3U/XldXpzvuuEPV1dW99l5Op1P33nuvtm/f3v3Yrl27dM8990iS7r777hOOkc+aNUuS9Mgjj5ywMHj77bf13e9+V5GRkeedxXft73znO90DPy3L0nPPPafHHnvsgq4NAABwPNZbrLcAAEDfYr3FegvwdxTDAMOSkpL08MMPS5K+9rWvKScnR1OmTFFWVpZWrlzZ/VxvuPnmm5Wamqrx48dr7NixGjdunMaMGaPDhw9r6tSp+tGPfnTC6x988EElJydr7dq1ysvL08SJEzV48GBdeeWVmjx5sm666abzzvKjH/1IEREReu2115Sdna0pU6YoJydHt99+uz772c9q+vTpF/rpAgAASGK9xXoLAAD0NdZbrLcAf0cxDPADjzzyiP7nf/5Ho0ePVmVlpY4ePaqbb75ZGzZsUF5eXq+9T0REhD788EPdd999amho0N69e5Wbm6vvfe97Wr58eXd/Z5/c3FytXr1aN954o8LDw7Vnzx5FRkbqRz/6kd5++205nc7zzjJ58mStWLFCCxYskNvt1p49e5Senq6nnnpKf/zjHy/0UwUAADgB6y3WWwAAoG+x3mK9Bfgzm2VZlukQAPrW4sWLdeedd+r222/X4sWLTccBAAAIOqy3AAAA+hbrLQAXgpNhAAAAAAAAAAAACFoUwwAAAAAAAAAAABC0zr8hKgAj/uu//ktvvvlmj16bmZmpl156qY8TAQAABBfWWwAAAH2L9RaA/kYxDAgw+/bt00cffdSj1/bmcFIAAIBQwXoLAACgb7HeAtDfbJZlWaZDAAAAAAAAAAAAAH2BmWEAAAAAAAAAAAAIWhTDAAAAAAAAAAAAELQohgEAAAAAAAAAACBoUQwDAAAAAAAAAABA0KIYBkCS9Oabb2r+/PlKTk5WTEyMJk2apF//+tdyu92mowEAAAS0Q4cO6be//a2+8pWvaPz48XI6nbLZbPrJT35iOhoAAEDAsyxLq1at0ne/+11ddNFFSkxMVHh4uLKysnTTTTdp+fLlpiMC8AM2y7Is0yEAmPXzn/9c3//+9yVJ+fn5io2N1Y4dO+R2u3Xdddfp5Zdflt1O7RwAAOB8fOtb39KTTz550uP/+Z//qUceecRAIgAAgOCxbNkyzZ8/X5Jkt9s1dOhQxcTEqLCwUE1NTZKkRx55RP/5n/9pMiYAw7i7DYS41atX69/+7d9kt9v1wgsv6MCBA9q6das2bdqkAQMG6LXXXtMvf/lL0zEBAAACVmpqqq655hr9+Mc/1ltvvaWbbrrJdCQAAICgYVmWhg4dqqefflpVVVXau3evNm3apOrq6u7N3z/5yU+0ZMkSw0kBmMTJMCDEXX311XrzzTf11a9+Vc8888wJz73wwgv6/Oc/r5SUFB07dkxhYWGGUgIAAASPO+64Q3/84x85GQYAANALGhoaFB0dLafTecrnr7rqKr311lu67rrr9Oqrr/ZzOgD+gpNhQAhraGjQe++9J0n60pe+dNLzt9xyi+Lj41VdXU1/ZQAAAAAAAPid+Pj40xbCJGnBggWSpH379vVXJAB+iGIYEMI2b96sjo4ORUZGatKkSSc9HxYWpqlTp0qS1q5d29/xAAAAAAAAgAvS1tYmSYqKijKcBIBJFMOAEFZYWChJys3NPe0Omvz8/BNeCwAAAAAAAAQCy7L00ksvSZJmzpxpOA0AkyiGASGstrZWkpSUlHTa1/ie870WAAAAAAAACAS//e1vtXnzZoWHh+tb3/qW6TgADKIYBoQw3zHx8PDw074mIiJCktTa2tovmQAAAAAAAIALtWnTJt13332SpJ/85CcaMmSI4UQATKIYBoSwyMhISVJHR8dpX9Pe3i6JvsoAAAAAAAAIDIcOHdI111yjtrY23XbbbXrggQdMRwJgGMUwIIT1pAViT1opAgAAAAAAAP6grKxMCxYs0LFjx3T11Vdr8eLFstlspmMBMIxiGBDChg0bJkk6cuSIurq6TvmagwcPnvBaAAAAAAAAwB/V1NRowYIFOnDggC699FK99NJLCgsLMx0LgB+gGAaEsIkTJyosLExtbW3atGnTSc93dnZq/fr1kqTp06f3dzwAAAAAAACgR5qamnTVVVdpx44dmjp1ql5//XXGfgDoRjEMCGHx8fGaP3++JOn3v//9Sc+/9NJLamhoUEpKiubMmdPP6QAAAAAAAICza29v16JFi7R27VoVFBTo7bffVlxcnOlYAPwIxTAgxD388MOy2Wz63e9+pxdffLH78a1bt+r++++XJD344IMKDw83FREAAAAAAAA4JZfLpc9+9rN6//33NWTIEL377rtKTk42HQuAn7FZlmWZDgHArJ/+9Kd65JFHJEn5+fmKjY3Vjh075Ha7dfXVV+vVV1+Vw+EwnBIAACAwffTRR1q0aFH3/29qalJ7e7uio6NPaN2zefNmDRw40EREAACAgPXiiy/qtttuk+SZeZ+enn7K12VmZuqll17qz2gA/IjTdAAA5j388MMaP368nnjiCW3cuFFlZWUaO3as7rzzTt1zzz0UwgAAAC5AZ2enqqurT3q8paVFLS0t3f/f5XL1ZywAAICg0N7e3v3vhYWFKiwsPOXr8vLy+isSAD/EyTAAAAAAAAAAAAAELWaGAQAAAAAAAAAAIGhRDAMAAAAAAAAAAEDQohgGAAAAAAAAAACAoEUxDAAAAAAAAAAAAEGLYhgAAAAAAAAAAACCFsUwAAAAAAAAAAAABC2KYQAAAAAAAAAAAAhaFMMAAAAAAAAAAAAQtCiGAQAAAAAAAAAAIGhRDAMAAAAAAAAAAEDQohgGAAAAAAAAAACAoEUxDAAAAAAAAAAAAEGLYhgAAAAAAAAAAACCFsUwAAAAAAAAAAAABC2KYQAAAAAAAAAAAAhaFMMAAAAAAAAAAAAQtCiGAQAAAAAAAAAAIGhRDAMAAAAAAAAAAEDQohgGAAAAAAAAAACAoEUxDAAAAAAAAAAAAEGLYhgAAAAAAAAAAACCltN0AAD+qbC8Ue/sLNO+8iaV1rUqISpMUwcn66ZJOUqLizAdDwAAIGhZlqUtR+v00f4q7ShpUG1LhzpcbuUmR2tMVoKuGJOhgcnRpmMCAACEjOb2Lj23+rA+2Fshy5Im5SXpjhmDlJEQaToagB6yWZZlmQ4BwD9YlqXleyv0q/cKta24/pSviQyz64GFI/SlWYNls9n6OSEAAEBwe39PuZ5ctl9bj9ad8XWzh6XqkatHa0RGXP8EAwAACFE7S+v1lT9uUGl92wmPR4U59O/XjNZt03MNJQNwLiiGAZAkbT5Sq5+8sVsbD9dKksIcNl0yLE3TBicrOylKlY3temVzibZ6i2TXjMvULz8zQeFOuq0CAABcqMrGdv3Hqzv01o4ySVK40675o9I1KTdJGQmRcthsOljVrI8PVOnjA9WyLMlpt+lf5w7Vt+YNk93OJiUAAIDedqCySTf8z0dqaOvSwOQofe2SIYoOd+iFtUe0wXsP7Vvzh+lb84cbTgrgbCiGASGutcOlx5bu1R8+OiTLkiKcdt0xY5C+dukQJceEn/Bay7L05zWH9eMlu9TpsnT12Ez9+nMTufkCAABwAXaU1Ourz3l2GzvsNn1p1mB99ZJ8pcaeujX10ZoW/eeSXVq6q1ySdHnBAD1x6wRFh9MFHwAAoLe0dbp0w9Mfa/exBk3KTdTiu6YpPjJMkuR2W/p/y/frl+/ukyT9903j9JmpA03GBXAWFMOAELb6QLW+989tOlzdIkm6cVK2HrpipAbEn7nf8Yf7KvWVP25Qh8utb88frvvmD+uPuAAAAEHng70V+vqfN6m106X8tBj9+nMTVZCV0KOP/eemYn3vH9vV4XJrUm6i/njXNMV5b9AAAADgwvzwtZ1a/HGRkmPC9dZ9s095v+yX7+7TU8sKFeG06+1vXaLBqTEGkgLoCYphQAhqbOvUz9/ao+fXHpEkZSZE6r9uHKu5I9J7fI2XNhzVd/++TQ67Ta/fM0ujs+L7Ki4AAEBQendXub7x/CZ1uNyaPSxV/++2SUqIOrdi1oaiGn3pjxtU39qpKXlJWnzXNMVGcEIMAADgQuwsrdfVT62SJD17x1TNHXnqe2Zut6Uv/mGdVu2v0pS8JP31axfLQQclwC8x7AcIMR/srdDlT6zoLoTdNj1XS799yTkVwiTplikDddXYDLnclv7t5e1yuamrAwAA9NRH+6v09T9vVIfLravGZuj3t08950KYJE0ZlKw/f2m64iOd2nC4Vve8sIl1GQAAwAX65VJP+8Nrx2edthAmSXa7TT+/aaxiwh3acLhWf/y4qJ8SAjhXFMOAEFHf0qkHXtqqO55dr9L6NuUmR+uFr0zXf90w9rzb6fzg2gLFRji15WidXlh3pJcTAwAABKf9FU26+88b1eX2zGB96rMTFe48/1/NxuYk6LkvTVdkmF0f7K3Uz97c3YtpAQAAQsvGwzVatqdCDrtN9y8YftbX5yRF6/tXjZIkPfHuPlU3tfd1RADngWIYEAKW76nQ/Cc+1N83Fstmk+6aOVhvf2u2ZgxJvaDrDoiP1HcvHyFJevK9fWrp6OqNuAAAAEGrprlDdy1er8a2Lk3OS9Ljnxkvp+PCfy2bMDBRj98yQZL0u1WH9OqWkgu+JgAAQCh63Hsq7JbJOT2eAXbbtFwVZMWrsb1LTy4r7Mt4AM4TxTAgiHW63PrZW7t15+L1qmxsV35ajP5+98X6j2tHKzq8d2ZJ3DY9VwOTo1TV1KE/rzncK9cEAAAIRi63pX99fqOO1LRoYHKU/u9fJisyzNFr1796XKbumTtUkvTIyztUXNvSa9cGAAAIBTtK6vXxgWo57TbdO29Yjz/ObrfpkatHS5KeX3tEheWNfRURwHmiGAYEqcrGdt322zV65sODkqTbL87Tm9+crcl5yb36PmEOu755mWdx8JsPD6q5ndNhAAAAp/KbDw9ozcEaxYQ79IfbpyolNqLX3+Nb84dpYm6iGtu7dP9ftzI/DAAA4Bz8dqXnPtrV4zKVnRh1Th978ZAULRw9QC63pSfe29cX8QBcAIphQBAqqWvVrc+s1vqiWsVFOPX05yfpR4vG9OrO4+PdMDFbg1NjVNPcoefXcjoMAADg07YX1+uJdz03RX60aIyGDYjrk/dxOux68taJigl3aF1RjX7z4YE+eR8AAIBgU1rXqiXbjkmSvjI7/7yu8Z2FnnEib24v094yTocB/oRiGBBkjtW36jO/Wa2DVc3KTozSq/fM1FVjM/v0PZ0Ou+6+1LNI+NOaw+xABgAAOE5rh0v3/XWzutyWrhqboZsmZffp++WmROtHi8ZI8gxx50YMAADA2f1xdZFcbksX56doTHbCeV1jREacrhqbIUn69fvMDgP8CcUwIIg0tnXqzmfXq6SuVfmpMXrp7ouVnxbbL+993fhsJUSF6WhNqz7YW9Ev7wkAABAIHn1nrw5WNmtAfIR+ev1Y2Wy2Pn/PmyZla+HoAepyW/reP7exWQkAAOAMOrrc+vuGYknSnTMHXdC17vWOE3lj+zFmhwF+hGIYECTcbkv3vrhZe8oalRYXoee+NE1Z59jb+EJEhTv0mSk5kqTnVtMqEQAAQPIMYV/88SFJ0i9uGqekmPB+eV+bzaYfLxqj2AinNh+po5U1AADAGby3u1zVzR1Kj4vQZSPTL+haozLjdXnBAFmW9Ov39/dSQgAXimIYECR+t+qgPthbqcgwu35/+xTlJEX3e4YvXJQnm036cF+lDlU19/v7AwAA+BOX29K/vbxdbku6dnyW5oy4sBsr5yojIVIPXeGZW/Hfb+/VsfrWfn1/AACAQPGX9UclSbdMyZHTceG3zL85z3M67PVtpTpQ2XTB1wNw4SiGAUFgR0m9Hn1nryTpB9cWaFxOopEceSkxumRYmiTp7xuPGskAAADgL55fe1jbiusVF+nUv18zykiGz0/P06TcRDW1d+lHr+0ykgEAAMCfHa1p0crCSknSrVNye+WaBVkJmj8qXZYlPfPhgV65JoALQzEMCHBdLrceeGmrOl2WLi8YoM9OHWg0z2emeN7/HxtLmE0BAABCVkVjmx5927NZ6cHLRyg9LtJIDrvdpp/dOE4Ou01v7yzTx/urjOQAAADwVy9tOCrLkmYNTVVuSu91WvrXuUMlSf/cVKLSOk7oA6ZRDAMC3Ivrj2pPWaMSosL0sxvH9ctA9jOZPzpdidFhKmto0yputgAAgBD11LJCNbZ3aVxOgm6bnmc0y4iMOH1humeX84+X7FKXy200DwAAgL/ocrn1tw3FkqRbe3mD+aTcJF2Un6wut6XfrjzYq9cGcO4ohgEBrK6lQ79c6tlxfP+C4Urup4HsZxLhdGjR+CxJnp01AAAAoaaoqll/WedZB/3bVaPksJvdrCRJ35o/XAlRYdpT1tg9EwMAACDUrSisVFlDm5Kiw7SwYECvX/8b3tNhL647ouqm9l6/PoCeoxgGBLD//eCAals6NXxArD4/vXd6GveGW7ytEpfuKld9a6fhNAAAAP3rsaV71eW2NGdEmi7KTzEdR5KUFBOub8/3DHJ/fOle1bewRgMAAHjRu4Hppkk5inA6ev36s4amalxOgto63Xr2o6Jevz6AnqMYBgSo+pZO/XnNYUnSg5ePlNPhP/85F2TFa1h6rDq63Hp3V7npOAAAAP1me3G9lmw7JpvNs0bzJ5+/KE9D02NV29Kppz/cbzoOAACAURUNbXp/T4Uk6bPTerdFoo/NZtO/zhkiSfrj6iI1trEhCTDFf+6eAzgnf1xdpOYOl0ZmxGneqHTTcU5gs9l0rbdV4utbSw2nAQAA6D///c4eSdKi8VkanRVvOM2Jwhx2ff9KT4Fu8UdFKm9oM5wIAADAnH9sKpHLbWlyXpKGpsf12fssHJ2hIWkxamzr0p/XHOmz9wFwZhTDgADU0tGlZz86JEn6+pwhstnMz6H4tGvGZUqSVu2vUk1zh+E0AAAAfW/j4VqtLKyS027T/QtGmI5zSpeNTNfkvCS1d7n11LJC03EAAACMsCxLL230tEj8zJScPn0vu92mr8/xzA77/apDaut09en7ATg1imFAAHp5c4lqWzqVmxytq8dmmo5zSvlpsSrIipfLbemtHcdMxwEAAOhzv37fU1y6aVKOclOiDac5NZvNpgcv9xTq/rr+qA5XNxtOBAAA0P82HanVwcpmRYU5dPW4rD5/v0UTspSdGKWqpna9tOFon78fgJNRDAMC0F+8wz2/eHGeX80K+zRfq8QlWymGAQCA4La9uF4f7K2U3eY5ue/Ppuen6NLhaepyW/rlu/tMxwEAAOh3f1tfLEm6elymYiOcff5+YQ67vnZpviTpmRUH1ely9/l7AjiR/95FB3BKO0rqtb2kXuEOu26c1LfHuC+U79TamkPVqmAmBQAACGK+U2GLJmRrUGqM4TRn913v6bDXtpZq97EGw2kAAAD6T0tHl5Zs88y4v2Vy/91b+8yUgUqNDVdxbate31rab+8LwINiGBBg/rrecypsYcEAJceEG05zZgOTozUxN1GWJb2xndNhAAAgOO0pa9DSXeWy2aRvzPXvU2E+Y7ITdPW4TFmW9Ng7e03HAQAA6Ddvbi9Tc4dLg1KiNW1wcr+9b2SYQ3fNGixJevqDA3K7rX57bwAUw4CA0tbp0itbSiRJn52aazhNz1zr7bu8ZBvFMAAAEJz+94MDkqSrxmRqaHqc4TQ9950Fw+Ww27RsT4U2FNWYjgMAANAvfDO7bpkyUDabrV/f+wsX5Skuwqn9FU16d3d5v743EOoohgEB5IO9FWps61J2YpRmDEkxHadHrh6XKZtN2ni4VsW1LabjAAAA9KqSutbuTT/+Pivs0/LTYrtbAz3K6TAAABACiqqatfZQjew26cZJ2f3+/vGRYfrijDxJ0tPL98uyOB0G9BeKYUAA8d1ouWZcpuz2/t25cr4GxEdq2iDPkfM3OB0GAACCzLOrDsnltjRzaIrGZCeYjnPO7ps/TOEOu9YeqtF6TocBAIAg9/eNxZKk2cPSlJkQZSTDnTMHKzLMrq3F9fpof7WRDEAoohgGBIjWDpeW7a6QJF01NtNwmnNz7XhaJQIAgOBT39qpF9cdkSR9ZXa+4TTnJzMhSjdN9uyKfnr5fsNpAAAA+o7LbekfmzzFsM9MGWgsR2psRPf4k6feLzSWAwg1FMOAAPHB3gq1drqUkxSlcTmBtev4yjEZctht2l5Sr6KqZtNxAAAAesVf1h1Rc4dLIwbE6dLhaabjnLevXTJEdpu0fG+ldpU2mI4DAADQJ1btr9Kx+jYlRodp/uh0o1nuvnSIwh12rTtUo7UHOR0G9AeKYUCAWLLdc6rq6rGZ/T7c80KlxEZ0zzh7YzunwwAAQODr6HLr2Y+KJElfmj044NZnxxuUGtPdeeB/PzxgOA0AAEDf+Ot6z4n+6ydkK8LpMJolIyFSt0zxzG799fuczgf6A8UwIAC0d7m0fE9gtkj0uWacJ/frW0sNJwEAALhwb+04prKGNqXFRWjRhCzTcS7Y1+cMkSS9sa2Uk/wAACDolNW36Z2d5ZKkW6eaa5F4vK/PGSKn3aZV+6u06Uit6ThA0KMYBgSAtQdr1NLhUnpcRMC1SPS5vCBDTrtNe8oatb+iyXQcAACAC/Lc6sOSpC9MzzO+s7g3FGQlaO6INLkt6bcrD5qOAwAA0KteWHdELrelaYOSNSoz3nQcSVJOUrRunOSZ3frrZcwOA/oaxTAgALzvPRU2d0R6wLbgSYwO16xhqZKkJds4HQYAAALXztJ6bTxcK6fdps9N84+dxb3ha5d6Tof9Y1Oxaps7DKcBAADoHR1dbr24ztMi8V8uzjOc5kT/Omdo9+zWbcV1puMAQY1iGODnLMvS8r3eYthIs8M9L9Q14zwthJZsOybLsgynAQAAOD9/8p4Ku2JMhtLjIw2n6T3TBydrdGa82jrdetE7UwMAACDQvbOzTJWN7UqLi9DlBRmm45xgUGqMFk3wng5jdhjQpyiGAX7uYFWzDle3KMxh6z5ZFagWFgxQuMOu/RVN2lveaDoOAADAOatv6dQrW0okSV+8eJDZML3MZrPprlmDJUnPfXxYnS634UQAAAAXzreR6bZpuQp3+t/t8G/MHSqbTXp3V7l2H2swHQcIWv73Xz+AEyz3tkicNjhZsRFOw2kuTHxkmC4ZniZJWrL1mOE0AAAA5+7vm4rV1unWyIw4TR2UZDpOr7t2fKZSYyNU1tCmN7ezXgMAAIFt97EGrSuqkdNu023Tc03HOaWh6bG6emymJOn/cToM6DMUwwA/9+G+SkmeeWHB4Nrxnh/uS7aV0ioRAAAEFLfb0p/XeHYW/8vFeQE7y/VMIpwO/ctFnlkaf1h1iPUaAAAIaL9deVCSdPmYDA3w4/bW91w2VJL05o5j2l9BNyWgL1AMA/xYe5dL64tqJKn7RFWgmzdqgCKcdhVVt2hHCUe/AQBA4Fi1v0qHqpoVF+HU9d7ZDsHo8xd5WghtLa7XpiO1puMAAACcl5K6Vr22pVSS9NXZ+YbTnNnIjHhdXjBAliX9z/IDpuMAQYliGODHNh+pU1unW6mxERqWHms6Tq+IjXBqwegBkqR/bi42nAYAAKDnnvPOm7hpco5iArx99Zmkxkbo+glZkqQ/rCoyGwYAAOA8/X7lIXW5LV2cn6LxAxNNxzmre+YOkyS9trVUxbUthtMAwYdiGODHPt5fJUmaMSQlqNrw3DQpR5L02pZSBrMDAICAUFzbovf3lEuSvuBtIxjM7pw5WJL01o5jKq1rNZwGAADg3NS1dOgv649Iku6eM8Rwmp4Zm5OgGUNS5HJbbEgC+gDFMMCPfXygWpKnGBZMZg9LVWpsuKqbO7TCOxMNAADAnz2/9ojcljRzaIqGBsmJ/TMZlRmv6YOT5bakv204ajoOAADAOfnT6sNq6XBpVGa8LhmWajpOj33tUk/h7i/rj6i+pdNwGiC4UAwD/FRze5e2HK2TJM0cGjg/tHvC6bBrkXfOxj820SoRAAD4t44ut/623lMQ+peLBpkN049um54rSfrb+qNyuS3DaQAAAHqmpaNLiz8ukiTdfWl+QHVbumRYqkZmxKmlw6U/rz1sOg4QVCiGAX5qXVGNutyWcpKiNDA52nScXnfjJE8x7L1dFex0AQAAfu3dXeWqbu5QelyE5o9KNx2n31xekKHE6DCV1rdpRSGn+QEAQGBY/HGRqps7lJscravHZpqOc05sNpu+dmm+JOnZj4rU1ukynAgIHhTDAD+15mBwtkj0GZ0Zr5EZcepwubVke6npOAAAAKflmzfxmSkD5XSEzq9QkWEO3TDRs4HpL+uOGE4DAABwdvWtnfrNBwckSd9eMCwg127XjMtSVkKkqpra9fLmEtNxgKAReH8bACFiQ1GtJGna4OArhi1ZskRz5szRh49crSNP3KL7vnC9lixZ0ivXnj9/vmw2m2w2m8rKyk75mpaWFv3kJz9RQUGBoqKilJKSoiuvvFIffvhhr2QAAADB40h1i1YWVslmk26dOtB0nPOyZMkSXXrppUpISFB8fLwuvfTSHq+9PjfN0ypx2e4Kfff7j3Svs071z/e+972TPn7Pnj36xS9+oXnz5ik3N1cRERHKyMjQjTfeqJUrV/bq5wkAAPC7lQfV0NalYemxum58tuk4p3Wm9VmYw667Zg2WJP12xUG5z9Cu+oc//OE5r8+am5v1pz/9Sffee6+mTZumiIgI2Ww2/fznP++bTxbwE07TAQCcrK3TpW3FdZKkqYOSzIbpZU899ZTuu+8+OZ1OXTLnMq053KCaQ5t17bXX6sknn9Q3v/nN87724sWLtWzZMtlsNlnWqRcKTU1Nmjt3rjZs2KDk5GTNnz9fdXV1eu+99/TOO+/oD3/4g+64447zzgAAAIKL71TY7GFpAdm6+vi11/z58xUREaGlS5f2eO01fECcJuUmatOROu0qa5AkzZw5U0OHDj3ptZMnTz7psfnz56ukpETx8fGaPn26Lr74Yu3atUsvv/yyXnnlFf3yl7/Ut771rV75XAEAQGiramrX71cdkiR9Z+FwOez+OSusJ+uzz07L1VPLCnWwqlnL9lRowegBZ7zmuazPCgsL9cUvfrHXPh8gUFAMA/zQtuJ6dbospcVFKDcAb7qczr59+/Sd73xHERERWr58uS6++GLd/aeNen3lRtX+5SF95zvf0ZVXXqlhw4ad87UrKyv1wAMPaOHChdq7d68OHz71kNHvf//72rBhgyZPnqy33npLaWlpkqRVq1bp8ssv1913363LLrtMubm5F/S5AgCAwNfpcutvG4olSbdNC7xTYadae/kenzFjRo/XXp+dlqtNR+q0s9RTDPvyl7/c481Do0eP1qOPPqqbbrpJ4eHh3Y8/88wzuvvuu7vXb6NHjz6/TxIAAMDrfz84oJYOl8ZmJ+jyggzTcU7pXNZnn5ueq2c+PKjnVhedtRh2LuuzuLg4felLX9K0adM0depU/eMf/9BPf/rTC/3UAL9Hm0TAD60vqpHkORVms/nnLpbz8eSTT6qrq0t333139w/7L1yUp7DkbMVf/Bl1dXXpqaeeOq9rf+tb31Jzc7Oefvrp076mo6NDf/jDHyR5duH4CmGSNGvWLP3rv/6r2tvb9atf/eq8MgAAgOCybHe5qpralRoboXmjznwDwh+dau0lScOHD9fDDz/c47XX1WMzFR3uUF1LxzlnWLp0qT73uc+dUAiTpK997WtauHChXC6XXnrppXO+LgAAwPGO1bfqT2s8G6MfuHyE395PO5f12Rem58lmk1YWVulAZVOvZRgyZIh+97vf6atf/aomTpwop5PzMggNFMOAC1BUVCSbzaY5c+aoublZ999/vwYOHKioqChNmjRJr7/+evdrX3rpJU2bNk0xMTEaMGCAvvnNb6q1tfWkazY1Nel3T/23Sn//Df3+S7O6+wa/8sorp8zwxhtv6K677tKoUaMUHx+vmJgYjR8/Xv/1X/+l9vb2k16/ePFi2Ww2/fCHP9SRI0d02223KS0tTVFRUZoyZcoJmXubr/fxzTff3P3YjCEpGpwaI+eQGZJ0Xu//zjvv6IUXXtDDDz+sIUOGnPZ1u3fvVktLiyIiIk5YcPjMmTNHkvTqq6+ecwYAAND3+mrt9eMf/1hjx45VdHT0CWuvF9YdlSR9ZkqOwrzD1wN97eVzyy23SOrZ2ismwtknu6vHjx8vSSotLe31awMAgP7R3+uzU3njjTd0+Y236dD/flUlT35GV00cFBTrs4HJ0Zo3Ml2S9KfVp+6ABKDnKPsCvaCjo0Pz5s3TgQMHdNFFF6mpqUkrVqzQDTfcoLffflvbt2/Xgw8+qKlTp2rhwoVauXKlfv3rX6u6ulrPP/9893XKy8t12WWXadeuXXLEpmj2JXPltDq1evVq3XDDDfrZz3520uDLL33pS2publZBQYHGjh2rhoYGrVu3Tg8//LCWLVumpUuXyuFwnJS5qKhIU6dOVWRkpGbNmqXy8nKtXr1a119/vd566y0tXLiwV/+M6urqdOSIZ+bGxIkTux+32226bVquflrVrLCYBB0+fFj19fVKSEjo0XVbWlp09913a+TIkXrwwQfP+Nrm5mZJUkJCwil3CCUnJ0uSDh48qMbGRsXFxfUoAwAA6F99sfbKzs7WggUL1NLS0r32Srz0diVcdItunfpJi8RAX3v55OTkKDU1tcdrrxsmZutZ77+/994ybdmyRW1tbcrJydGVV155ynkUZ3Pw4EFJUkaGf7YxAgAAPddf67NT3Ru74867VF3fqLCUXM2+aLKcrragWZ998eJBem93hf6xsVjfvXyEYiJOfTv//fff75X1GRDULADn7dChQ5YkS5I1Z84cq6ampvu5Z5991pJkDR061EpOTrZWrFjR/VxJSYmVnp5uSbIOHDjQ/fiVV15pSbLip99kjfy3163OLpdlWZZ14MABa8iQIZbD4bC2bt16QoaXX37ZampqOuGxhoYG65prrrEkWX/84x9PeM6XS5J17733Wp2dnd3P/epXv7IkWbNnzz7pc83Ly+v+uJ7+c+jQoe6P37p1qyXJSkpKOunadS0d1uh/f8sKS8+3JFnbtm070x/7Ce6//35LkrV8+fKTsh47duyE1+7bt8+SZNlsNqu5ufmka7344ovd2bdv397jDAAAoH/01drrwQcftDo6OrofP3DggJWSmWvJZreu+sGfTsgQDGsvnwkTJvR47dXlcltZc//ltO990003WY2NjWe9js/+/futiIgIS5K1YcOGHn8cAADwL/25PjvdvbGr73/cGvjtv1u3/2Ft92PBsj5zudzW3EeXW3kPLbH+tLropNf/4Ac/uOD1me8aP/vZz876WiCQcTIM6AUOh0O//e1vlZSU1P3YF7/4RT344IPav3+//uM//kOzZ8/ufi4rK0uf//zn9cQTT2jFihXKz8/Xli1b9NZbb2nY2Mlqv/QOTR6cJqe3HU9+fr4ef/xxXX/99frd7353wmyH66+//qQ8cXFxeuKJJ7RkyRK9+uqr+uIXv3jSa3zXPL4v8De+8Q396Ec/0po1a9TR0XHCbIebb75ZVVVV5/TnEhsb2/3vTU2e3sbR0dEnvS4hKkyfm5arn/wh8oTXns2mTZv05JNP6vbbb+9ucXgmQ4cOVVZWlkpLS/Xcc8/p7rvvPuH5Z599tvvfGxsbe5QBAAD0v95ce82YMUM///nPTzg1nps3SEmXfUnVz/9Ajn3LJX2h+7lgWHv5xMTEnPDaM3HYbZoxqUDLdJcWXH6F/nDPVaqtrdWKFSv04IMP6h//+IdcLpdefvnls16rq6tLd9xxh9rb23XrrbeyaxkAgCDQ1+uz090b232sQTvDR8huSQ8sHNH9+mBZn9ntNv3LxXn60eu79NzqIn1+eu4Jfy5Dhw7VY489piuvvFJ5eXnnvT4DQgHFMKAXDBo0SEOHDj3hMbvdrry8PFVWVmrBggUnfYxvttWxY8ckSe+++64kKX3MTBXbbJoyKOmE18+aNUuStH79+pOuVVhYqDfffFP79+9Xc3Oz3G63LMvqfu5U5syZo7CwsBMeczqdys/P18aNG1VdXa3MzMzu5x577LHT/wH0gC/P6QaY3jlrsH4iz2sOVDTp5IleJ3K5XPrKV76ixMTEHmez2Wz6/ve/r3vvvVff/e53FRkZqeuuu0719fV6/PHHtXTpUjmdTnV1dcluZ6QiAAD+qjfXXosWLTppffL+ngq1pQyTJFUc3HXStYJh7XX8a3rqR/d/XeufWqnNDXZ12cKVk5Oj2267TXPnztXYsWP1yiuv6OOPP9aMGTPOeJ17771Xq1atUn5+vp5++ulzygAAAPxTX6/PpFPfG3t86T5ZljQzvVPL/r5YzwTh+uymyTn677f3al95kzYdqdPkvE/uGX7hC1844bUxMTHntT4DQgHFMKAXZGdnn/Jx326OUz3ve843yLOoqEiS9NGLT0l6St/+hfTtU1zz+B0olmXpgQce0BNPPHHamxmnO+GUk5Nzysd9O1ZONWD0Qvjmb/nmdn1admKU4p1uVUp6eUe1vrDozNf71a9+pU2bNun3v/+9UlNTe5zjG9/4hg4cOKAnn3xSd9555wnPPfTQQ3r++edVXFx8wk4mAADgX3pz7fXQQw/poYceOu17VVcH59pL8sxePT7D2YzOitfIjDjtKWvUG9uP6bbpuZKkzMxM3XnnnXrsscf0zjvvnPFmy49//GP95je/0YABA/TOO+90z2wFAACBrT/XZ757YxsP1+rdXWWqW/57vbjhVb0QpOuz+MgwXTU2U//YVKy/rT96QjHsdM5lfQaECophQC84046OnjwveU46SVJEToHCkjK0aHxWd5vE4x1f+PnrX/+qX/7yl8rJydGvfvUrXXzxxUpLS1NYWJg6OjoUERFx2hs1Pcl0vAceeOCcj4I/9thj3Xlzcz03S2pra9Xc3Ny94DleV5Pn+uur7NpWXKdxOYmnvfbrr78um82mP/7xj3ruuedOeK6srEySdOONNyo8PFw/+clPuncP2Ww2PfHEE7rzzjv1yiuvqLi4WKmpqbr++us1evRoPfroo4qMjFR+fv45fa4AAKD/9Obaa/bs2Sf83G/pcOnN7Z7dyVcUZGhQTkb3c8G29iouLj7htT1x/cRs/fytPVqyrbS7GCZJw4Z5TtL5dnafyv/8z//oBz/4gRISEvT222+ftHscAAAErr5cn31aamqqLMvSo+/sUcvuFWpY/0rQr89unTpQ/9hUrNe3lerfrx2t2Iiz39bvyfoMCCUUwwA/4duNEj1ipi6+7gv68zdnn+Uj1N3z93//9391zTXXnPDcwYMHezXf3//+dx0+fPicPuaHP/xh9w/8xMRE5ebm6siRI9q8eXN3ccqnuLhYtdXVikvNkD0iRr98d58W3zntjNe3LEsrVqw47fOrV6+WpFMuVMaNG6dx48ad8Njrr78ut9utWbNmndAvGgAABB/f2uvmm2/WN7/5ze7Hf/nuPq1bVqgZQ1L0wlcuOuFjgm3tVVVVpdzcXCUkJPT4Pa4em6mfv7VHaw5Wq7KxXWlxEZI8N3Wk058ye/7553XvvfcqOjpab7zxhiZMmHBOnxsAAAh+p1ufncqqwiqtOVijtv1rJAX/+mzqoCTlp8boYFWz3thWqlunnn0z09nWZ0CoYSgO4Cfmz58vSWopXKMJAxN79DG+H2oDBw486bm//e1vvZZN8hxVtyzrnP4ZNGjQCde4+uqrJXkWD5/20ksvSZIWXXutHHabPthbqbUHq0+b54MPPjjt++bl5Uny7HyxLOuUg+5P5YknnpAkffWrX+3R6wEAQODyrb1eeeWV7se6XG69tOGoJOmz006+wRCMa69P3zQ6m4HJ0Ro/MFFuS3p7p+c0vmVZ3YXCyZMnn/Qxb775pu644w6FhYXp5Zdf1syZM8/pPQEAQGg41frsVHynwiQpPaJLUvCvz2w2mz4z1fM5/nX90bNmPdv6DAhFFMMAP3HRRRcpfcQUtR/Zpi0vPammpqYTnne73Vq6dKlWrVrV/djw4cMlSf/3f/93wpHvlStX6tFHH+2f4Ofgvvvuk8Ph0G9+8xutWbOm+/HCwkL99Kc/lcPh0CMPfUe3en+4/+j1XTpytFgjR47UyJEjeyVDRUWFjhw5csJjHR0duu+++7R8+XLNnTtXt9xyS6+8FwAA8F8XXXSR5s2bp+XLl+vb3/62mpqa9OG+Sh2rb1NSdJgWjEoLibXXp3ddl5SUnHLtVVVVpeeee07t7e26ZqxnkPySraVqamrS17/+da1du1YZGRm64YYbTvi4jz76SDfffLMkT5vJhQsX9sWnCgAAgsCp1mfH890be/L517W1uF5RYQ7NmTpeUmiszx7/ylVy2m3adKROheWNJ6zPjne29RkQqugDBviJLpdb8Vfer9qaf9ObL/5eee+8rAkTJigtLU0lJSXau3evKisr9cQTT3Qfo/7mN7+pxYsX6+mnn9YHH3ygcePGqaSkRKtWrdJ3vvMdPfbYY4Y/qxONGDFCjz76qO6//37Nnj1bCxYsUHh4uJYuXarW1lb98pe/1IgRI/Sd7Ha9vrVUu4416OUNh7V3795ey7Br1y5ddtllmjRpkgYPHqyuri59/PHHqqio0MSJE7t34QAAgOD3/PPPa+HChfrVr36l5557ThED8lVvRUn2ZuX9v6Mhs/Y6Xmdn5ynXXk1NTbr99tt17733asiwEapsitBr7c3K+7cjqqmpVmJiov7+978rOjr6hI+75ppr1NraqsGDB+uVV1455U7vWbNm6ctf/nKvfu4AACAwfXp9dqp7Y6NvuFcafrlunzFINw75tv76wp9CZn32lZHpWrqrXH9df1RfGBPdvT4bNWqUcnNzVVdXp02bNqm6+vTrM0m64YYbumeJ+eaUPf30091rtczMzO6TZUCwoBgG+InCiiZ1RsRr6Jef1JdS9+ulv/1N69evV0dHhzIzMzVx4kQtWrRIn/nMZ7o/Zvjw4Vq/fr0eeughrV27Vq+99ppGjBihZ555Rl/5ylf87ge+JH3729/W0KFD9eijj2rlypWSPMe1v/vd7+q6666TJKXERujb84frx0t26f9W9m5/5yFDhuj222/XRx99pDfffFN2u10jRozQQw89pHvuuUfh4eG9+n4AAMB/DRgwQGvWrNFvfvMb/fmFF7V52w5Zri65srNCau3VEykpKXrooYe0Zs0a7d+/X23llbJsNqXk5Ok7d96hb3/728rOzj7p4+rq6iRJhw4d0qFDh057fYphAABAOnF99te//vWke2Mjps/Vy3W5igt36CuzByslNiKk1me3Th2opbvK9c/NJfr6zGknrM+2bNkih8OhwYMH6447Tr8+k6TNmzefNP/s6NGjOnrU04LRN4IECCY26/jzowCMeXHdEX3/n9tPOaw9FHW63Lr6qZXaV96kmybl6PHPjDcdCQAABLEn3yvUE+/t0/TB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WBj5+flcfvnlxMTEnHBZXFwcl1xyCXPmzGHJkiVMmjTpjHOIiHeJDbVTWu3grvc38tHtI7H72X76SsCvf/1rli5dyvPPP88999zTcHzKlCl06NCB4cOHc++993LppZc2nGARETkbrVFfvbc2g8c+2Q7ATSM78fvL+jTUUR988AEOh4Pzzz+fxMTEptwVEZEmCQ/058HJPXny8108uWAXwztH0y3up9873nXXXaSlpfHCCy9w8803n3DZww8/zHvvvUdWVhbt2rVrqegi0ga19jmymTNnsn37dubNm8eUKVMajt90002EhoYybdo07rvvPlatWnXC9Zwug8fmbcNlwCX9EhjT3X2u7NFHH+X999/nq6++atTPFxHPNmN4J95alU5GQQUvfbefRy5KBXR+y5vpt2Gyt99++6RjKSkpTJ06lfDwcCIiIiguLiYrK4vevXuf9L1ZWe5pmsnJyWf0c19bfoAnP99F+c7FAPz+17edshFWn+fgwYN06nTqjUBTUlIAyM3NPaMMIuKdRneLYVuwP1uzinlywS7+b+pP7xPhdDr54IMPALjqqqtOunzo0KF07tyZtLQ0Dhw4QI8ePZo9t4i0HS1dX7218iC/n78TgJ+N7szvLu11wj6Ks2fPBuCGG25o8n0REWmqm0d35rvduaxKK+DuDzbxyZ2jTlgW/1QsFgvPPfccN998M/PmzSMrK4uYmBimTp1K7969eeaZZwgMDKRLly6tdC9EpC1ozXNkhw4dYsmSJdjtdi677LKTLp8yZQp2u501a9ZQVVVFYOAPK6X8e/kBNmUWEWr347FLejUc7969OwBHjhz56TsrIh4vwM/K7y7pzS3vbOCNFQe57pwkktoF6vyWF1MzzGQ/NYV7wIABLFu2jI0bN570Ql9bW8v27dux2+307Nmz0T/vpe/287dv9lJbmE3NkX0EBwczbdq0015n0KBBLF68mMLCwlNeXlBQAJzd7DQR8T4hdj+evWYAP3trA++uyaBzTAg/G9P5R6+Tm5tLTU0NwClH8B1//HTPNSIijdWS9VX9gCKA28Z14ZELU09ohO3du5f169cTHBzMlVde2Qz3RkSkaWxWC89dO5CLXljOriMlPLVwN49f1qdR1+3fvz/9+/c/4dj8+fNxuVyMGTNGo51FpFm15jmy+sZZSEjIKZd8tdlsBAcHU11dTVFREfHx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REQ8064jJbz03X5qnC4cThcOl0GNw/2x2uE+YVhZ42zY/qOy1nnSXi3NrX4J9x+WafdvWLo9zH7isu0NXwf+0OSqb3wFB/hpBSUREfEJaoaJiIiIiIiIiIi0EsMwqHG6fhhhX+Ok6rhGWXWti8raH76uqnXidBn426z42yx1yzG6Pw+wWd0NrbpmV1hDE8umAXUiIiLHUTNMREREREREREREREREfFbz7tIpIiIiIiIiIiIiIiIi4kHUDBMRERERERERERERERGfpWaYiIiIiIiIiIiIiIiI+Cw1w0RERERERERERERERMRnqRkmIiIiIiIiIiIiIiIiPkvNMBEREREREREREREREfFZaoaJiIiIiIiIiIiIiIiIz1IzTERERERERERERERERHyWmmEiIiIiIiIiIiIiIiLis9QMExEREREREREREREREZ+lZpiIiIiIiIiIiIiIiIj4LDXDRERERERERERERERExGepGSYiIiIiIiIiIiIiIiI+S80wERERERERERERERER8VlqhomIiIiIiIiIiIiIiIjPUjNMREREREREREREREREfJZfY77JMAxqampaOouIiIi0soCAACwWi9kxBNVbIiIivkr1ludQvSUiIuKbGlNvNaoZVlNTw1/+8pdmCSUiIiKe45FHHsFut5sdQ1C9JSIi4qvuuusuYmJizI4hqN4SERHxVY05v2UxDMP4qRvypJEzOTk5vPXWW8yaNYv4+Hiz4/gkPcYtT49xy9Nj3PL0GLe81niMNVLZczS13tL/SfPpd+AZ9Hswn34H5tPvwDPU/x5uvfVWEhMTzY4jeNb5LU+h54um02PYPPQ4Np0ew6bTY9h0Zj2GzTYzzGKxeMyo8YCAgIaPnpLJ1+gxbnl6jFueHuOWp8e45ekxbluaWm/p78V8+h14Bv0ezKffgfn0O/AM9b8HDTzyHJ50fstT6Pmi6fQYNg89jk2nx7Dp9Bg2nSc/hlazA4iIiIiIiIiIiIiIiIi0FK9rhoWGhjJu3DhCQ0PNjuKz9Bi3PD3GLU+PccvTY9zy9BjLmdDfi/n0O/AM+j2YT78D8+l34Bn0exBvoL/TptNj2Dz0ODadHsOm02PYdJ78GDZqzzARERERERERERERERERb+R1M8NEREREREREREREREREGkvNMBEREREREREREREREfFZaoaJiIiIiIiI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xIkT6dKlC++//z6bN29uOF5aWsr//d//4efnx6xZs0zLJ9JYLpeLn//857z55ptcffXVzJ49WwVCM9u8efMpl4koLCzk0UcfBeCiiy5q7VjihVQjSVuhOkvETXWa+VTHiS9QDSmtRTWceALVT83DW2ogi2EYhtkhztZ3333HpEmTMAyD22677ZTr8w4cOJCpU6e2fjgfsmLFCl577TUA8vLy+OKLL+jatStjxowBIDU1lUceecTMiF5h8eLFTJ48GbvdzvXXX094eDhz587l4MGDPPnkkzz22GNmR/R6r732GitWrABg27ZtbNy4kdGjR9OtWzcApk6dqueDJvr973/PH/7wB0JDQ7n33ntPOapj6tSpDBw4sPXD+Yhf/epXvPbaa0yYMIFOnToREhJCRkYGn3/+OWVlZUybNo05c+Zour78KNVInkE1VOtRnWU+1WHmU51mPtVx4u1UQzYP1YCNpxqu6VSDNY3qp+bhNTWQ4cXefPNNA/jRfzNnzjQ7ptf7qcd53LhxZkf0GmvXrjUuvPBCIyIiwggKCjKGDh1qzJ492+xYPmPmzJk/+rf6+OOPmx3R6/3UYwwYb775ptkxvdry5cuNWbNmGampqUZ4eLjh5+dnxMXFGRdeeKHx/vvvGy6Xy+yI4gVUI3kG1VCtS3WWuVSHmU91mvlUx4m3Uw3ZPFQDnhnVcE2jGqxpVD81D2+pgbx6ZpiIiIiIiIiIiIiIiIjIj9HcfBEREREREREREREREfFZaoaJiIiIiIiIiIiIiIiIz1IzTERERERERERERERERHyWmmEiIiIiIiIiIiIiIiLis9QMExEREREREREREREREZ+lZpiIiIiIiIiIiIiIiIj4LDXDRERERERERERERERExGepGSYiIiIiIiIiIiIiIiI+S80wERERERERERERERER8VlqhomIiIiIiIiIiIiIiIjPUjNMREREREREREREREREfJaaYSIiIiIiIiIiIiIiIuKz/j/7J+z9+TVWRQAAAABJRU5ErkJggg==",
+      "text/plain": [
+       "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "from pytensor.tensor.optimize import root\n", - "\n", - "A = pt.matrix(\"A\", shape=(3, 3))\n", - "x = np.ones((3, 1))\n", - "b = pt.vector(\"b\", shape=(3,))\n", + "print(mu_mu)\n", "\n", - "eqns = pt.stack([A @ x - b])\n", - "var = pt.stack([A, b])\n", + "with model_marg as m:\n", + " idata_marg = pm.sample()\n", "\n", - "soln, _ = root(eqns, variables=var)" + "az.plot_posterior(idata_marg)" ] }, { "cell_type": "code", - "execution_count": 21, - "id": "07f8abf3-6158-4d62-83d2-2cffe65aae91", + "execution_count": 274, + "id": "124eb56a-9891-432a-b2ba-8c750e3f540d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "(10,)\n", - "(10, 1, 1)\n" + "0.2646751313145017\n" ] }, { "data": { + "image/png": "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", "text/plain": [ - "Reshape{4}.0" + "
" ] }, - "execution_count": 21, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "from pytensor.tensor.math import tensordot\n", - "\n", - "a = pt.tensor(\"a\", shape=(10,))\n", - "b = pt.tensor(\"b\", shape=(10, 1, 1))\n", - "\n", - "print(a.type.shape)\n", - "print(b.type.shape)\n", - "# print(b.T.type.shape)\n", + "import matplotlib.pyplot as plt\n", + "import scipy\n", "\n", - "tensordot(a, b, axes=0)" + "rng = np.random.default_rng(12345)\n", + "n = 2\n", + "d = 1\n", + "\n", + "mu_true = 2\n", + "mu_mu = 1\n", + "cov_true = np.identity(d)\n", + "\n", + "y_obs = rng.multivariate_normal(mean=np.array([mu_true]), cov=cov_true, size=n)\n", + "\n", + "mu_val = np.arange(-10, 10, 0.1)\n", + "\n", + "x0 = (y_obs.sum(axis=0) - mu_val) / (n - 1)\n", + "logp = -0.5 * (\n", + " ((y_obs - x0) ** 2).sum(axis=0)\n", + " + (x0 - mu_val) ** 2\n", + " + (mu_val - mu_mu) ** 2\n", + " + np.log(np.abs(1 - n) ** d)\n", + " - ((y_obs - mu_true) ** 2).sum(axis=0)\n", + ") - d / 2 * np.log(2 * np.pi)\n", + "p = np.exp(logp)\n", + "\n", + "P = scipy.integrate.simpson(p, x=mu_val)\n", + "print(P)\n", + "\n", + "plt.plot(mu_val, p)\n", + "plt.plot([mu_true, mu_true + 1e-12], [p.min(), p.max()], label=\"mu_true\")\n", + "plt.plot([mu_mu, mu_mu + 1e-12], [p.min(), p.max()], label=\"mu_mu\")\n", + "plt.legend()\n", + "plt.xlim([0, 5])\n", + "plt.show()" ] }, { "cell_type": "code", - "execution_count": 31, - "id": "2eee8e73-5305-4472-8f9c-58a689f9471e", + "execution_count": 276, + "id": "e3af0ddc-4ae9-4e39-aa6b-a43b1272dde9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n" + "y_logprob\n", + "0.2423859374167768\n" ] }, { - "ename": "AttributeError", - "evalue": "'MarginalLaplaceRV' object has no attribute 'owner'", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[31]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m model_marg \u001b[38;5;28;01mas\u001b[39;00m m:\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m \u001b[43mpm\u001b[49m\u001b[43m.\u001b[49m\u001b[43msample\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/sampling/mcmc.py:783\u001b[39m, in \u001b[36msample\u001b[39m\u001b[34m(draws, tune, chains, cores, random_seed, progressbar, progressbar_theme, step, var_names, nuts_sampler, initvals, init, jitter_max_retries, n_init, trace, discard_tuned_samples, compute_convergence_checks, keep_warning_stat, return_inferencedata, idata_kwargs, nuts_sampler_kwargs, callback, mp_ctx, blas_cores, model, compile_kwargs, **kwargs)\u001b[39m\n\u001b[32m 780\u001b[39m _log.warning(msg)\n\u001b[32m 782\u001b[39m provided_steps, selected_steps = assign_step_methods(model, step, methods=pm.STEP_METHODS)\n\u001b[32m--> \u001b[39m\u001b[32m783\u001b[39m exclusive_nuts = (\n\u001b[32m 784\u001b[39m \u001b[38;5;66;03m# User provided an instantiated NUTS step, and nothing else is needed\u001b[39;00m\n\u001b[32m 785\u001b[39m (\u001b[38;5;129;01mnot\u001b[39;00m selected_steps \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(provided_steps) == \u001b[32m1\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(provided_steps[\u001b[32m0\u001b[39m], NUTS))\n\u001b[32m 786\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m\n\u001b[32m 787\u001b[39m \u001b[38;5;66;03m# Only automatically selected NUTS step is needed\u001b[39;00m\n\u001b[32m 788\u001b[39m (\n\u001b[32m 789\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m provided_steps\n\u001b[32m 790\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(selected_steps) == \u001b[32m1\u001b[39m\n\u001b[32m 791\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28missubclass\u001b[39m(\u001b[38;5;28mnext\u001b[39m(\u001b[38;5;28miter\u001b[39m(selected_steps)), NUTS)\n\u001b[32m 792\u001b[39m )\n\u001b[32m 793\u001b[39m )\n\u001b[32m 795\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m nuts_sampler != \u001b[33m\"\u001b[39m\u001b[33mpymc\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 796\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m exclusive_nuts:\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/sampling/mcmc.py:245\u001b[39m, in \u001b[36massign_step_methods\u001b[39m\u001b[34m(model, step, methods)\u001b[39m\n\u001b[32m 243\u001b[39m methods_list: \u001b[38;5;28mlist\u001b[39m[\u001b[38;5;28mtype\u001b[39m[BlockedStep]] = \u001b[38;5;28mlist\u001b[39m(methods \u001b[38;5;129;01mor\u001b[39;00m pm.STEP_METHODS)\n\u001b[32m 244\u001b[39m selected_steps: \u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mtype\u001b[39m[BlockedStep], \u001b[38;5;28mlist\u001b[39m] = {}\n\u001b[32m--> \u001b[39m\u001b[32m245\u001b[39m model_logp = \u001b[43mmodel\u001b[49m\u001b[43m.\u001b[49m\u001b[43mlogp\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 247\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m var \u001b[38;5;129;01min\u001b[39;00m model.value_vars:\n\u001b[32m 248\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m var \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m assigned_vars:\n\u001b[32m 249\u001b[39m \u001b[38;5;66;03m# determine if a gradient can be computed\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/model/core.py:691\u001b[39m, in \u001b[36mModel.logp\u001b[39m\u001b[34m(self, vars, jacobian, sum)\u001b[39m\n\u001b[32m 689\u001b[39m rv_logps: \u001b[38;5;28mlist\u001b[39m[TensorVariable] = []\n\u001b[32m 690\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m rvs:\n\u001b[32m--> \u001b[39m\u001b[32m691\u001b[39m rv_logps = \u001b[43mtransformed_conditional_logp\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 692\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs\u001b[49m\u001b[43m=\u001b[49m\u001b[43mrvs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 693\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs_to_values\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mrvs_to_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 694\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs_to_transforms\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mrvs_to_transforms\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 695\u001b[39m \u001b[43m \u001b[49m\u001b[43mjacobian\u001b[49m\u001b[43m=\u001b[49m\u001b[43mjacobian\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 696\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 697\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(rv_logps, \u001b[38;5;28mlist\u001b[39m)\n\u001b[32m 699\u001b[39m \u001b[38;5;66;03m# Replace random variables by their value variables in potential terms\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/logprob/basic.py:570\u001b[39m, in \u001b[36mtransformed_conditional_logp\u001b[39m\u001b[34m(rvs, rvs_to_values, rvs_to_transforms, jacobian, **kwargs)\u001b[39m\n\u001b[32m 567\u001b[39m transform_rewrite = TransformValuesRewrite(values_to_transforms) \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[32m 569\u001b[39m kwargs.setdefault(\u001b[33m\"\u001b[39m\u001b[33mwarn_rvs\u001b[39m\u001b[33m\"\u001b[39m, \u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[32m--> \u001b[39m\u001b[32m570\u001b[39m temp_logp_terms = \u001b[43mconditional_logp\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 571\u001b[39m \u001b[43m \u001b[49m\u001b[43mrvs_to_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 572\u001b[39m \u001b[43m \u001b[49m\u001b[43mextra_rewrites\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtransform_rewrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 573\u001b[39m \u001b[43m \u001b[49m\u001b[43muse_jacobian\u001b[49m\u001b[43m=\u001b[49m\u001b[43mjacobian\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 574\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 575\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 577\u001b[39m \u001b[38;5;66;03m# The function returns the logp for every single value term we provided to it.\u001b[39;00m\n\u001b[32m 578\u001b[39m \u001b[38;5;66;03m# This includes the extra values we plugged in above, so we filter those we\u001b[39;00m\n\u001b[32m 579\u001b[39m \u001b[38;5;66;03m# actually wanted in the same order they were given in.\u001b[39;00m\n\u001b[32m 580\u001b[39m logp_terms = {}\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc/pymc/logprob/basic.py:500\u001b[39m, in \u001b[36mconditional_logp\u001b[39m\u001b[34m(rv_values, warn_rvs, ir_rewriter, extra_rewrites, **kwargs)\u001b[39m\n\u001b[32m 497\u001b[39m node_values = remapped_vars[: \u001b[38;5;28mlen\u001b[39m(node_values)]\n\u001b[32m 498\u001b[39m node_inputs = remapped_vars[\u001b[38;5;28mlen\u001b[39m(node_values) :]\n\u001b[32m--> \u001b[39m\u001b[32m500\u001b[39m node_logprobs = \u001b[43m_logprob\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 501\u001b[39m \u001b[43m \u001b[49m\u001b[43mnode\u001b[49m\u001b[43m.\u001b[49m\u001b[43mop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 502\u001b[39m \u001b[43m \u001b[49m\u001b[43mnode_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 503\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43mnode_inputs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 504\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 505\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 507\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(node_logprobs, \u001b[38;5;28mlist\u001b[39m | \u001b[38;5;28mtuple\u001b[39m):\n\u001b[32m 508\u001b[39m node_logprobs = [node_logprobs]\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/git/pymc-extras/.pixi/envs/default/lib/python3.12/functools.py:912\u001b[39m, in \u001b[36msingledispatch..wrapper\u001b[39m\u001b[34m(*args, **kw)\u001b[39m\n\u001b[32m 908\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m args:\n\u001b[32m 909\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfuncname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m requires at least \u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 910\u001b[39m \u001b[33m'\u001b[39m\u001b[33m1 positional argument\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m912\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mdispatch\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m.\u001b[49m\u001b[34;43m__class__\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkw\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[36mFile \u001b[39m\u001b[32m:17\u001b[39m, in \u001b[36mlaplace_marginal_rv_logp\u001b[39m\u001b[34m(op, values, *inputs, **kwargs)\u001b[39m\n", - "\u001b[31mAttributeError\u001b[39m: 'MarginalLaplaceRV' object has no attribute 'owner'" + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_30561/3702793765.py:45: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n", + " logp[i] = model_logp.eval({'mu_param': [mu]}) -0.5*(x0 - mu)**2 + n*1.5#- logp_y\n" ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "with model_marg as m:\n", - " pm.sample()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "991b7cbd-4ef3-487a-9ece-139226883502", - "metadata": {}, - "outputs": [], - "source": [ - "[2, 2, 3, 4, 2, 2, 2, 3, 3, 4]" + "rng = np.random.default_rng(12345)\n", + "n = 2\n", + "d = 1\n", + "\n", + "# Initialise arrays\n", + "mu_true = 2 * np.ones((d,)) # rng.random(d)\n", + "cov_true = np.identity(d) # np.diag(rng.random(d))\n", + "Q_val = np.identity(d) # np.diag(rng.random(d))\n", + "cov_param_val = np.identity(d) # np.diag(rng.random(d))\n", + "\n", + "# x_val = rng.random(d)\n", + "# mu_val = rng.random(d)\n", + "\n", + "mu_mu = np.ones((d,)) # rng.random(d)\n", + "mu_cov = np.identity(d) # np.diag(np.ones(d))\n", + "# cov_mu = rng.random(d**2)\n", + "# cov_cov = np.diag(np.ones(d**2))\n", + "# Q_mu = rng.random(d**2)\n", + "# Q_cov = np.diag(np.ones(d**2))\n", + "\n", + "with pm.Model() as model:\n", + " y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n)\n", + "\n", + " mu_param = pm.MvNormal(\"mu_param\", mu=mu_mu, cov=mu_cov)\n", + " # cov_param = np.abs(pm.MvNormal(\"cov_param\", mu=cov_mu, cov=cov_cov))\n", + " # Q = pm.MvNormal(\"Q\", mu=Q_mu, cov=Q_cov)\n", + "\n", + " x = pm.MvNormal(\"x\", mu=mu_param, tau=Q_val)\n", + "\n", + " y = pm.MvNormal(\n", + " \"y\",\n", + " mu=x,\n", + " cov=cov_param_val, # cov_param.reshape((d, d)),\n", + " observed=y_obs,\n", + " )\n", + "\n", + "# pm.model_to_graphviz(model)\n", + "model_marg = marginalize(\n", + " model,\n", + " [x],\n", + " Q=Q_val,\n", + " temp_kwargs=[n, cov_param_val, y_obs, mu_true, model.rvs_to_values[mu_param]],\n", + ")\n", + "model_logp = model_marg.logp()\n", + "\n", + "logp = np.zeros_like(mu_val)\n", + "logp_y = -0.5 * np.squeeze((y_obs - mu_true) ** 2).sum(axis=0) - d / 2 * np.log(2 * np.pi)\n", + "for i, mu in enumerate(mu_val):\n", + " x0 = (y_obs.sum(axis=0) - mu) / (n - 1)\n", + " logp[i] = model_logp.eval({\"mu_param\": [mu]}) - 0.5 * (x0 - mu) ** 2 + n * 1.5 # - logp_y\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import scipy\n", + "\n", + "p = np.exp(logp)\n", + "\n", + "P = scipy.integrate.simpson(p, x=mu_val)\n", + "print(P)\n", + "\n", + "plt.plot(mu_val, p)\n", + "plt.plot([mu_true, mu_true + 1e-12], [p.min(), p.max()], label=\"mu_true\")\n", + "plt.plot([mu_mu, mu_mu + 1e-12], [p.min(), p.max()], label=\"mu_mu\")\n", + "plt.legend()\n", + "plt.xlim([0, 5])\n", + "plt.show()" ] }, { diff --git a/pymc_extras/model/marginal/distributions.py b/pymc_extras/model/marginal/distributions.py index 42ee3ff8..25d9ff24 100644 --- a/pymc_extras/model/marginal/distributions.py +++ b/pymc_extras/model/marginal/distributions.py @@ -3,6 +3,7 @@ from collections.abc import Sequence import numpy as np +import pytensor import pytensor.tensor as pt from pymc.distributions import Bernoulli, Categorical, DiscreteUniform @@ -19,6 +20,7 @@ from pytensor.scan import map as scan_map from pytensor.scan import scan from pytensor.tensor import TensorVariable +from pytensor.tensor.optimize import minimize from pytensor.tensor.random.type import RandomType from pymc_extras.distributions import DiscreteMarkovChain @@ -135,6 +137,19 @@ class MarginalDiscreteMarkovChainRV(MarginalRV): class MarginalLaplaceRV(MarginalRV): """Base class for Marginalized Laplace-Approximated RVs""" + def __init__( + self, + *args, + Q: TensorVariable, + temp_kwargs: list, + minimizer_kwargs: dict | None = None, + **kwargs, + ) -> None: + self.temp_kwargs = temp_kwargs # TODO REMOVE + self.Q = Q + self.minimizer_kwargs = minimizer_kwargs + super().__init__(*args, **kwargs) + def get_domain_of_finite_discrete_rv(rv: TensorVariable) -> tuple[int, ...]: op = rv.owner.op @@ -389,62 +404,43 @@ def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs): rv_values = inner_rv_values | {x: marginalized_vv} logps_dict = conditional_logp(rv_values=rv_values, **kwargs) - logp = pt.sum( - [pt.sum(logps_dict[k]) for k in logps_dict] - ) # TODO check this gives the proper p(y | x, params) - - import pytensor + # logp(y | x, params) + log_likelihood = pt.sum([pt.sum(logps_dict[k]) for k in logps_dict if k != marginalized_vv]) - from pytensor.tensor.optimize import minimize + # logp = logp(y | x, params) + logp(x | params) + logp = pt.sum([pt.sum(logps_dict[k]) for k in logps_dict]) - # Maximize log(p(x | y, params)) wrt x to find mode x0 # TODO args need to be user-supplied + # Maximize log(p(x | y, params)) wrt x to find mode x0 + minimizer_kwargs = ( + op.minimizer_kwargs + if op.minimizer_kwargs is not None + else {"method": "BFGS", "optimizer_kwargs": {"tol": 1e-8}} + ) + # minimizer_kwargs = {'method': 'BFGS', 'optimizer_kwargs': {"tol": 1e-8}} x0, _ = minimize( - objective=-logp, + objective=-logp, # logp(x | y, params) = logp(y | x, params) + logp(x | params) + const (const omitted during minimization) x=marginalized_vv, - method="BFGS", - # jac=use_jac, - # hess=use_hess, - optimizer_kwargs={"tol": 1e-8}, + **minimizer_kwargs, ) - # print(op.__dict__) - # marginalized_rv_input_rvs = op.kwargs['marginalized_rv_input_rvs'] - # x0 = op.kwargs['x0'] - # log_laplace_approx = op.kwargs['log_laplace_approx'] - # return logp - log_laplace_approx - + # # Set minimizer initialisation to be random + d = 3 # 10000 # TODO pull this from x.shape (or similar) somehow rng = np.random.default_rng(12345) - d = 10 - # Q = np.diag(rng.random(d)) - from pymc import MvNormal - - x = op.owner.inputs[0] - if not isinstance(x, MvNormal): - raise ValueError("Latent field x must be MvNormal.") - Q = x.owner.inputs[1] # TODO double check this grabs the right thing - x0 = rng.random(d) - - # x0 = pytensor.graph.replace.graph_replace(x0, {marginalized_vv: rng.random(d)}) - # for rv in marginalized_rv_input_rvs: - # x0 = pytensor.graph.replace.graph_replace(x0, {marginalized_vv: rng.random(d)}) + x0 = pytensor.graph.replace.graph_replace(x0, {marginalized_vv: rng.random(d)}) - # require f''(x0) for Laplace approx - hess = pytensor.gradient.hessian(logp, marginalized_vv) - # hess = pytensor.graph.replace.graph_replace(hess, {marginalized_vv: x0}) + # TODO USE CLOSED FORM SOLUTION FOR NOW + n, y_obs = op.temp_kwargs + mu_param = pytensor.graph.basic.get_var_by_name(x, "mu_param")[0] + x0 = (y_obs.sum(axis=0) - mu_param) / (n - 1) - # Could be made more efficient with adding diagonals only - tau = Q - hess - - # Currently x is passed both as the query point for f(x, args) = logp(x | y, params) AND as an initial guess for x0. This may cause issues if the query point is - # far from the mode x0 or in a neighbourhood which results in poor convergence. + # logp(x | y, params) using laplace approx evaluated at x0 + hess = pytensor.gradient.hessian(log_likelihood, marginalized_vv) + tau = op.Q - hess _, logdetTau = pt.nlinalg.slogdet(tau) - log_laplace_approx = 0.5 * logdetTau - 0.5 * x0.shape[0] * np.log(2 * np.pi) + log_laplace_approx = 0.5 * logdetTau - 0.5 * marginalized_vv.shape[0] * np.log( + 2 * np.pi + ) # At x = x0, the quadratic term becomes 0 - # Reduce logp dimensions corresponding to broadcasted variables - # marginalized_logp = logps_dict.pop(marginalized_vv) + # logp(y | params) = logp(y | x, params) + logp(x | params) - logp(x | y, params) joint_logp = logp - log_laplace_approx - - # TODO this might cause circularity issues by overwriting x as an input to the x0 minimizer - joint_logp = pytensor.graph.replace.graph_replace(joint_logp, {marginalized_vv: x0}) - - return joint_logp # TODO check if pm.sample adds on p(params). Otherwise this is p(y|params) not p(params|y) + return pytensor.graph.replace.graph_replace(joint_logp, {marginalized_vv: x0}) From c49de10b31fce71c7cd5a4884d74713945044c58 Mon Sep 17 00:00:00 2001 From: Michal-Novomestsky Date: Sat, 9 Aug 2025 16:27:49 +1000 Subject: [PATCH 09/21] refactor: variable name change --- pymc_extras/model/marginal/distributions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymc_extras/model/marginal/distributions.py b/pymc_extras/model/marginal/distributions.py index 25d9ff24..7ff58b87 100644 --- a/pymc_extras/model/marginal/distributions.py +++ b/pymc_extras/model/marginal/distributions.py @@ -442,5 +442,5 @@ def laplace_marginal_rv_logp(op: MarginalLaplaceRV, values, *inputs, **kwargs): ) # At x = x0, the quadratic term becomes 0 # logp(y | params) = logp(y | x, params) + logp(x | params) - logp(x | y, params) - joint_logp = logp - log_laplace_approx - return pytensor.graph.replace.graph_replace(joint_logp, {marginalized_vv: x0}) + marginal_likelihood = logp - log_laplace_approx + return pytensor.graph.replace.graph_replace(marginal_likelihood, {marginalized_vv: x0}) From 54e394df8f641973f7d0d91a8319eef9d7175264 Mon Sep 17 00:00:00 2001 From: Michal-Novomestsky Date: Sun, 10 Aug 2025 21:50:26 +1000 Subject: [PATCH 10/21] jesse minimize testing --- notebooks/INLA_JESSE.ipynb | 522 ++++++++++++++++++++ notebooks/INLA_testing.ipynb | 256 ++++++++-- pymc_extras/inference/fit.py | 2 +- pymc_extras/inference/inla.py | 56 ++- pymc_extras/model/marginal/distributions.py | 8 +- 5 files changed, 760 insertions(+), 84 deletions(-) create mode 100644 notebooks/INLA_JESSE.ipynb diff --git a/notebooks/INLA_JESSE.ipynb b/notebooks/INLA_JESSE.ipynb new file mode 100644 index 00000000..7d5eddf1 --- /dev/null +++ b/notebooks/INLA_JESSE.ipynb @@ -0,0 +1,522 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "ffd6780e-1bfb-42f0-ba6a-055e9ffd1490", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5a2819fd-6e01-47c0-88b2-f2b5e4215b9b", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pymc as pm\n", + "import pytensor.tensor as pt\n", + "\n", + "import pytensor\n", + "\n", + "from pymc.model.fgraph import fgraph_from_model, model_from_fgraph" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9f8841b1-9da5-43b2-bf64-6bb93c8f4e93", + "metadata": {}, + "outputs": [], + "source": [ + "def marginalize(\n", + " model,\n", + " rvs_to_marginalize,\n", + " Q,\n", + " temp_kwargs,\n", + " minimizer_kwargs={\"method\": \"BFGS\", \"optimizer_kwargs\": {\"tol\": 1e-8}},\n", + "):\n", + " from pymc.model.fgraph import (\n", + " ModelFreeRV,\n", + " ModelValuedVar,\n", + " )\n", + "\n", + " from pymc_extras.model.marginal.graph_analysis import (\n", + " find_conditional_dependent_rvs,\n", + " find_conditional_input_rvs,\n", + " is_conditional_dependent,\n", + " subgraph_batch_dim_connection,\n", + " )\n", + "\n", + " from pymc_extras.model.marginal.marginal_model import (\n", + " _unique,\n", + " collect_shared_vars,\n", + " remove_model_vars,\n", + " )\n", + "\n", + " from pymc_extras.model.marginal.distributions import (\n", + " MarginalLaplaceRV,\n", + " )\n", + "\n", + " from pymc.pytensorf import collect_default_updates\n", + "\n", + " from pytensor.graph import (\n", + " FunctionGraph,\n", + " Variable,\n", + " clone_replace,\n", + " )\n", + "\n", + " fg, memo = fgraph_from_model(model)\n", + " rvs_to_marginalize = [memo[rv] for rv in rvs_to_marginalize]\n", + " toposort = fg.toposort()\n", + "\n", + " for rv_to_marginalize in sorted(\n", + " rvs_to_marginalize,\n", + " key=lambda rv: toposort.index(rv.owner),\n", + " reverse=True,\n", + " ):\n", + " all_rvs = [node.out for node in fg.toposort() if isinstance(node.op, ModelValuedVar)]\n", + "\n", + " dependent_rvs = find_conditional_dependent_rvs(rv_to_marginalize, all_rvs)\n", + " if not dependent_rvs:\n", + " # TODO: This should at most be a warning, not an error\n", + " raise ValueError(f\"No RVs depend on marginalized RV {rv_to_marginalize}\")\n", + "\n", + " # Issue warning for IntervalTransform on dependent RVs\n", + " for dependent_rv in dependent_rvs:\n", + " transform = dependent_rv.owner.op.transform\n", + "\n", + " # if isinstance(transform, IntervalTransform) or (\n", + " # isinstance(transform, Chain)\n", + " # and any(isinstance(tr, IntervalTransform) for tr in transform.transform_list)\n", + " # ):\n", + " # warnings.warn(\n", + " # f\"The transform {transform} for the variable {dependent_rv}, which depends on the \"\n", + " # f\"marginalized {rv_to_marginalize} may no longer work if bounds depended on other variables.\",\n", + " # UserWarning,\n", + " # )\n", + "\n", + " # Check that no deterministics or potentials depend on the rv to marginalize\n", + " for det in model.deterministics:\n", + " if is_conditional_dependent(memo[det], rv_to_marginalize, all_rvs):\n", + " raise NotImplementedError(\n", + " f\"Cannot marginalize {rv_to_marginalize} due to dependent Deterministic {det}\"\n", + " )\n", + " for pot in model.potentials:\n", + " if is_conditional_dependent(memo[pot], rv_to_marginalize, all_rvs):\n", + " raise NotImplementedError(\n", + " f\"Cannot marginalize {rv_to_marginalize} due to dependent Potential {pot}\"\n", + " )\n", + "\n", + " marginalized_rv_input_rvs = find_conditional_input_rvs([rv_to_marginalize], all_rvs)\n", + " other_direct_rv_ancestors = [\n", + " rv\n", + " for rv in find_conditional_input_rvs(dependent_rvs, all_rvs)\n", + " if rv is not rv_to_marginalize\n", + " ]\n", + " input_rvs = _unique((*marginalized_rv_input_rvs, *other_direct_rv_ancestors))\n", + "\n", + " output_rvs = [rv_to_marginalize, *dependent_rvs]\n", + " rng_updates = collect_default_updates(output_rvs, inputs=input_rvs, must_be_shared=False)\n", + " outputs = output_rvs + list(rng_updates.values())\n", + " inputs = input_rvs + list(rng_updates.keys())\n", + " # Add any other shared variable inputs\n", + " inputs += collect_shared_vars(output_rvs, blockers=inputs)\n", + "\n", + " inner_inputs = [inp.clone() for inp in inputs]\n", + " inner_outputs = clone_replace(outputs, replace=dict(zip(inputs, inner_inputs)))\n", + " inner_outputs = remove_model_vars(inner_outputs)\n", + "\n", + " marginalize_constructor = MarginalLaplaceRV\n", + "\n", + " _, _, *dims = rv_to_marginalize.owner.inputs\n", + " marginalization_op = marginalize_constructor(\n", + " inputs=inner_inputs,\n", + " outputs=inner_outputs,\n", + " dims_connections=[\n", + " (None,),\n", + " ], # dependent_rvs_dim_connections, # TODO NOT SURE WHAT THIS IS\n", + " dims=dims,\n", + " Q=Q,\n", + " temp_kwargs=temp_kwargs,\n", + " minimizer_kwargs=minimizer_kwargs,\n", + " )\n", + "\n", + " new_outputs = marginalization_op(*inputs)\n", + " for old_output, new_output in zip(outputs, new_outputs):\n", + " new_output.name = old_output.name\n", + "\n", + " model_replacements = []\n", + " for old_output, new_output in zip(outputs, new_outputs):\n", + " if old_output is rv_to_marginalize or not isinstance(\n", + " old_output.owner.op, ModelValuedVar\n", + " ):\n", + " # Replace the marginalized ModelFreeRV (or non model-variables) themselves\n", + " var_to_replace = old_output\n", + " else:\n", + " # Replace the underlying RV, keeping the same value, transform and dims\n", + " var_to_replace = old_output.owner.inputs[0]\n", + " model_replacements.append((var_to_replace, new_output))\n", + "\n", + " fg.replace_all(model_replacements)\n", + "\n", + " return model_from_fgraph(fg, mutate_fgraph=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "47d6057b-b459-43ee-afdb-32e63cee5e62", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster3\n", + "\n", + "3\n", + "\n", + "\n", + "cluster10000 x 3\n", + "\n", + "10000 x 3\n", + "\n", + "\n", + "\n", + "mu_param\n", + "\n", + "mu_param\n", + "~\n", + "Multivariate_normal\n", + "\n", + "\n", + "\n", + "x\n", + "\n", + "x\n", + "~\n", + "Multivariate_normal\n", + "\n", + "\n", + "\n", + "mu_param->x\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "y\n", + "\n", + "y\n", + "~\n", + "Multivariate_normal\n", + "\n", + "\n", + "\n", + "x->y\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rng = np.random.default_rng(12345)\n", + "n = 10000\n", + "d = 3\n", + "\n", + "mu_mu = np.zeros((d,))\n", + "mu_true = np.ones((d,))\n", + "\n", + "cov = np.diag(np.ones(d))\n", + "Q_val = np.diag(np.ones(d))\n", + "cov_true = np.diag(np.ones(d))\n", + "\n", + "with pm.Model() as model:\n", + " x_mu = pm.MvNormal(\"mu_param\", mu=mu_mu, cov=cov)\n", + "\n", + " x = pm.MvNormal(\"x\", mu=x_mu, tau=Q_val)\n", + "\n", + " y_obs = rng.multivariate_normal(mean=mu_true, cov=cov_true, size=n)\n", + "\n", + " y = pm.MvNormal(\n", + " \"y\",\n", + " mu=x,\n", + " cov=cov,\n", + " observed=y_obs,\n", + " )\n", + "\n", + "pm.model_to_graphviz(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "93dbf1e3-0242-4da8-aa2f-62c5541f14cc", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster10000 x 3\n", + "\n", + "10000 x 3\n", + "\n", + "\n", + "cluster3\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "y\n", + "\n", + "y\n", + "~\n", + "MarginalLaplace\n", + "\n", + "\n", + "\n", + "mu_param\n", + "\n", + "mu_param\n", + "~\n", + "Multivariate_normal\n", + "\n", + "\n", + "\n", + "mu_param->y\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_marg = marginalize(\n", + " model,\n", + " [x],\n", + " Q=Q_val,\n", + " temp_kwargs=None,\n", + " minimizer_kwargs={\"method\": \"L-BFGS-B\", \"optimizer_kwargs\": {\"tol\": 1e-8}},\n", + ")\n", + "pm.model_to_graphviz(model_marg, var_names=[\"y\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "41d721e1-fdd4-4d58-95b7-bc978c468ef0", + "metadata": {}, + "outputs": [], + "source": [ + "rng = np.random.default_rng(12345)\n", + "mu = rng.random(d)\n", + "\n", + "f_logp = model_marg.compile_logp(profile=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "41b19afc-dc41-4e6a-908f-41f9fd06f188", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9.58 ms ± 428 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "f_logp({\"mu_param\": mu})" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "8440ca77-e7c8-40ba-a106-40fef8b87d34", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Function profiling\n", + "==================\n", + " Message: /home/michaln/git/pymc/pymc/pytensorf.py:942\n", + " Time in 811 calls to Function.__call__: 7.819569e+00s\n", + " Time in Function.vm.__call__: 7.7988263611114235s (99.735%)\n", + " Time in thunks: 7.780319690704346s (99.498%)\n", + " Total compilation time: 6.888381e-01s\n", + " Number of Apply nodes: 29\n", + " PyTensor rewrite time: 3.427114e-01s\n", + " PyTensor validate time: 5.761475e-03s\n", + " PyTensor Linker time (includes C, CUDA code generation/compiling): 0.3434671189970686s\n", + " C-cache preloading 5.671625e-03s\n", + " Import time 0.000000e+00s\n", + " Node make_thunk time 3.368705e-01s\n", + " Node MinimizeOp(method=L-BFGS-B, jac=True, hess=False, hessp=False)([0.2273360 ... .79736546], True, [0.], [[2]], [[[1. 0. 0 ... . 0. 1.]]], [0.5], True, 0.0, [[2]], ExpandDims{axis=0}.0, [[[1. 0. 0 ... . 0. 1.]]]) time 2.206649e-01s\n", + " Node Scan{scan_fn, while_loop=False, inplace=none}(3, [0 1 2], 3, Neg.0, Neg.0) time 1.019020e-01s\n", + " Node Squeeze{axis=0}(CAReduce{Composite{(i0 + sqr(i1))}, axis=1}.0) time 1.282859e-03s\n", + " Node ExpandDims{axis=1}(mu_param) time 1.102447e-03s\n", + " Node ExpandDims{axis=0}(mu_param) time 1.032342e-03s\n", + "\n", + "Time in all call to pytensor.grad() 7.087498e-01s\n", + "Time since pytensor import 120.663s\n", + "Class\n", + "---\n", + "<% time>