1classdef MultivariateNormal < ContinuousDistribution
2 % MultivariateNormal Multivariate Normal (Gaussian) Distribution
4 % Represents a d-dimensional normal distribution with mean vector mu and
5 % covariance matrix Sigma. The distribution can be used standalone or
6 % within a Prior
for mixture models.
9 % mvn = MultivariateNormal(mu, Sigma)
12 % mu - d-dimensional mean vector (column vector)
13 % Sigma - d x d positive definite covariance matrix
16 % % Create 2D normal distribution
18 % Sigma = [1, 0.5; 0.5, 1];
19 % mvn = MultivariateNormal(mu, Sigma);
22 % samples = mvn.sample(100); % 100 x 2 matrix
25 % pdf_val = mvn.evalPDF([1; 2]);
28 % norm = mvn.getMarginalUniv(1);
30 % Copyright (c) 2012-2026, Imperial College London
33 dimension; % Dimensionality
37 function self = MultivariateNormal(mu, Sigma)
40 line_error(mfilename,
'mu must be a vector');
42 if ~ismatrix(Sigma) || size(Sigma,1) ~= size(Sigma,2)
43 line_error(mfilename, 'Sigma must be square matrix');
50 % Check dimension consistency
52 line_error(mfilename, 'Sigma dimensions must match mu length');
55 % Check positive definite
58 line_error(mfilename, 'Sigma must be positive definite');
61 % Call superclass constructor
62 self@ContinuousDistribution('MultivariateNormal', 2, [-Inf, Inf]);
64 % Store dimension and parameters
66 self.setParam(1, 'mu', mu);
67 self.setParam(2, 'Sigma', Sigma);
69 % Set mean of first component for Prior compatibility
73 % =================== ACCESSORS ===================
75 function d = getDimension(self)
76 % Get the dimensionality of the distribution
80 function mu = getMeanVector(self)
81 % Get the mean vector (d x 1)
82 mu = self.getParam(1).paramValue;
85 function Sigma = getCovariance(self)
86 % Get the covariance matrix (d x d)
87 Sigma = self.getParam(2).paramValue;
90 function R = getCorrelation(self)
91 % Get the correlation matrix
92 Sigma = self.getCovariance();
95 % R(i,j) = Sigma(i,j) / (sqrt(Sigma(i,i)) * sqrt(Sigma(j,j)))
99 std_i = sqrt(Sigma(i,i));
100 std_j = sqrt(Sigma(j,j));
101 if std_i > eps && std_j > eps
102 R(i,j) = Sigma(i,j) / (std_i * std_j);
104 R(i,j) =
double(i == j);
110 % =================== DISTRIBUTION METHODS ===================
112 function MEAN = getMean(self)
113 % Get the mean of the first component (for Prior compatibility)
114 mu = self.getMeanVector();
118 function VAR = getVar(self)
119 % Get the variance of the first component
120 Sigma = self.getCovariance();
124 function SCV = getSCV(self)
125 % Get squared coefficient of variation (not meaningful for multivariate)
127 line_warning(mfilename, 'SCV not defined for multivariate distributions');
130 function SKEW = getSkewness(self)
131 % Get skewness (multivariate normal
is symmetric)
135 % =================== SAMPLING ===================
137 function X = sample(self, n)
138 % Generate n samples from the multivariate normal distribution
140 % Returns n x d matrix of samples
146 mu = self.getMeanVector();
147 Sigma = self.getCovariance();
150 % Use mvnrnd if available (Statistics Toolbox)
151 if exist('mvnrnd', 'file') == 2
152 X = mvnrnd(mu', Sigma, n);
154 % Manual implementation using Cholesky decomposition
155 % X = mu + L*Z where L = chol(Sigma, 'lower'), Z ~ N(0,I)
156 L = chol(Sigma, 'lower');
162 % =================== PDF EVALUATION ===================
164 function p = evalPDF(self, x)
165 % Evaluate the multivariate normal PDF
168 % x - d x 1 column vector or d x n matrix of points
173 mu = self.getMeanVector();
174 Sigma = self.getCovariance();
177 % Handle both column vector and matrix input
179 x = x(:)'; % Convert to row vector
182 if exist('mvnpdf', 'file') == 2
183 % Use Statistics Toolbox if available
184 p = mvnpdf(x, mu', Sigma);
186 % Manual calculation: f(x) = (2π)^(-d/2) |Σ|^(-1/2) exp(-0.5(x-μ)'Σ^(-1)(x-μ))
190 invSigma = inv(Sigma);
191 detSigma = det(Sigma);
192 normConst = 1 / sqrt((2*pi)^d * detSigma);
196 p(i) = normConst * exp(-0.5 * diff' * invSigma * diff);
201 function Ft = evalCDF(self, t)
202 % CDF
is not well-defined for multivariate distributions
203 line_error(mfilename, 'CDF
is not defined for multivariate distributions');
206 function L = evalLST(self, s)
207 % LST
is not well-defined for multivariate distributions
208 line_error(mfilename, 'LST
is not defined for multivariate distributions');
211 % =================== MARGINAL DISTRIBUTIONS ===================
213 function mvn_marg = getMarginal(self, indices)
214 % Extract a marginal distribution for a subset of dimensions
217 % indices - vector of dimension indices to keep (1-based)
220 % mvn_marg - MultivariateNormal for the marginal
222 mu = self.getMeanVector();
223 Sigma = self.getCovariance();
225 % Extract marginal mean and covariance
226 mu_marg = mu(indices);
227 Sigma_marg = Sigma(indices, indices);
229 % Create new MultivariateNormal for marginal
230 mvn_marg = MultivariateNormal(mu_marg, Sigma_marg);
233 function norm = getMarginalUniv(self, index)
234 % Extract a univariate marginal distribution
237 % index - dimension index (1-based)
240 % norm - 1D MultivariateNormal distribution for that dimension
242 mu = self.getMeanVector();
243 Sigma = self.getCovariance();
245 mean_marg = mu(index);
246 var_marg = Sigma(index, index);
248 norm = MultivariateNormal(mean_marg, var_marg);
251 % =================== SERIALIZATION ===================
253 function s = toString(self)
254 % Convert to
string representation
255 s = sprintf('jline.MultivariateNormal(d=%d)', self.dimension);
260 function mvn = fitMeanAndCovariance(mu, Sigma)
261 % Create a multivariate normal from mean and covariance
265 % Sigma - covariance matrix
268 % mvn - MultivariateNormal distribution
270 mvn = MultivariateNormal(mu, Sigma);