function s = mvnrnd(mu,Sigma,K)
% function s = mvnrnd( mu,Sigma)
%         nxd         nxd  dxd
% Draw n random d-dimensional vectors from a multivariate Gaussian distribution
% with mean mu and covariance matrix Sigma.

% Iain Murray 2003 -- I got sick of this simple thing not being in Octave and
%                     locking up a stats-toolbox license in Matlab for no good
%                     reason.

% If mu is column vector and Sigma not a scalar then assume user didn't read
% help but let them off and flip mu. Don't be more liberal than this or it will
% encourage errors (eg what should you do if mu is square?).
if ((size(mu,2)==1) && (length(Sigma)~=1))
	mu=mu';
end

% May 2004 take a third arg, cases. Makes it more compatible with Matlab's.
if nargin==3
	mu=repmat(mu,K,1);
end

[n,d]=size(mu);

if (size(Sigma,1)~=d && size(Sigma,2)~=d)
	error('Sigma must have dimensions dxd where mu is nxd.');
end

try
	U=chol(Sigma);
catch
	[E,Lambda]=eig(Sigma);
	if (min(diag(Lambda))<0),error('Sigma must be positive semi-definite.'),end
	U = sqrt(Lambda)*E';
end

s = randn(n,d)*U + mu;

% {{{ END OF CODE --- Guess I should provide an explanation:
% 
% We can draw from axis aligned unit Gaussians with randn(d)
% 	x ~ A*exp(-0.5*x'*x)
% We can then rotate this distribution using
% 	y = U'*x
% Note that
% 	x = inv(U')*y
% Our new variable y is distributed according to:
% 	y ~ B*exp(-0.5*y'*inv(U'*U)*y)
% or
% 	y ~ N(0,Sigma)
% where
% 	Sigma = U'*U
% For a given Sigma we can use the chol function to find the corresponding U,
% draw x and find y. We can adjust for a non-zero mean by just adding it on.
% 
% But the Cholsky decomposition function doesn't always work...
% Consider Sigma=[1 1;1 1]. Now inv(Sigma) doesn't actually exist, but Matlab's
% mvnrnd provides samples with this covariance st x(1)~N(0,1) x(2)=x(1). The
% fast way to deal with this would do something similar to chol but be clever
% when the rows aren't linearly independent. However, I can't be bothered, so
% another way of doing the decomposition is by diagonalising Sigma (which is
% slower but works).
% if
% 	[E,Lambda]=eig(Sigma)
% then
% 	Sigma = E*Lambda*E'
% so
% 	U = sqrt(Lambda)*E'
% If any Lambdas are negative then Sigma just isn't even positive semi-definite
% so we can give up.
% }}}
