Files
2026-07-13 13:30:25 +08:00

101 lines
2.4 KiB
Python
Executable File

import numpy as np
from prml.rv.rv import RandomVariable
class MultivariateGaussian(RandomVariable):
"""
The multivariate Gaussian distribution
p(x|mu, cov)
= exp{-0.5 * (x - mu)^T @ cov^-1 @ (x - mu)}
/ (2pi)^(D/2) / |cov|^0.5
"""
def __init__(self, mu=None, cov=None, tau=None):
super().__init__()
self.mu = mu
if cov is not None:
self.cov = cov
elif tau is not None:
self.tau = tau
else:
self.cov = None
self.tau = None
@property
def mu(self):
return self.parameter["mu"]
@mu.setter
def mu(self, mu):
if isinstance(mu, np.ndarray):
assert mu.ndim == 1
self.parameter["mu"] = mu
else:
assert mu is None
self.parameter["mu"] = None
@property
def cov(self):
return self.parameter["cov"]
@cov.setter
def cov(self, cov):
if isinstance(cov, np.ndarray):
assert cov.ndim == 2
self.tau_ = np.linalg.inv(cov)
self.parameter["cov"] = cov
else:
assert cov is None
self.tau_ = None
self.parameter["cov"] = None
@property
def tau(self):
return self.tau_
@tau.setter
def tau(self, tau):
if isinstance(tau, np.ndarray):
assert tau.ndim == 2
self.parameter["cov"] = np.linalg.inv(tau)
self.tau_ = tau
else:
assert tau is None
self.tau_ = None
self.parameter["cov"] = None
@property
def ndim(self):
if hasattr(self.mu, "ndim"):
return self.mu.ndim
else:
return None
@property
def size(self):
if hasattr(self.mu, "size"):
return self.mu.size
else:
return None
@property
def shape(self):
if hasattr(self.mu, "shape"):
return self.mu.shape
else:
return None
def _fit(self, X):
self.mu = np.mean(X, axis=0)
self.cov = np.atleast_2d(np.cov(X.T, bias=True))
def _pdf(self, X):
d = X - self.mu
return (
np.exp(-0.5 * np.sum(d @ self.tau * d, axis=-1))
* np.sqrt(np.linalg.det(self.tau))
/ np.power(2 * np.pi, 0.5 * self.size))
def _draw(self, sample_size=1):
return np.random.multivariate_normal(self.mu, self.cov, sample_size)