This repository has been archived by the owner on Feb 20, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
mvnpdf.m
134 lines (124 loc) · 3.78 KB
/
mvnpdf.m
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
129
130
131
132
133
134
%% Author: Paul Kienzle <[email protected]>
%% This program is granted to the public domain.
%% -*- texinfo -*-
%% @deftypefn {Function File} {@var{y} =} mvnpdf (@var{x})
%% @deftypefnx{Function File} {@var{y} =} mvnpdf (@var{x}, @var{mu})
%% @deftypefnx{Function File} {@var{y} =} mvnpdf (@var{x}, @var{mu}, @var{sigma})
%% Compute multivariate normal pdf for @var{x} given mean @var{mu} and covariance matrix
%% @var{sigma}. The dimension of @var{x} is @var{d} x @var{p}, @var{mu} is
%% @var{1} x @var{p} and @var{sigma} is @var{p} x @var{p}. The normal pdf is
%% defined as
%%
%% @example
%% @iftex
%% @tex
%% $$ 1/y^2 = (2 pi)^p |\Sigma| \exp \{ (x-\mu)^T \Sigma^{-1} (x-\mu) \} $$
%% @end tex
%% @end iftex
%% @ifnottex
%% 1/@var{y}^2 = (2 pi)^@var{p} |@var{Sigma}| exp @{ (@var{x}-@var{mu})' inv(@var{Sigma})@
%% (@var{x}-@var{mu}) @}
%% @end ifnottex
%% @end example
%%
%% @strong{References}
%%
%% NIST Engineering Statistics Handbook 6.5.4.2
%% http://www.itl.nist.gov/div898/handbook/pmc/section5/pmc542.htm
%%
%% @strong{Algorithm}
%%
%% Using Cholesky factorization on the positive definite covariance matrix:
%%
%% @example
%% @var{r} = chol (@var{sigma});
%% @end example
%%
%% where @var{r}'*@var{r} = @var{sigma}. Being upper triangular, the determinant
%% of @var{r} is trivially the product of the diagonal, and the determinant of
%% @var{sigma} is the square of this:
%%
%% @example
%% @var{det} = prod (diag (@var{r}))^2;
%% @end example
%%
%% The formula asks for the square root of the determinant, so no need to
%% square it.
%%
%% The exponential argument @var{A} = @var{x}' * inv (@var{sigma}) * @var{x}
%%
%% @example
%% @var{A} = @var{x}' * inv (@var{sigma}) * @var{x}
%% = @var{x}' * inv (@var{r}' * @var{r}) * @var{x}
%% = @var{x}' * inv (@var{r}) * inv(@var{r}') * @var{x}
%% @end example
%%
%% Given that inv (@var{r}') == inv(@var{r})', at least in theory if not numerically,
%%
%% @example
%% @var{A} = (@var{x}' / @var{r}) * (@var{x}'/@var{r})' = sumsq (@var{x}'/@var{r})
%% @end example
%%
%% The interface takes the parameters to the multivariate normal in columns rather than
%% rows, so we are actually dealing with the transpose:
%%
%% @example
%% @var{A} = sumsq (@var{x}/r)
%% @end example
%%
%% and the final result is:
%%
%% @example
%% @var{r} = chol (@var{sigma})
%% @var{y} = (2*pi)^(-@var{p}/2) * exp (-sumsq ((@var{x}-@var{mu})/@var{r}, 2)/2) / prod (diag (@var{r}))
%% @end example
%%
%% @seealso{mvncdf, mvnrnd}
%% @end deftypefn
function pdf = mvnpdf (x, mu, sigma)
%% Check input
%mu = 0;
%sigma = 1;
if (~ismatrix (x))
error ('mvnpdf: first input must be a matrix');
end
if (~isvector (mu) && ~isscalar (mu))
error ('mvnpdf: second input must be a real scalar or vector');
end
if (~ismatrix (sigma) || ~issquare (sigma))
error ('mvnpdf: third input must be a square matrix');
end
[ps, ps] = size (sigma);
[d, p] = size (x);
if (p ~= ps)
error ('mvnpdf: dimensions of data and covariance matrix does not match');
end
if (numel (mu) ~= p && numel (mu) ~= 1)
error ('mvnpdf: dimensions of data does not match dimensions of mean value');
end
mu = mu (:).';
if (all (size (mu) == [1, p]))
mu = repmat (mu, [d, 1]);
end
if (nargin < 3)
pdf = (2*pi)^(-p/2) * exp (-sumsq (x-mu, 2)/2);
else
r = chol (sigma);
pdf = (2*pi)^(-p/2) * exp (-sumsq ((x-mu)/r, 2)/2) / prod (diag (r));
end
end
%~demo
%~ mu = [0, 0];
%~ sigma = [1, 0.1; 0.1, 0.5];
%~ [X, Y] = meshgrid (linspace (-3, 3, 25));
%~ XY = [X(:), Y(:)];
%~ Z = mvnpdf (XY, mu, sigma);
%~ mesh (X, Y, reshape (Z, size (X)));
%~ colormap jet
%~test
%~ mu = [1,-1];
%~ sigma = [.9 .4; .4 .3];
%~ x = [ 0.5 -1.2; -0.5 -1.4; 0 -1.5];
%~ p = [ 0.41680003660313; 0.10278162359708; 0.27187267524566 ];
%~ q = mvnpdf (x, mu, sigma);
%~ assert (p, q, 10*eps);