Distributions#
Each mixture family (Variance Gamma, Normal-Inverse Gamma, Normal-Inverse Gaussian, Generalized Hyperbolic) documents four classes from one module: the joint \((X,Y)\) law, the marginal-of-\(X\) law, a scalar (\(d=1\)) convenience wrapper, and the factor-analysis variant.
Univariate Distributions#
Gamma#
Gamma distribution as an exponential family.
Exponential family structure:
- class normix.distributions.gamma.Gamma(alpha, beta)[source]#
Bases:
ExponentialFamilyGamma(\(\alpha\), \(\beta\)) distribution — shape \(\alpha > 0\), rate \(\beta > 0\).
- raw_moment(k)[source]#
Raw moment \(E[X^k] = \Gamma(\alpha+k)/(\Gamma(\alpha)\,\beta^k)\).
Finite for all \(k > -\alpha\).
- raw_moments(ks)[source]#
Vectorised
raw_moment()over ordersks.
- mode()[source]#
Mode \((\alpha - 1)/\beta\) for \(\alpha \ge 1\).
For \(\alpha < 1\) the density diverges at \(x=0\) and the formula returns a non-positive value; we clip to
LOG_EPSso the return value is always a valid positive sample location.- Return type:
- classmethod from_natural(theta)[source]#
Construct from natural parameters θ. Subclasses must override.
- to_gig(*, boundary_eps=0.0)[source]#
Exact embedding into the GIG family.
Gamma(\(\alpha\), \(\beta\)) is the \(b \to 0\) limit of GIG(\(p = \alpha,\; a = 2\beta,\; b\)). With
boundary_eps = 0the embedding storesb = 0exactly; pass a small positive value to stay in the strict interior of GIG’s domain (matters only for downstreamexpectation_paramscalls on the lifted GIG).- Parameters:
boundary_eps (float)
- classmethod from_expectation(eta, *, theta0=None, maxiter=100, tol=1e-12, backend='jax', alpha_min=None, **kwargs)[source]#
Closed-form \(\eta \to \theta\) via Newton on \(\psi(\alpha) - \log\alpha = \eta_1 - \log\eta_2\).
\(\eta = [E[\log X],\; E[X]]\) → \(\alpha\) from digamma inversion, \(\beta = \alpha / \eta_2\).
- Parameters:
backend (str) –
'jax'(default):lax.fori_loopNewton (JIT-compatible).'cpu':scipy.specialdigamma/polygamma (no XLA tracing).alpha_min (float, optional) – Lower bound on the fitted shape \(\alpha\). When set, the digamma-inversion result is clamped to
jnp.maximum(alpha, alpha_min)before \(\beta = \alpha/\eta_2\) is formed, so the projected estimate stays self-consistent. This is the opt-in VG estimand control (theghyp“fix-\(\lambda\)” analogue): it restricts the estimator to a region where the VG marginal likelihood is bounded.None(default) leaves the estimate unconstrained. JIT-safe (no Python branch on traced values).eta (Array)
maxiter (int)
tol (float)
- Return type:
Inverse Gamma#
InverseGamma distribution as an exponential family.
Exponential family structure:
- class normix.distributions.inverse_gamma.InverseGamma(alpha, beta)[source]#
Bases:
ExponentialFamilyInverseGamma(\(\alpha\), \(\beta\)) — shape \(\alpha > 0\), rate \(\beta > 0\).
- raw_moment(k)[source]#
Raw moment \(E[X^k] = \beta^k\,\Gamma(\alpha-k)/\Gamma(\alpha)\).
Finite for \(k < \alpha\).
- raw_moments(ks)[source]#
Vectorised
raw_moment()over ordersks.
- mode()[source]#
Mode \(\beta / (\alpha + 1)\) (closed form, valid for all \(\alpha > 0\)).
- Return type:
- ppf(q)[source]#
Quantile function \(F^{-1}(q) = \beta / \mathrm{gammaincinv}(\alpha, 1-q)\).
Follows from \(F(x) = 1 - P(\alpha, \beta/x) = q\).
- rvs(n, seed=42)[source]#
Sample n observations from \(\mathrm{InvGamma}(\alpha, \beta)\) via JAX PRNG.
Uses the relation: if \(X \sim \mathrm{Gamma}(\alpha, 1/\beta)\) then \(1/X \sim \mathrm{InvGamma}(\alpha, \beta)\).
- classmethod from_natural(theta)[source]#
Construct from natural parameters θ. Subclasses must override.
- Parameters:
theta (Array)
- Return type:
- to_gig(*, boundary_eps=0.0)[source]#
Exact embedding into the GIG family.
InverseGamma(\(\alpha\), \(\beta\)) is the \(a \to 0\) limit of GIG(\(p = -\alpha,\; a,\; b = 2\beta\)). With
boundary_eps = 0the embedding storesa = 0exactly; pass a small positive value to stay in the strict interior of GIG’s domain.- Parameters:
boundary_eps (float)
Inverse Gaussian#
Inverse Gaussian (Wald) distribution as an exponential family.
Exponential family structure:
- class normix.distributions.inverse_gaussian.InverseGaussian(mu, lam)[source]#
Bases:
ExponentialFamilyInverseGaussian(\(\mu\), \(\lambda\)) — mean \(\mu > 0\), shape \(\lambda > 0\).
- log_density_power(alpha)[source]#
Log density-power integral via the exact GIG embedding.
InverseGaussian has a non-constant base measure, \(\log h(x) = -\tfrac{1}{2}\log(2\pi) - \tfrac{3}{2}\log x\), so the constant-base-measure formula in
ExponentialFamilydoes not apply. The distribution is exactly \(\mathrm{GIG}(p=-\tfrac12,\, a=\lambda/\mu^2,\, b=\lambda)\), where \(\log h \equiv 0\) and the \(\log x\) term is promoted to a sufficient statistic — so the density-power integral (and henceentropy(),varentropy(), andrenyi(), which all route through this method) are evaluated on the GIG embedding.
- raw_moments(ks)[source]#
Vectorised
raw_moment()over ordersks.
- mode()[source]#
Mode \(\mu\bigl(\sqrt{1 + 9\mu^2/(4\lambda^2)} - 3\mu/(2\lambda)\bigr)\).
Closed-form maximiser of the IG density on \((0, \infty)\).
- Return type:
- cdf(x)[source]#
CDF of the Inverse Gaussian distribution (log-space stable).
\[F(x) = \Phi(t_1) + \exp\!\bigl(2\lambda/\mu + \log\Phi(-t_2)\bigr)\]where \(t_1 = \sqrt{\lambda/x}\,(x/\mu - 1)\) and \(t_2 = \sqrt{\lambda/x}\,(x/\mu + 1)\). The second term uses
log_ndtrto avoid overflow when \(\lambda/\mu\) is large.
- quantile_table()[source]#
Frozen PINV table for amortised
ppf()/ sampling.The analytical
cdf()does not use this table; hold the return value when evaluating many quantiles at fixed parameters.- Return type:
- ppf(q)[source]#
Quantile function via a PINV table built from
log_prob().Trapezoidal-CDF lookup on \(w = \log x\), seeded at \(\log\)
mode().
- rvs(n, seed=42)[source]#
Sample n observations from \(\mathrm{InvGaussian}(\mu, \lambda)\) via JAX PRNG.
Uses the algorithm from Michael, Schucany & Haas (1976):
\(\nu \sim \mathcal{N}(0,1)\), \(y = \nu^2\)
\(x = \mu + \frac{\mu^2 y}{2\lambda} - \frac{\mu}{2\lambda}\sqrt{4\mu\lambda y + \mu^2 y^2}\)
\(z \sim \mathrm{Uniform}(0,1)\); return \(x\) if \(z \le \mu/(\mu+x)\), else \(\mu^2/x\)
Uses
jnp.wherefor vectorized branching over the full sample array.
- classmethod from_natural(theta)[source]#
Construct from natural parameters θ. Subclasses must override.
- Parameters:
theta (Array)
- Return type:
- to_gig(*, boundary_eps=0.0)[source]#
Exact embedding into the GIG family.
InverseGaussian(\(\mu\), \(\lambda\)) is GIG with \(p = -1/2,\; a = \lambda/\mu^2,\; b = \lambda\). No boundary approximation: the embedding lands strictly inside GIG’s domain.
boundary_epsis accepted for API uniformity with Gamma/InvGamma and ignored.- Parameters:
boundary_eps (float)
Generalized Inverse Gaussian#
Generalized Inverse Gaussian (GIG) distribution as an exponential family.
Exponential family structure:
Special cases:
\(b \to 0,\; p > 0\): GIG → \(\mathrm{Gamma}(p,\; a/2)\)
\(a \to 0,\; p < 0\): GIG → \(\mathrm{InvGamma}(-p,\; b/2)\)
\(p = -1/2\): GIG → InverseGaussian
η→θ rescaling (reduces Fisher condition number):
Solve \(\tilde{\eta} \to \tilde{\theta}\) with symmetric GIG (\(\tilde{a} = \tilde{b}\)), then unscale.
Log-Partition Triad Overrides:
_log_partition_from_theta: JAX, useslog_kv(backend='jax')_grad_log_partition: analytical Bessel ratios (5 \(K_\nu\) calls)_hessian_log_partition: analytical 11-Bessel Hessian in \(\theta\)-space_log_partition_cpu: numpy +log_kv(backend='cpu')_grad_log_partition_cpu: analytical Bessel ratios viascipy.kve_hessian_log_partition_cpu: central FD on_log_partition_cpu
- class normix.distributions.generalized_inverse_gaussian.GeneralizedInverseGaussian(p, a, b)[source]#
Bases:
ExponentialFamilyGeneralized Inverse Gaussian distribution.
Stored: \(p\) (shape, any real), \(a > 0\), \(b > 0\).
- to_gig(*, boundary_eps=0.0)[source]#
Identity embedding into the GIG family.
GIG is already in GIG coordinates, so this returns
self. It exists so that every subordinator family exposes a uniformto_gig()for the shared prior-to-posterior conjugacy map in the EM E-step (see_posterior_gig_params()).boundary_epsis accepted for API uniformity and ignored.- Parameters:
boundary_eps (float)
- Return type:
- static expectation_params_batch(p, a, b, backend='jax')[source]#
Vectorized η for arrays of (p, a, b), each shape (N,). Returns (N, 3) array where columns are [E_log_X, E_inv_X, E_X].
backend=’jax’ : vmap over scalar JAX grad backend=’cpu’ : vectorized scipy.kve (6 C-level array calls)
- raw_moment(k)[source]#
Raw moment \(E[X^k] = (b/a)^{k/2}\,K_{p+k}(\sqrt{ab})/K_p(\sqrt{ab})\).
Requires \(a, b > 0\). For the Gamma / InverseGamma boundary embeddings use those classes’ own
raw_moment()instead.
- raw_moments(ks)[source]#
Vectorised
raw_moment()over ordersks(shared \(K_p\)).
- var()[source]#
\(\mathrm{Var}[X] = E[X^2] - E[X]^2\) via three Bessel evaluations.
Uses the moment formula \(E[X^r] = (b/a)^{r/2}\,K_{p+r}(\sqrt{ab})/K_p(\sqrt{ab})\) rather than the full 11-Bessel Fisher Hessian entry
[2, 2].- Return type:
- mode()[source]#
Interior mode \(\bigl((p-1) + \sqrt{(p-1)^2 + ab}\bigr) / a\).
Closed-form positive critical point of the log-density. For \(p \ge 1\) this is the unique global maximum on \((0,\infty)\); for \(p < 1\) the density diverges at 0 and this returns the interior local maximum.
- Return type:
- cdf(x)[source]#
CDF \(F(x) = P(X \le x)\).
Trapezoidal CDF on a \(w = \log x\) grid built from
log_prob(); seeded at \(\log\)mode(). In the degenerate regimes (\(\sqrt{ab} <\)GIG_DEGEN_THRESHOLD) delegates to the limiting Gamma / InverseGamma CDF for accuracy.JIT-compatible: the degeneracy test uses
jax.lax.cond()(no hostfloat()casts).
- quantile_table()[source]#
Frozen PINV table (non-degenerate regime only).
Degenerate Gamma / InverseGamma limits bypass the table in
cdf()/ppf(); hold this object when evaluating many quantiles at fixed non-degenerate parameters.- Return type:
- rvs(n, seed=42, method='devroye')[source]#
Sample n observations from \(\mathrm{GIG}(p, a, b)\).
- Parameters:
n (int) – Sample size.
seed (int) – Integer seed for JAX PRNG (or
scipyrandom_statefor'scipy').method (str) –
Sampling algorithm:
'devroye'(default) — Transformed density rejection (TDR) on \(\log(x)\), pure JAX, no Bessel functions.'pinv'— Numerical inverse CDF (CPU table build + JAX sampling), no Bessel. Best for large n with fixed parameters.'scipy'—scipy.stats.geninvgauss(CPU, original fallback).
- Return type:
- to_gamma()[source]#
KL projection onto the
Gammafamily.Minimises \(D_{\mathrm{KL}}(\mathrm{GIG}\,\|\,q)\) over \(q \in \mathrm{Gamma}\) by matching the Gamma sufficient statistics under the source GIG: \(E_{q^*}[\log X] = \eta_1,\; E_{q^*}[X] = \eta_3\). Solved via
Gamma.from_expectation().
- to_inverse_gamma()[source]#
KL projection onto the
InverseGammafamily.Matches \(E[-1/X] = -\eta_2,\; E[\log X] = \eta_1\).
- to_inverse_gaussian()[source]#
KL projection onto the
InverseGaussianfamily.Matches \(E[X] = \eta_3,\; E[1/X] = \eta_2\). The closed form \(\lambda = 1/(\eta_2 - 1/\eta_3)\) is well-defined whenever \(\eta_2 > 1/\eta_3\) (Jensen, true for every non-degenerate GIG);
InverseGaussian.from_expectation()clamps near degenerate inputs.
- classmethod from_natural(theta)[source]#
Construct from natural parameters θ. Subclasses must override.
- Parameters:
theta (Array)
- Return type:
- classmethod from_expectation(eta, *, theta0=None, maxiter=500, tol=1e-10, backend='jax', method='newton', verbose=0)[source]#
\(\eta \to \theta\) via \(\eta\)-rescaling + optimization.
Rescaling makes the Fisher matrix symmetric (\(\tilde{a} = \tilde{b}\)), reducing condition number by up to \(10^{30}\) for extreme \(a/b\) ratios.
- Parameters:
theta0 (jax.Array, optional) – Warm-start point (required for JAX solvers; if
None, uses multi-start CPU solver with Gamma/InvGamma/InvGauss seeds).backend (str) –
'jax'(default, JIT-able) or'cpu'(scipy, more robust).method (str) –
'newton','lbfgs', or'bfgs'.eta (Array)
maxiter (int)
tol (float)
verbose (int)
- Return type:
- normix.distributions.generalized_inverse_gaussian.GIG#
alias of
GeneralizedInverseGaussian
Multivariate Distributions#
Multivariate Normal distribution.
Stored: mu (d,), L_Sigma (d×d) lower-triangular Cholesky of \(\Sigma\).
All linear algebra via L_Sigma — never form \(\Sigma^{-1}\) explicitly.
Exponential family structure#
where \(\operatorname{vec}\) uses row-major order (numpy.ndarray.ravel()).
All parametrization conversions are analytical (closed-form):
classical \(\leftrightarrow\) natural:
natural_params/from_naturalnatural \(\to\) expectation:
_grad_log_partition(analytical override)expectation \(\to\) classical:
from_expectation
No Bregman solver is ever invoked. fit_mle computes
\(\hat\eta = n^{-1}\sum_i t(x_i)\) and calls from_expectation
(closed-form). log_prob overrides the inherited EF formula with a
direct Cholesky computation for efficiency.
- class normix.distributions.normal.MultivariateNormal(mu, L_Sigma)[source]#
Bases:
ExponentialFamilyMultivariate Normal distribution as an exponential family.
- Parameters:
Notes
Natural parameters: \(\theta = [\Sigma^{-1}\mu,\; -\tfrac{1}{2}\operatorname{vec}(\Sigma^{-1})]\). Sufficient statistics: \(t(x) = [x,\; \operatorname{vec}(xx^\top)]\). Log-partition: \(\psi(\theta) = \tfrac{1}{2}\mu^\top\Sigma^{-1}\mu - \tfrac{1}{2}\log|\Sigma^{-1}| + \tfrac{d}{2}\log(2\pi)\). Log base measure: \(\log h(x) = 0\).
- natural_params()[source]#
\(\theta = [\Sigma^{-1}\mu,\; -\tfrac{1}{2}\operatorname{vec}(\Sigma^{-1})]\)
- Return type:
- classmethod from_classical(mu, sigma)[source]#
Construct from mean μ and covariance matrix Σ.
- Return type:
- classmethod from_expectation(eta, **_kwargs)[source]#
Closed-form inversion \(\eta \to \theta \to (\mu, L_\Sigma)\).
\(\eta = [E[X],\; \operatorname{vec}(E[XX^\top])]\), so
\[\mu = \eta_1, \qquad \Sigma = \operatorname{reshape}(\eta_2, d, d) - \mu\mu^\top\]- Parameters:
eta (jax.Array) – Expectation parameters of shape
(d + d²,).**_kwargs – Ignored (accepts
backend,theta0, etc. for API compatibility).
- Return type:
- classmethod from_natural(theta)[source]#
Construct from natural parameters \(\theta = [\theta_1, \theta_2]\).
Recovers \(\Lambda = -2\,\mathrm{reshape}(\theta_2, d, d)\), then \(\mu = \Lambda^{-1}\theta_1\) and \(L_\Sigma = \mathrm{chol}(\Lambda^{-1})\).
- Parameters:
theta (Array)
- Return type:
- log_prob(x)[source]#
\(\log f(x) = -\tfrac{d}{2}\log(2\pi) - \tfrac{1}{2}\log|\Sigma| - \tfrac{1}{2}\|L_\Sigma^{-1}(x-\mu)\|^2\).
Overrides the inherited EF formula for numerical efficiency (Cholesky-direct).
Mixture Distributions#
Variance Gamma#
Variance Gamma (VG) distribution.
Special case of GH with GIG → Gamma subordinator (\(b \to 0\), \(p > 0\)). \(Y \sim \mathrm{Gamma}(\alpha, \beta)\), i.e. GIG(\(p = \alpha\), \(a = 2\beta\), \(b \to 0\)).
Stored: \(\mu\), \(\gamma\), \(L_\Sigma\) (Cholesky of \(\Sigma\)), \(\alpha\) (shape), \(\beta\) (rate) of Gamma.
- class normix.distributions.variance_gamma.JointVarianceGamma(mu, gamma, L_Sigma, alpha, beta)[source]#
Bases:
JointNormalMixtureJoint \(f(x,y)\): \(X\mid Y \sim \mathcal{N}(\mu+\gamma y, \Sigma y)\), \(Y \sim \mathrm{Gamma}(\alpha, \beta)\).
GIG limit: \(p = \alpha\), \(a = 2\beta\), \(b \to 0\).
- natural_params()[source]#
\(\theta = [\alpha-1-d/2,\; -\tfrac{1}{2}\mu^\top\Lambda\mu,\; -(\beta+\tfrac{1}{2}\gamma^\top\Lambda\gamma),\; \Lambda\gamma,\; \Lambda\mu,\; -\tfrac{1}{2}\mathrm{vec}(\Lambda)]\)
(Gamma subordinator: \(p=\alpha\), \(a=2\beta\), \(b\to 0\)).
- Return type:
- class normix.distributions.variance_gamma.VarianceGamma(joint)[source]#
Bases:
NormalMixtureMarginal Variance Gamma distribution f(x).
- Parameters:
joint (JointVarianceGamma)
- log_prob(x)[source]#
Marginal VG log-density (own formula, no GH delegation).
\[f(x) \propto \left(\frac{q}{2c}\right)^{\nu/2} K_\nu\!\left(\sqrt{2qc}\right) \exp(\gamma^\top\Sigma^{-1}(x-\mu))\]where \(\nu = \alpha - d/2\), \(c = \beta + \tfrac{1}{2}\gamma^\top\Lambda\gamma\), \(q = (x-\mu)^\top\Lambda(x-\mu)\).
\(q,\,2c\) are floored at
LOG_EPSbefore forming \(\sqrt{2qc}\), matching the floor used in the \((q/2c)^{\nu/2}\) ratio — otherwise \(x=\mu\) sends the true \(q=0\) intolog_kvunfloored while the ratio uses the floored value, breaking the cancellation needed for a finite limit.
- class normix.distributions.variance_gamma.UnivariateVarianceGamma(joint)[source]#
Bases:
_UnivariateNormalMixtureMixin,VarianceGammaUnivariate (d=1) Variance Gamma distribution.
Sibling of
VarianceGammafor 1-D problems: exposes scalarmean/var/std,(n,)-shapedrvs, andcdf/ppfbacked by a PINV table over the marginal log-density. EM,fit,replace, and regularisation are inherited fromVarianceGamma.
- class normix.distributions.variance_gamma.FactorVarianceGamma(mu, gamma, F, D, *, alpha, beta)[source]#
Bases:
FactorNormalMixtureFactor-analysis Variance Gamma: \(Y \sim \mathrm{Gamma}(\alpha, \beta)\), \(\Sigma = F F^\top + \mathrm{diag}(D)\).
GIG limit of the subordinator: \(p = \alpha\), \(a = 2\beta\), \(b \to 0\).
Normal Inverse Gamma#
Normal-Inverse Gamma (NInvG) distribution.
Special case of GH with GIG → InverseGamma subordinator (\(a \to 0\), \(p < 0\)). \(Y \sim \mathrm{InvGamma}(\alpha, \beta)\), i.e. GIG(\(p = -\alpha\), \(a \to 0\), \(b = 2\beta\)).
Stored: \(\mu\), \(\gamma\), \(L_\Sigma\) (Cholesky of \(\Sigma\)), \(\alpha\) (shape), \(\beta\) (rate) of InverseGamma.
- class normix.distributions.normal_inverse_gamma.JointNormalInverseGamma(mu, gamma, L_Sigma, alpha, beta)[source]#
Bases:
JointNormalMixtureJoint \(f(x,y)\): \(X\mid Y \sim \mathcal{N}(\mu+\gamma y, \Sigma y)\), \(Y \sim \mathrm{InvGamma}(\alpha, \beta)\).
GIG limit: \(p = -\alpha\), \(a \to 0\), \(b = 2\beta\).
The \(\gamma y\) mean term is the skewness that generalizes this beyond the textbook Normal-inverse-gamma conjugate prior — see
NormalInverseGammafor its role in the marginal density.- natural_params()[source]#
\(\theta = [-(\alpha+1)-d/2,\; -(\beta+\tfrac{1}{2}\mu^\top\Lambda\mu),\; -\tfrac{1}{2}\gamma^\top\Lambda\gamma,\; \Lambda\gamma,\; \Lambda\mu,\; -\tfrac{1}{2}\mathrm{vec}(\Lambda)]\)
(InverseGamma subordinator: \(p=-\alpha\), \(a\to 0\), \(b=2\beta\)).
- Return type:
- class normix.distributions.normal_inverse_gamma.NormalInverseGamma(joint)[source]#
Bases:
NormalMixtureMarginal Normal-Inverse Gamma distribution \(f(x)\).
Not the textbook Normal-inverse-gamma conjugate prior — that distribution is a pure variance mixture, \(X\mid Y\sim\mathcal N(\mu,\Sigma Y)\), whose marginal is a plain Student-t with no special functions. This class is the GH-family variance-mean mixture (see
JointNormalInverseGamma): \(X\mid Y\sim\mathcal N(\mu+\gamma Y,\Sigma Y)\). The extra \(\gamma Y\) term is whylog_prob()needslog_kv(): expanding the quadratic form adds a term linear in \(Y\), turning the \(\int_0^\infty dY\) integral from a Gamma integral into a Generalized Inverse Gaussian one, \(2(b/a)^{p/2}K_p(\sqrt{ab})\) with \(a=\gamma^\top\Sigma^{-1}\gamma\). At \(\gamma=0\) this reduces exactly to the textbook result \(f(x)=t\big(x\mid\nu=2\alpha,\ \hat\mu=\mu,\ \hat\Sigma=\tfrac{\beta}{\alpha}\Sigma\big)\) — see The Generalized Hyperbolic Distribution “Special Cases”.- Parameters:
joint (JointNormalInverseGamma)
- log_prob(x)[source]#
Marginal NInvG log-density (own formula, no GH delegation).
GIG params: \(p=-\alpha\), \(a=\gamma^\top\Lambda\gamma\), \(b=2\beta+Q(x)\). The normalising integral is \(2(b/a)^{p/2} K_p(\sqrt{ab})\).
\(a,b\) are floored at
LOG_EPSbefore forming \(\sqrt{ab}\), matching the floor used in the \((b/a)^{p/2}\) ratio. Without this, \(\gamma=0\) (the common no-skew case) sends the true \(a=0\) intolog_kvunfloored while the ratio uses the floored value, breaking the cancellation between the two that is needed for a finite limit.
- class normix.distributions.normal_inverse_gamma.UnivariateNormalInverseGamma(joint)[source]#
Bases:
_UnivariateNormalMixtureMixin,NormalInverseGammaUnivariate (d=1) Normal-Inverse-Gamma distribution.
Sibling of
NormalInverseGammafor 1-D problems; seeUnivariateVarianceGammafor the contract.
- class normix.distributions.normal_inverse_gamma.FactorNormalInverseGamma(mu, gamma, F, D, *, alpha, beta)[source]#
Bases:
FactorNormalMixtureFactor-analysis Normal-Inverse-Gamma: \(Y \sim \mathrm{InvGamma}(\alpha, \beta)\), \(\Sigma = F F^\top + \mathrm{diag}(D)\).
GIG limit: \(p = -\alpha\), \(a \to 0\), \(b = 2\beta\).
Normal Inverse Gaussian#
Normal-Inverse Gaussian (NIG) distribution.
Special case of GH with GIG → InverseGaussian subordinator (\(p = -1/2\)). \(Y \sim \mathrm{InvGaussian}(\mu_{IG}, \lambda)\), i.e. GIG(\(p = -1/2\), \(a = \lambda/\mu_{IG}^2\), \(b = \lambda\)).
Stored: \(\mu\), \(\gamma\), \(L_\Sigma\) (Cholesky of \(\Sigma\)), \(\mu_{IG}\) (IG mean), \(\lambda\) (IG shape).
- class normix.distributions.normal_inverse_gaussian.JointNormalInverseGaussian(mu, gamma, L_Sigma, mu_ig, lam)[source]#
Bases:
JointNormalMixtureJoint \(f(x,y)\): \(X\mid Y \sim \mathcal{N}(\mu+\gamma y, \Sigma y)\), \(Y \sim \mathrm{InvGaussian}(\mu_{IG}, \lambda)\).
Stored: \(\mu_{IG}\) (IG mean) and \(\lambda\) (IG shape) directly. GIG params: \(p = -1/2\), \(a = \lambda/\mu_{IG}^2\), \(b = \lambda\).
- natural_params()[source]#
\(\theta = [-3/2-d/2,\; -(\lambda/2+\tfrac{1}{2}\mu^\top\Lambda\mu),\; -(\lambda/(2\mu_{IG}^2)+\tfrac{1}{2}\gamma^\top\Lambda\gamma),\; \Lambda\gamma,\; \Lambda\mu,\; -\tfrac{1}{2}\mathrm{vec}(\Lambda)]\)
where \(p=-1/2\), \(a=\lambda/\mu_{IG}^2\), \(b=\lambda\), aligned with GIG natural parameters on \([\log y,\,1/y,\,y]\).
- Return type:
- classmethod from_natural(theta)[source]#
Recover classical parameters from \(\theta\).
From \(b = -2\theta_2 - 2\mu_{\mathrm{quad}} = \lambda\) and \(a = -2\theta_3 - 2\gamma_{\mathrm{quad}} = \lambda/\mu_{IG}^2\), so \(\mu_{IG} = \sqrt{b/a}\).
- Parameters:
theta (Array)
- Return type:
- log_density_power(alpha)[source]#
Log density-power integral via the exact
JointGeneralizedHyperbolicembedding.Unlike the VG / NInvG joints (whose shape \(p\) is a free coordinate read back from \(\theta_1\)), this class fixes \(p=-1/2\) and drops \(\theta_1\) from
_log_partition_from_theta()(using \(K_{-1/2}\)). The density-power scaling \(\theta\mapsto\alpha\theta\) moves \(\theta_1\) (i.e. the GIG order) off \(-1/2\), so the constant-base-measure formula inExponentialFamilymust be evaluated on the GH embedding, where \(p\) is carried faithfully throughlog_kv. This drivesentropy(),varentropy(), andrenyi().
- class normix.distributions.normal_inverse_gaussian.NormalInverseGaussian(joint)[source]#
Bases:
NormalMixtureMarginal Normal-Inverse Gaussian distribution f(x).
- Parameters:
joint (JointNormalInverseGaussian)
- log_prob(x)[source]#
Marginal NIG log-density.
Uses \(K_{-1/2}(z) = \sqrt{\pi/(2z)}\,e^{-z}\) for the normalisation, leaving only one \(\log K_\nu\) call at order \(\nu = -1/2 - d/2\).
- class normix.distributions.normal_inverse_gaussian.UnivariateNormalInverseGaussian(joint)[source]#
Bases:
_UnivariateNormalMixtureMixin,NormalInverseGaussianUnivariate (d=1) Normal-Inverse-Gaussian distribution.
Sibling of
NormalInverseGaussianfor 1-D problems; seeUnivariateVarianceGammafor the contract.
- class normix.distributions.normal_inverse_gaussian.FactorNormalInverseGaussian(mu, gamma, F, D, *, mu_ig, lam)[source]#
Bases:
FactorNormalMixtureFactor-analysis Normal-Inverse-Gaussian: \(Y \sim \mathrm{InvGaussian}(\mu_{IG}, \lambda)\), \(\Sigma = F F^\top + \mathrm{diag}(D)\).
GIG params: \(p = -1/2\), \(a = \lambda/\mu_{IG}^2\), \(b = \lambda\).
Generalized Hyperbolic#
Generalized Hyperbolic (GH) distribution.
Joint: \(X \mid Y \sim \mathcal{N}(\mu + \gamma y, \Sigma y)\), \(Y \sim \mathrm{GIG}(p, a, b)\).
Marginal: \(\mathrm{GH}(\mu, \gamma, \Sigma, p, a, b)\).
Marginal log-density (closed form via Bessel functions):
Let \(Q(x) = (x-\mu)^\top \Sigma^{-1}(x-\mu)\), \(A = a + \gamma^\top \Sigma^{-1} \gamma\).
Posterior: \(Y \mid X = x \sim \mathrm{GIG}(p - d/2,\; a + \gamma^\top\Sigma^{-1}\gamma,\; b + (x-\mu)^\top\Sigma^{-1}(x-\mu))\).
- class normix.distributions.generalized_hyperbolic.JointGeneralizedHyperbolic(mu, gamma, L_Sigma, p, a, b)[source]#
Bases:
JointNormalMixtureJoint \(f(x,y)\): \(X\mid Y \sim \mathcal{N}(\mu+\gamma y, \Sigma y)\), \(Y \sim \mathrm{GIG}(p, a, b)\).
Stored:
mu,gamma,L_Sigma(fromJointNormalMixture) +p,a,b(GIG parameters).- to_joint_generalized_hyperbolic(*, boundary_eps=0.0)[source]#
Identity: JointGH is already the divergence gauge.
- Parameters:
boundary_eps (float)
- natural_params()[source]#
\(\theta = [p-1-d/2,\; -(b/2+\tfrac{1}{2}\mu^\top\Sigma^{-1}\mu),\; -(a/2+\tfrac{1}{2}\gamma^\top\Sigma^{-1}\gamma),\; \Sigma^{-1}\gamma,\; \Sigma^{-1}\mu,\; -\tfrac{1}{2}\mathrm{vec}(\Sigma^{-1})]\)
The scalar coefficients on sufficient statistics \(1/y\) and \(y\) match the GIG convention \(\theta_{\mathrm{GIG}} = [p-1,\,-b/2,\,-a/2]\) on \(t_Y = [\log y,\,1/y,\,y]\).
- Return type:
- classmethod from_classical(*, mu, gamma, sigma, p, a, b)[source]#
Construct from classical parameters.
- classmethod from_natural(theta)[source]#
Recover classical parameters from \(\theta\).
\(p = \theta_1 + 1 + d/2\), \(b = -2\theta_2 - 2\mu_{\mathrm{quad}}\), \(a = -2\theta_3 - 2\gamma_{\mathrm{quad}}\).
- Parameters:
theta (Array)
- Return type:
- to_joint_variance_gamma()[source]#
KL projection onto
JointVarianceGamma(Gamma subordinator).- Return type:
- class normix.distributions.generalized_hyperbolic.GeneralizedHyperbolic(joint)[source]#
Bases:
NormalMixtureMarginal Generalized Hyperbolic distribution \(f(x)\).
Stores a
JointGeneralizedHyperbolic. Provides:log_prob(x)— closed-form Bessel expressione_step,m_step— for EM fittingfit(X, ...)— convenience fitting method
- Parameters:
joint (JointGeneralizedHyperbolic)
- log_prob(x)[source]#
Marginal \(\log f(x)\).
\[f(x) \propto \left(\frac{A}{Q(x)+b}\right)^{(d/2-p)/2} K_{p-d/2}\!\left(\sqrt{A(Q(x)+b)}\right) \exp\!\left(\gamma^\top\Sigma^{-1}(x-\mu)\right)\]where \(Q(x) = (x-\mu)^\top\Sigma^{-1}(x-\mu)\), \(A = a + \gamma^\top\Sigma^{-1}\gamma\).
- m_step(eta, **kwargs)[source]#
Full M-step with warm-started + sanity-checked subordinator solve.
Overrides the base
cls.from_expectation(eta)because the GIG solver benefits substantially from warm-starting at the current \(\theta\) and from a fall-back when the solver wanders into unsane regions; both are managed bym_step_subordinator().- Return type:
- m_step_subordinator(eta, **kwargs)[source]#
M-step for the subordinator only (MCECM Cycle 2).
Reads the subordinator-relevant fields of
eta; normal parameters are read fromself._jointand copied unchanged. Subclasses with iterative solvers may override to add warm-start or sanity-check fallbacks.- Return type:
- regularize_a_eq_b()[source]#
Rescale so \(a = b = \sqrt{ab}\) (orbit invariant).
Picks \(s = \sqrt{a/b}\). Idempotent: applying twice leaves the model unchanged.
- Return type:
- to_normal_inverse_gaussian()[source]#
KL projection onto the
NormalInverseGaussianfamily.- Return type:
- classmethod default_init(X)[source]#
Warm-start from the best of NIG / VG / NInvG sub-model fits.
Runs 5 EM iterations (JAX backend, Newton method) for each special case, converts each to GH parametrisation, and selects the candidate with the highest marginal log-likelihood. A moment-based fallback (\(p=1, a=1, b=1\)) is included as a fourth candidate.
Fully JAX-native: no try/except, no Python branching on data values.
- Parameters:
X (Array)
- Return type:
- class normix.distributions.generalized_hyperbolic.UnivariateGeneralizedHyperbolic(joint)[source]#
Bases:
_UnivariateNormalMixtureMixin,GeneralizedHyperbolicUnivariate (d=1) Generalized Hyperbolic distribution.
Sibling of
GeneralizedHyperbolicfor 1-D problems; seeUnivariateVarianceGammafor the contract.
- class normix.distributions.generalized_hyperbolic.FactorGeneralizedHyperbolic(mu, gamma, F, D, *, p, a, b)[source]#
Bases:
FactorNormalMixtureFactor-analysis Generalized Hyperbolic: \(Y \sim \mathrm{GIG}(p, a, b)\), \(\Sigma = F F^\top + \mathrm{diag}(D)\).
The GIG subordinator’s M-step uses warm-started numerical optimisation with the same sanity-check fall-back as the standard
GeneralizedHyperbolic.- m_step(eta, **kwargs)[source]#
Full M-step with warm-started, sanity-checked GIG solve.
Mirrors
GeneralizedHyperbolic.m_step(): do the closed-form factor M-step first, then run the subordinator update with warm-start and fall-back.- Return type:
- m_step_subordinator(eta, **kwargs)[source]#
M-step for the subordinator only (MCECM cycle 2).
Reads the subordinator-relevant fields of
eta; \((\mu, \gamma, F, D)\) are read fromselfand copied unchanged. Subclasses with iterative solvers may override to add a warm-start or sanity-check fallback.- Return type:
- regularize_a_eq_b()[source]#
Rescale so \(a = b = \sqrt{ab}\) (orbit invariant).
Mirrors
GeneralizedHyperbolic.regularize_a_eq_b(). Picks \(s = \sqrt{a/b}\).- Return type:
- classmethod default_init(X, *, r=1)[source]#
Warm-start from the best of FactorNIG / FactorVG / FactorNInvG fits.
Mirrors
GeneralizedHyperbolic.default_init(): runs a few EM iterations of each special-case factor family, converts each subordinator to the GIG embedding, and selects the candidate with the highest marginal log-likelihood. A moment-based fallback (\(p = 1, a = 1, b = 1\)) is included as a fourth candidate.Fully JAX-native: no try/except, no Python branching on data values.
- Parameters:
- Return type: