# Path: bambi/families/univariate.py
# class Gaussian(UnivariateFamily):
#     SUPPORTED_LINKS = ["identity", "log", "inverse"]
# 
#     def posterior_predictive(self, model, posterior, linear_predictor, draws, draw_n):
#         "Sample from posterior predictive distribution"
#         mean = self.link.linkinv(linear_predictor)
#         sigma = posterior[model.response.name + "_sigma"].values
# 
#         idxs = np.random.randint(low=0, high=draw_n, size=draws)
#         mean = mean[:, idxs, :]
#         sigma = sigma[:, idxs, np.newaxis]
# 
#         return np.random.normal(mean, sigma)
# 
# class StudentT(UnivariateFamily):
#     SUPPORTED_LINKS = ["identity", "log", "inverse"]
# 
#     def posterior_predictive(self, model, posterior, linear_predictor, draws, draw_n):
#         mean = self.link.linkinv(linear_predictor)
#         sigma = posterior[model.response.name + "_sigma"].values
# 
#         idxs = np.random.randint(low=0, high=draw_n, size=draws)
#         if isinstance(self.likelihood.priors["nu"], (int, float)):
#             nu = self.likelihood.priors["nu"]
#         else:
#             nu = posterior[model.response.name + "_nu"].values[:, idxs, np.newaxis]
# 
#         mean = mean[:, idxs, :]
#         sigma = sigma[:, idxs, np.newaxis]
# 
#         return stats.t.rvs(nu, mean, sigma)
# 
# class VonMises(UnivariateFamily):
#     SUPPORTED_LINKS = ["identity", "tan_2"]
# 
#     def posterior_predictive(self, model, posterior, linear_predictor, draws, draw_n):
#         mean = self.link.linkinv(linear_predictor)
#         kappa = posterior[model.response.name + "_kappa"].values
# 
#         idxs = np.random.randint(low=0, high=draw_n, size=draws)
#         mean = mean[:, idxs, :]
#         kappa = kappa[:, idxs, np.newaxis]
# 
#         return np.random.vonmises(mean, kappa)
# 
# Path: bambi/priors/prior.py
# class Prior:
#     """Abstract specification of a term prior.
# 
#     Parameters
#     ----------
#     name : str
#         Name of prior distribution. Must be the name of a PyMC3 distribution
#         (e.g., ``"Normal"``, ``"Bernoulli"``, etc.)
#     auto_scale: bool
#         Whether to adjust the parameters of the prior or use them as passed. Default to ``True``.
#     scale: num or str
#         How to scale the prior. If a number, must be within 0 and 1. If a string, must be one of
#         ``"narrow"``, ``"medium"``, ``"wide"``, or ``"superwide"``. Only used when the model was
#         created with ``automatic_priors="mle"``.
#     kwargs : dict
#         Optional keywords specifying the parameters of the named distribution.
#     """
# 
#     def __init__(self, name, auto_scale=True, scale=None, **kwargs):
#         self.name = name
#         self.auto_scale = auto_scale
#         self.scale = scale
#         self.args = {}
#         self.update(**kwargs)
# 
#     def update(self, **kwargs):
#         """Update the arguments of the prior with additional arguments.
# 
#         Parameters
#         ----------
#         kwargs : dict
#             Optional keyword arguments to add to prior args.
#         """
#         # The backend expect numpy arrays, so make sure all numeric values are represented as such.
#         kwargs_ = {}
#         for key, val in kwargs.items():
#             if isinstance(val, (int, float)):
#                 val = np.array(val)
#             elif isinstance(val, np.ndarray):
#                 val = val.squeeze()
#             kwargs_[key] = val
#         self.args.update(kwargs_)
# 
#     def __eq__(self, other):
#         if not isinstance(other, type(self)):
#             return False
#         else:
#             return self.__dict__ == other.__dict__
# 
#     def __str__(self):
#         args = ", ".join(
#             [
#                 f"{k}: {np.round_(v, 4)}" if not isinstance(v, type(self)) else f"{k}: {v}"
#                 for k, v in self.args.items()
#             ]
#         )
#         return f"{self.name}({args})"
# 
#     def __repr__(self):
#         return self.__str__()


import numpy as np
from bambi.families.univariate import Gaussian, StudentT, VonMises
from .prior import Prior
        if isinstance(self.model.family, (Gaussian, StudentT)):
            self.response_mean = np.mean(model.response.data)
            self.response_std = np.std(self.model.response.data)
        else:
            self.response_mean = 0
            self.response_std = 1

    def get_intercept_stats(self):
        mu = self.response_mean
        sigma = self.STD * self.response_std

        # Only adjust mu and sigma if there is at least one Normal prior for a common term.
        if self.priors:
            sigmas = np.hstack([prior["sigma"] for prior in self.priors.values()])
            x_mean = np.hstack([self.model.terms[term].data.mean(axis=0) for term in self.priors])
            sigma = (sigma**2 + np.dot(sigmas**2, x_mean**2)) ** 0.5

        return mu, sigma

    def get_slope_sigma(self, x):
        return self.STD * (self.response_std / np.std(x))

    def scale_response(self):
        # Add cases for other families
        priors = self.model.family.likelihood.priors
        if isinstance(self.model.family, (Gaussian, StudentT)):
            if priors["sigma"].auto_scale:
                priors["sigma"] = Prior("HalfStudentT", nu=4, sigma=self.response_std)
        elif isinstance(self.model.family, VonMises):
            if priors["kappa"].auto_scale:

