-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmvnpdf_fast.asv
128 lines (117 loc) · 4.77 KB
/
mvnpdf_fast.asv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
function y = mvnpdf_fast(X, Mu, Sigma)
%MVNPDF Multivariate normal probability density function (pdf).
% Y = MVNPDF(X) returns the probability density of the multivariate normal
% distribution with zero mean and identity covariance matrix, evaluated at
% each row of X. Rows of the N-by-D matrix X correspond to observations or
% points, and columns correspond to variables or coordinates. Y is an
% N-by-1 vector.
%
% Y = MVNPDF(X,MU) returns the density of the multivariate normal
% distribution with mean MU and identity covariance matrix, evaluated
% at each row of X. MU is a 1-by-D vector, or an N-by-D matrix, in which
% case the density is evaluated for each row of X with the corresponding
% row of MU. MU can also be a scalar value, which MVNPDF replicates to
% match the size of X.
%
% Y = MVNPDF(X,MU,SIGMA) returns the density of the multivariate normal
% distribution with mean MU and covariance SIGMA, evaluated at each row
% of X. SIGMA is a D-by-D matrix, or an D-by-D-by-N array, in which case
% the density is evaluated for each row of X with the corresponding page
% of SIGMA, i.e., MVNPDF computes Y(I) using X(I,:) and SIGMA(:,:,I).
% If the covariance matrix is diagonal, containing variances along the
% diagonal and zero covariances off the diagonal, SIGMA may also be
% specified as a 1-by-D matrix or a 1-by-D-by-N array, containing
% just the diagonal. Pass in the empty matrix for MU to use its default
% value when you want to only specify SIGMA.
%
% If X is a 1-by-D vector, MVNPDF replicates it to match the leading
% dimension of MU or the trailing dimension of SIGMA.
%
% Example:
%
% mu = [1 -1]; Sigma = [.9 .4; .4 .3];
% [X1,X2] = meshgrid(linspace(-1,3,25)', linspace(-3,1,25)');
% X = [X1(:) X2(:)];
% p = mvnpdf(X, mu, Sigma);
% surf(X1,X2,reshape(p,25,25));
%
% See also MVTPDF, MVNCDF, MVNRND, NORMPDF.
% Copyright 1993-2020 The MathWorks, Inc.
% Get size of data. Column vectors provisionally interpreted as multiple scalar data.
[n,d] = size(X);
% Single covariance matrix
sz = size(Sigma);
sz(1) = sz(2);
%Check that sigma is the right size
R = sqrt(Sigma);
xRinv = X0./R;
logSqrtDetSigma = sum(log(R));
else
% Make sure Sigma is a valid covariance matrix
[R,err] = cholcov(Sigma,0);
if err ~= 0
error(message('stats:mvnpdf:BadMatrixSigma'));
end
% Create array of standardized data, and compute log(sqrt(det(Sigma)))
xRinv = X0 / R;
logSqrtDetSigma = sum(log(diag(R)));
end
end
% Multiple covariance matrices
elseif ndims(Sigma) == 3
sz = size(Sigma);
if sz(1)==1 && sz(2)>1
% Just the diagonal of Sigma has been passed in.
sz(1) = sz(2);
Sigma = reshape(Sigma,sz(2),sz(3))';
sigmaIsDiag = true;
else
sigmaIsDiag = false;
end
% Special case: if Sigma is supplied, then use it to try to interpret
% X and Mu as row vectors if they were both column vectors.
if (d == 1) && (numel(X) > 1) && (sz(1) == n)
X0 = X0';
[n,d] = size(X0);
end
% Data and mean are a single row, rep them out to match covariance
if n == 1 % already know size(Sigma,3) > 1
n = sz(3);
X0 = repmat(X0,n,1); % rep centered data out to match cov
end
% Make sure Sigma is the right size
if sz(1) ~= sz(2)
error(message('stats:mvnpdf:BadCovarianceMultiple'));
elseif (sz(1) ~= d) || (sz(2) ~= d) % Sigma is a stack of dxd matrices
error(message('stats:mvnpdf:CovSizeMismatchMultiple'));
elseif sz(3) ~= n
error(message('stats:mvnpdf:CovSizeMismatchPages'));
else
if sigmaIsDiag
if any(any(Sigma<=0))
error(message('stats:mvnpdf:BadDiagSigma'));
end
R = sqrt(Sigma);
xRinv = X0./R;
logSqrtDetSigma = sum(log(R),2);
else
% Create array of standardized data, and vector of log(sqrt(det(Sigma)))
xRinv = zeros(n,d,'like',internal.stats.dominantType(X0,Sigma));
logSqrtDetSigma = zeros(n,1,'like',Sigma);
for i = 1:n
% Make sure Sigma is a valid covariance matrix
[R,err] = cholcov(Sigma(:,:,i),0);
if err ~= 0
error(message('stats:mvnpdf:BadMatrixSigmaMultiple'));
end
xRinv(i,:) = X0(i,:) / R;
logSqrtDetSigma(i) = sum(log(diag(R)));
end
end
end
elseif ndims(Sigma) > 3
error(message('stats:mvnpdf:BadCovariance'));
end
% The quadratic form is the inner products of the standardized data
quadform = sum(xRinv.^2, 2);
y = exp(-0.5*quadform - logSqrtDetSigma - d*log(2*pi)/2);