# Path: bambi/families/univariate.py
# class Gaussian(UnivariateFamily):
#     SUPPORTED_LINKS = ["identity", "log", "inverse"]
# 
#     def posterior_predictive(self, model, posterior, linear_predictor, draws, draw_n):
#         "Sample from posterior predictive distribution"
#         mean = self.link.linkinv(linear_predictor)
#         sigma = posterior[model.response.name + "_sigma"].values
# 
#         idxs = np.random.randint(low=0, high=draw_n, size=draws)
#         mean = mean[:, idxs, :]
#         sigma = sigma[:, idxs, np.newaxis]
# 
#         return np.random.normal(mean, sigma)
# 
# class StudentT(UnivariateFamily):
#     SUPPORTED_LINKS = ["identity", "log", "inverse"]
# 
#     def posterior_predictive(self, model, posterior, linear_predictor, draws, draw_n):
#         mean = self.link.linkinv(linear_predictor)
#         sigma = posterior[model.response.name + "_sigma"].values
# 
#         idxs = np.random.randint(low=0, high=draw_n, size=draws)
#         if isinstance(self.likelihood.priors["nu"], (int, float)):
#             nu = self.likelihood.priors["nu"]
#         else:
#             nu = posterior[model.response.name + "_nu"].values[:, idxs, np.newaxis]
# 
#         mean = mean[:, idxs, :]
#         sigma = sigma[:, idxs, np.newaxis]
# 
#         return stats.t.rvs(nu, mean, sigma)
# 
# class VonMises(UnivariateFamily):
#     SUPPORTED_LINKS = ["identity", "tan_2"]
# 
#     def posterior_predictive(self, model, posterior, linear_predictor, draws, draw_n):
#         mean = self.link.linkinv(linear_predictor)
#         kappa = posterior[model.response.name + "_kappa"].values
# 
#         idxs = np.random.randint(low=0, high=draw_n, size=draws)
#         mean = mean[:, idxs, :]
#         kappa = kappa[:, idxs, np.newaxis]
# 
#         return np.random.vonmises(mean, kappa)
# 
# Path: bambi/priors/prior.py
# class Prior:
#     """Abstract specification of a term prior.
# 
#     Parameters
#     ----------
#     name : str
#         Name of prior distribution. Must be the name of a PyMC3 distribution
#         (e.g., ``"Normal"``, ``"Bernoulli"``, etc.)
#     auto_scale: bool
#         Whether to adjust the parameters of the prior or use them as passed. Default to ``True``.
#     scale: num or str
#         How to scale the prior. If a number, must be within 0 and 1. If a string, must be one of
#         ``"narrow"``, ``"medium"``, ``"wide"``, or ``"superwide"``. Only used when the model was
#         created with ``automatic_priors="mle"``.
#     kwargs : dict
#         Optional keywords specifying the parameters of the named distribution.
#     """
# 
#     def __init__(self, name, auto_scale=True, scale=None, **kwargs):
#         self.name = name
#         self.auto_scale = auto_scale
#         self.scale = scale
#         self.args = {}
#         self.update(**kwargs)
# 
#     def update(self, **kwargs):
#         """Update the arguments of the prior with additional arguments.
# 
#         Parameters
#         ----------
#         kwargs : dict
#             Optional keyword arguments to add to prior args.
#         """
#         # The backend expect numpy arrays, so make sure all numeric values are represented as such.
#         kwargs_ = {}
#         for key, val in kwargs.items():
#             if isinstance(val, (int, float)):
#                 val = np.array(val)
#             elif isinstance(val, np.ndarray):
#                 val = val.squeeze()
#             kwargs_[key] = val
#         self.args.update(kwargs_)
# 
#     def __eq__(self, other):
#         if not isinstance(other, type(self)):
#             return False
#         else:
#             return self.__dict__ == other.__dict__
# 
#     def __str__(self):
#         args = ", ".join(
#             [
#                 f"{k}: {np.round_(v, 4)}" if not isinstance(v, type(self)) else f"{k}: {v}"
#                 for k, v in self.args.items()
#             ]
#         )
#         return f"{self.name}({args})"
# 
#     def __repr__(self):
#         return self.__str__()


# Path: bambi/priors/scaler_default.py
import numpy as np
from bambi.families.univariate import Gaussian, StudentT, VonMises
from .prior import Prior

        if isinstance(self.model.family, (Gaussian, StudentT)):
            self.response_mean = np.mean(model.response.data)
            self.response_std = np.std(self.model.response.data)
        else:
            self.response_mean = 0
            self.response_std = 1

    def get_intercept_stats(self):
        mu = self.response_mean
        sigma = self.STD * self.response_std

        # Only adjust mu and sigma if there is at least one Normal prior for a common term.
        if self.priors:
            sigmas = np.hstack([prior["sigma"] for prior in self.priors.values()])
            x_mean = np.hstack([self.model.terms[term].data.mean(axis=0) for term in self.priors])
            sigma = (sigma**2 + np.dot(sigmas**2, x_mean**2)) ** 0.5

        return mu, sigma

    def get_slope_sigma(self, x):
        return self.STD * (self.response_std / np.std(x))

    def scale_response(self):
        # Add cases for other families
        priors = self.model.family.likelihood.priors
        if isinstance(self.model.family, (Gaussian, StudentT)):
            if priors["sigma"].auto_scale:
                priors["sigma"] = Prior("HalfStudentT", nu=4, sigma=self.response_std)
        elif isinstance(self.model.family, VonMises):
            if priors["kappa"].auto_scale:

                priors["kappa"] = Prior("HalfStudentT", nu=4, sigma=self.response_std)